Inside the Sausage Factory: PART 21 (On Model-View-Presenter Patterns)

In our last post we took a little detour from developing our solution so that we could fix the nagging problems with the NDbUnit software so that our data-dependent Unit Tests would be able to be more easily (and correctly!) run.  Now that we’re done with that, we can safely return to the task at hand: that of building the next layer of our application.

First let’s review what we’ve accomplished to-date:

  • feature-set for 1.0 release determined
  • database schema designed and implemented
  • user interface mockup designed
  • data access layer developed (at least the first-pass of the methods that we think we will need)
  • unit tests for our data access layer developed (and passed!)

Even thought its taken us a bit longer to get here than I had planned, I’ve decided to continue on our current pace for at least the time being, irrespective of how long it may take to actually complete this project now.  Our next step is to consider the manner in which our User Interface (UI) is going to talk to our data access layer (DAL).

UI Application Design Approaches

There are a number of viable approaches to this ranging from just using the Microsoft Visual Studio Webforms designer to drag-and-drop controls onto the form and hook up databinding by setting properties on the controls at the simple end to the more complex choices of either a Ruby-On-Rails -like approach in something like MonoRail or a home-rolled Model-View-Controller/Model-View-Presenter approach on the other end.

I have long been a critic of the giant mess that is the ASP.NET postback model.  I am a further critic of the unpleasant ‘blending’ of presentation logic, business logic, and application logic that tends to ensue when one blindly sticks all of one’s code in the aspx code-behind pages of a typical .NET web application.  This kind of thing flies in the face of everything that I have ever learned about good software engineering practices (separation of concerns, etc.) and so I find myself predisposed not to accept it in my own work, even if Microsoft’s own tooling has made it quite clearly the path-of-least-resistance to get an application built quickly (at least a simple one).

While I have a soft spot in my heart for what the Castle Project is trying to do with Monorail, the requirement to just about completely abandon the entire ASP.NET page lifecycle model means that its harder than I would like to get third-party control libraries to ‘play nice’ with their ideas and for the time being that’s a deal-breaker in my eyes.  To adopt Monorail to get the benefits of that framework means jettisoning the benefits of just about any third-party control library and that’s further than I’m willing to go right now.  Their tag-line is correct: Monorail is indeed "A Paradigm shift to Simplicity" but that simplicity right now comes at too high a price for me.

Instead, I tend to approach the design of ASP.NET web projects by rolling my own Model-View-Presenter style organization for the application.  Its not nearly as powerful as what Monorail offers, but certainly makes it much simpler to effectively practice good software engineering practices like the aforementioned separation-of-concerns, DRY, reusability, and testability.  The Microsoft default approach to webforms engineering doesn’t make it all that simple to achieve these goals in one’s application (though as we’ll see in this project, the tools and capabilities are certainly present to support such an approach).  Where the Monorails folks tend to want to ‘throw the baby out with the bath water’, implementing a Model-View-Presenter approach to our application will enable us to leverage the best of what the Microsoft ASP.NET infrastructure offers while avoiding some of the pitfalls that it often makes it all too easy to slip into.

The View (of what?)

Since the point of the MVP solution is (largely) to support the View part of the MVP triad, I prefer to start my development process by considering the View part of the Model-View-Presenter (MVP) pattern.  The simplest way to do this is to consider the UI from the perspective of two questions:

  1. What inputs does the UI need in order to populate itself with data for the user?
  2. What outputs is the UI going to need for it to interact with the rest of the solution to do its work?

From the answers to these two questions, we can begin to formulate the Interface for our View.

SearchCriteraEntryControls To make matters simple, let’s not consider right now the whole User Interface that we developed in this post but instead concentrate on the Search Criteria set of controls (shown here) that make up the most significant part of the UI from a programming perspective — since this set of controls is the hub of how a user will search for people and skills in our application, this is the concentration of the most complexity in behavior and so represents a good place to start thinking about the inputs and outputs that are needed to support it.

The inputs we need to support are clear here: we need to provide a list of values to the View for each of the list controls that provide the choices for the user to select from when performing a search as in…

  • Employee Type
  • Office Region
  • Specific Office
  • Skill Category
  • Specific Skill
  • Skill Level
  • Years the skill has been in use
  • Years since the skill was last used

The outputs are equally easy to determine here: we need a way for the View to report back what item from each of these lists has been selected by the user for use in the actual search as in…

  • Selected Employee Type
  • Selected Office Region
  • Selected Office
  • Selected Skill Category
  • Selected Skill
  • Selected Skill Level
  • Number of Years the skill has been in use
  • Number of Years since the skill was last used

 This gives us an Interface definition for our View along the lines of…

    public interface IPersonSearchCriteriaView
    {
        //write-only properties, used to populate the controls with initial values
        IList<PersonType> PersonTypes { set; get;}
        IList<Region> Regions { set; get;}
        IList<Office> Offices { set; get;}
        IList<SkillType> SkillCategories { set; get;}
        IList<Skill> Skills { set; get;}
        IList<SkillLevel> SkillLevels { set; get;}
        IList<int> YearsUsed { set; get;}
        IList<int> YearsSinceUsed { set; get;}

        //read-only properties, used to feed back user-selections from the controls
        int SelectedPersonTypeId { get;}
        int SelectedRegionId { get;}
        int SelectedOfficeId { get;}
        int SelectedSkillCategoryId { get;}
        int SelectedSkillId { get;}
        int SelectedSkillLevelId { get;}
        int SelectedYearsUsed { get;}
        int SelectedYearsSinceUsed { get;}

    }

You may notice that the first block of properties are commented to be ‘write-only’ but they are defined here as having both a public setter and a public getter method (which clearly makes them not write-only smile_wink  ).  This was done to support the need to access these properties’ values during unit testing to assert that their values are correct as we will see later when we write our unit tests that involve this Interface.

Note that I’m not really a big fan of changing significant aspects of my code only to support the need for unit testing, but I consider making something readable to be an acceptable minor change to support testing (whereas making something writable that otherwise would not be just to support testing would likely not be an acceptable change to me).

Usually design decisions made to support unit testing are also excellent software design practices anyway so they can be perceived of as not being ‘testing overhead’ or having the need for unit tests unduly ‘influence’ the design in a negative way; this case here is one where the change to support unit testing actually leads to a less-ideal solution than otherwise but its impact on the design is minimal so I will choose to live with it in order to get the much greater benefit of being able to unit test my View.

The SelectedXXX properties correctly expose only a public getter method as is appropriate since nothing outside the View itself should ever have the opportunity to do anything other than interrogate these values.  Our View Interface defined, our next step is to hack together an instance of the Presenter part of the MVP triad.

Presenting…the Presenter!

In the MVP design pattern, (nearly) all the work is done in the Presenter; its the Presenter’s job to arbitrate the communication between the Model (an object model full of domain objects, a database modeling the data, whatever) and the View (the actual, mostly-passive, UI layer).  To do its work, our Presenter needs both a reference to the View (to get and set values from/to the controls) and a reference to the Dataprovider (to get data in and out of the database as needed).

So to start our Presenter class, we need to declare a few fields to hold these objects for us…

    public class PersonSearchCriteriaPresenter
    {
        private DataProvider _dataProvider;
        private IPersonSearchCriteriaView _view;

Since I’m a huge fan of DI (dependency injection) and its fancier-sounding name, Inversion of Control, and it plays a significant role in both the canonical implementation of the MVP patterns and our eventual need to unit test this stuff, our Presenter’s constructor needs to take both of these references when the Presenter is instantiated…

        public PersonSearchCriteriaPresenter(IPersonSearchCriteriaView view, DataProvider dataProvider)
        {
            _view = view;
            _dataProvider = dataProvider;
        }

The only problem with this constructor signature is that its going to require whatever calls it (our View implementation in this case) to pass it a DataProvider instance and we would really rather that our View not have any idea what a DataProvider even is, let alone how to create one (recall that the whole point of the Presenter in the first place is to mediate between the Model and the View so it makes no sense for the View to need to know how to get stuff in and out of the model via a DataProvider).  Since the View knows itself, it can certainly fulfill the need to pass a View argument to the constructor, but it needs to somehow do so without passing a DataProvider argument.

Fortunately, the C# language has a way for us to handle this via a mechanism called ‘constructor chaining’ that lets one constructor for a class call another constructor in the same class (technically it actually lets one constructor call a constructor in ANY class, but we don’t need that capability right now).  Using this approach, we can code a second constructor overload that call into the first but creates its own DataProvider on-the-fly as it does so…

        public PersonSearchCriteriaPresenter(IPersonSearchCriteriaView view)
            : this(view, new DataProvider())
        {
            //do nothing here -- constructor chainging will pass on to primary constructor
        }

This constructor signature will enable a View to create a Presenter without needing to also first create a DataProvider to pass in as well.

Now that our constructors are addressed, we next need a method that will be used to initially setup the state of the View for us.  MVP purists cannot seem to agree on what this method should be called and convention seems to vary from InitView( ) to Initialize( ) to Init( ) to InitializeView( ).  My personal opinion is that Init( ) and Initialize( ) are too vague — just what does the method initialize when its called???  InitView( ) is abbreviating ‘Initialize’ for no good reason; intellisense in the VS IDE means I’m not concerned about saving myself keystrokes.  That leaves us with InitializeView( ) as our method name of choice.

Thanks to all the work we did in our Data Access Layer, populating the properties of our View object with the proper values from the database is trivial and can really be done in a single line of code for each property…

        public void InitializeView()
        {
            _view.PersonTypes = _dataProvider.GetAllPersonTypes();
            _view.Regions = _dataProvider.GetAllRegions();
            _view.Offices = _dataProvider.GetAllOffices();
            _view.SkillCategories = _dataProvider.GetAllSkillTypes();
            _view.Skills = _dataProvider.GetAllSkills();
            _view.SkillLevels = _dataProvider.GetAllSkillLevels();

            IList<int> _yearsSinceUsedList = new List<int>();
            for (int i = 0; i < 4; i++)
                _yearsSinceUsedList.Add(i);

            IList<int> _yearsUsedList = new List<int>();
            for (int i = 0; i < 6; i++)
                _yearsUsedList.Add(i);

            _view.YearsSinceUsed = _yearsSinceUsedList;
            _view.YearsUsed = _yearsUsedList;
        }

Note that we’re building an IList<int> on the fly for both the YearsUsed and YearsSinceUsed selector lists since these values aren’t found in the database.  Also note that it would probably be a great SkillPortal v2.0 feature for the upper bounds of the for loops that build these selector values to be stored in the application’s configuration file or something so that they could avoid being hard-coded here but this is certainly not worth bothering with at this time smile_wink 

Lastly, to round out the Presenter class we need a method that the View can call in the Presenter that can be responsible to actually perform the search based on user-selected values.  We’re going to cleverly call it PerformSearch( ) and since the Presenter already has a reference to the View object and so can get all its input directly from the View, this method doesn’t even need any arguments to do its work to return a IList<PersonSkillSearchView> to the caller…

        public IList<PersonSkillSearchView> PerformSearch()
        {
            SearchCriteria criteria = new SearchCriteria();

            criteria.OfficeId = _view.SelectedOfficeId;
            criteria.PersonTypeId = _view.SelectedPersonTypeId;
            criteria.RegionId = _view.SelectedRegionId;
            criteria.SkillId = _view.SelectedSkillId;
            criteria.SkillLevelId = _view.SelectedSkillLevelId;
            criteria.SkillTypeId = _view.SelectedSkillCategoryId;

            return _dataProvider.GetDistinctPersonsBySearchCriteria(criteria);

        }

Now that we have both our View Interface and our Presenter class written, you might think that the next step (finally!) would be to actually build the UI, but that’s one step too soon.  Before we take the step of trying to build a UI on top of this code and make it behave correctly, we need to write some unit tests for our View and our Presenter to ensure that they are able to act as a solid foundation for our UI before we go ahead and try to build anything on top of them.

And that’s precisely what we will be doing in the next post~!