Saturday, January 21, 2012

The MVP Pattern: Son of MVC

Last time, we starting looking at the concept of architectural patterns, and how they are used in software development. We also traced the history of the prototypical architectural pattern, the Model-View-Controller or MVC pattern, from its Smalltalk roots in 1979 through 3 decades of progress, to modern MVC frameworks, like Ruby on Rails or ASP.NET MVC.

But MVC isn't the end of the story, not by a long shot. Besides evolving into new versions of itself, the MVC pattern has also spawned an array of alternative patterns. These patterns take the same core concept, separation of concerns at a fundamental architectural level, and just reorganize where all the pieces go.

Today, we'll take a look at some of the common elements of this family of patterns, then examine one  of those variations in more detail: the Model-View-Presenter or MVP pattern.

A Glossary

As a result of being derivatives of the same common "ancestor" patterns, most modern architectural patterns share a lot of their concepts and terms amongst each other. Knowing what a particular word means, at least in the jargon of these patterns, goes a long way to helping explain what each pattern means, and how it works. So lets start by defining some terms. Don't worry if the distinction between some of these isn't clear: there is significant overlap in their uses, since they're all trying to solve the same problem. Hopefully things will start to make more sense when we see these elements in the context of an entire pattern.
  • Model - The model represents the part of your application that is responsible for storing, maintaining, and maniuplating the data that is particular to your application's business domain. The model, in this sense, includes the majority of the business and data tiers in your application. This would include any data storage entities, business rules, validation logic, and other elements unique to your application.
  • View - The view represents the part of your application that a user interacts with. Typically views are associated with the output of your program, but in modern architectural patterns, the view is also frequently responsible for processing user input. How much input processing a view is responsible for depends on the exact environment.
  • Controller - The controller element is largely absent in modern architectural patterns because its role has been subsumed by the operating system itself. The remaining aspects of what a traditional controller would do have been migrated into other components as appropriate.
  • Presenter - A presenter is a component that is responsible for any user interface logic that is specific to a given view. It acts as a go-between, taking commands from a View and translating them into operations against a Model, and taking raw data from the model and formatting it for display in the View.
  • ViewModel - A view model is a component that is similar to a Presenter, in that it supplies data to a view and processes input from the view. A view model, however, is a more fully-featured class that encapsulates all of the operations a view needs to do, both domain-specific and UI-specific, into a single class.
In addition to the pattern's components, these architectural patterns are often used in conjunction with other modern programming techniques and design patterns. You should at least be familiar with the basic idea behind these concepts:
  • Dependency Injection - This is a programming pattern that is used when a given component is very strongly coupled with one or more other components, but should not be tightly bound to any specific implementation of those other components. It sees heavy use in two major areas: pluggable services and unit testing. For example, most business layer objects have a strong dependency on the data layer to store and retrieve data; however, for unit testing purposes, we want to be able to swap out our real data layer for a mock one. Using a dependency injection pattern, one option would be to bind our business layer to a repository interface that is used in place of the actual data layer objects. The default constructor for the business object would create an instance of the real data layer, but an overloaded constructor for unit testing would accept one as a parameter. On the services side, our web framework may have a dependency on an authentication module that all requests pass through. By default, the framework plugs in its own, internal module, perhaps one that simply accepts all requests, but we could configure our application to inject our own authentication module in its place.
  • Repository Pattern - One common example of dependency injection makes use of this pattern. The idea is to centralize all access to your data layer into a single object or interface, the repository. This provides a single point of entry for the upper layers to interact with, but also makes it very easy to inject a mock data layer into your code for unit testing. When used properly, it also forces developers to understand the intended usage patterns behind their data model, and restricts the upper layers to only taking actions that are well-defined by the repository.
  • Observer Pattern - This is one of the key design patterns in use by the MV* pattern family. Objects that implement an observer pattern expose some form of notification or messaging system that propogates any change in object state to other interested listening objects. WCF's data binding model, for example, is almost entirely based on the Observer pattern, through the INotifyPropertyChanged and DependecyProperty mechanisms.
Architectural Patterns Are Not Tiers!


One thing to keep in mind here is that these patterns deal primarily with the presentation tier of a traditional n-tier architecture. These patterns are meant to help isolate and encapsulate the user interface from the rest of the application. In the basic three-tier system, for example, the Model would contain the entire data later and most or all of the business layer. It may make sense to include some business logic, particularly data validation, in your Presenters, especially if communication with the Model is expensive, but those are exceptions.

Two of the main goals of a multi-tiered system are reduced deployment and maintenance costs. They isolate problems to smaller, more modular pieces that can be fixed and swapped out in isolation. They also promote the use of centralized business logic, so that a variety of presentation systems can share common behavor.

None of these typically apply to the architectural patterns we're discussing here. These components are separated logically, not physically, and are often very tightly bound to each other. A ViewModel exposes its data and events directly to its companion View, while a Presenter often calls into a View and interacts directly with its elements. Both components need to be changed in sync and deployed simultaneously.

The purposes of these separations, instead, is to increase developer efficiency. For example, by having a well-defined ViewModel for each View, the two elements can be worked on independently, by different developers, and brought together as you near completion of a feature. Having your event handling code in a Presenter class makes it easier to unit test those behaviors, as opposed to a web or Windows form

These patterns also tend to encourage the use of other, more specific design patterns, which have been shown to result in better-written code. Both Presenters and ViewModels often make use of the Observer pattern, for example, to update their associated View. The use of these common patterns means that much of the scaffolding code that is common to your chosen style of user interface (wiring up data bindings in WPF, intercepting clickbacks in ASP.NET, handling messages in a Windows form, etc.) is done in a consistent manner, allowing developers to move on to the more interesting parts more quickly.

Model-View-Presenter

The Model-View-Presenter, or MVP, pattern, was one of the first MVC variants to gain widespread popularity. It is particularly popular with web-based Frameworks, where the View is an HTML page hosted in a browser that has limited interactive behavior. For example, the traditional structure of an ASP.NET Web Application uses an MVP-like architecture.

As with most patterns, the Model encapsulates the business logic and data, and exposes that information through properties and methods that define the high-level operations. The  Model is commonly implemented using the Repository pattern, with a single class (or, more likely, interface) supplying all of the public-facing interactions with a Model.

The View in an MVP application is extremely passive: it contains just the user interface controls that make up the look and feel of the application. In some variations of MVP, the View may be aware of parts of the Model that is cares about; in others, the View only interacts directly with the Presenter.

Most of the presentation logic itself is found in the Presenter class. Input from the View, in the form of events, are passed directly into the Presenter as-is. The Presenter is responsible for interpreting the meaning of those events, based on the state of the Model and any related user input.

A key aspect of the MVP model is that the Presenter is usually very much aware of the View that it is managing; a typical Presenter class contains a direct reference to an instance of a View class. The Presenter is responsible for taking the Model information and pushing it up to the View in the correct format. In certain variations of the MVP pattern, the View may bypass the Presenter when retrieving some simple pieces of information (a process called data binding, a key to many modern frameworks), but anything more complex will be actively written into the View by the Presenter.

One of the trade-offs in any of these patterns is trying to balance reusability -- the ability to use the same Presenter against different Views -- against functionality -- the ability for the Presenter to actually do something useful. In the most common implementation of the MVP pattern, this balance is achieved by inserting an interface layer between the two, in the form of a view interface. The idea here is that the  Presenter would have a documented set of View elements that it requires access to, in order to do its job. Any View that wanted to bind to that Presenter would implement at least those requirements, via the interface. This leaves it up to the View if they want to implement a list as a combo box, list box, <SELECT> element, or whatever else is appropriate to the UI framework. Often, there is also an interface sitting between the Presenter and the Model, as well. In addition to code reuse, this interface pattern also makes unit testing easier by providing dependency injection points to add, say, a mock View or mock Model when unit testing the Presenter.

Let use an example of a simple Point of Sale system for a retail store. A simple conceptual model for this system might look like this:

During the current sprint, you've been assigned to develop the entry screen for accepting payments. (For now, we'll ignore electronic payments like debits; assume all payments are manually entered for this iteration.) Our view needs to perform two tasks:
  1. Accept the input data, such as tender type and amount, and add them to our transaction
  2. Display current transaction information, such as remaining balance and change due
Passive MVP View

To achieve this, the MVP patterns comes in two fundamental "flavors": the Passive View pattern and the Supervising Controller pattern. The Passive View pattern relies on the Presenter to perform all of the work in getting the view updated. There are a number of ways to accomplish this, but the one I see used most often makes our View into little more than a thin wrapper around a set of key properties, defined by a View Interface like this:
interface ITenderView
{
    decimal ChangeDue
    {
        set;
    }

    decimal BalanceDue
    {
        set;
    }
}
We can then implement this interface in whatever UI Framework we want; I'll use WPF as an example, so we can better compare this to the MVVM pattern later. This is generally not how a WPF application would be developed; MVP is much more popular in ASP.NET applications, but this same technique can be applied to any framework. At any rate, here's a sample XAML fragment:
<TextBlock name="BalanceDueTextBlock" />
<TextBlock name="ChangeDueTextBlock" />
This view also implements our interface:
public partial class TenderView : UserControl, ITenderView
{
    public decimal ChangeDue
    {
        set
        {
            this.ChangeDueTextBlock.Text = value.ToString("c2");
        }
    }

    public decimal BalanceDue
    {
        set
        {
            this.BalanceDueTextBlock.Text = value.ToString("c2");
        }
    }
}
Now that we have a View, we need to build up the Presenter to use it. In the Presenter, we're basically snapping LEGOs together: plugging our data repository interface and our view interface together. The Presenter is handed instances that implement each of those interfaces, then sets about putting the data into the View where it belongs. For example, we could trigger the Presenter to update its associated View every time we assign a new transaction to it:
public int TransactionId
{
    get
    {
        return this.transaction.Id;
    }
    set
    {
        this.transaction = this.model.GetTransaction(value);
        this.Update();
    }
}

public void Update()
{
    this.view.BalanceDue = this.transaction.BalanceDue;
    this.view.ChangeDue = this.transaction.ChangeDue;
}
This takes care of the display side, but there's still the issue of responding to user events. Again, under this pattern, our View is very thin, and the event handling code will reside mostly in the Presenter. First, lets add some code to our view interface:
event EventHandler AddNewTender;

int TenderType
{
    get;
    set;
}

decimal Amount
{
    get;
    set;
}
And we'll make the following additions to our view and presenter:
<TextBlock name="TenderType" />
<TextBlock name="Quantity" />
<Button click="AddButtonClick" content="Add" />
// TenderView.xaml.cs:
public int TenderType
{
    get
    {
        return int.Parse(this.TenderTypeTextBox.Text);
    }
    set
    {
        this.TenderTypeTextBox.Text = value.ToString();
    }
}

public decimal Amount
{
    get
    {
        return decimal.Parse(this.AmountTextBox.Text);
    }
    set
    {
        this.AmountTextBox.Text = value.ToString("c2");
    }
}

private void AddButtonClick(object sender, RoutedEventArgs e)
{
    this.AddNewTender(this, new EventArgs());
}

// TenderPresenter.cs:
public TenderPresenter(ITenderView view, IDataRepository model)
{
    this.view = view;
    this.model = model;

    this.view.AddNewTender += this.ViewAddTender;
}

public void ViewAddTender(object sender, EventArgs e)
{
    var type = this.view.TenderType;
    var amount = this.view.Amount;
    this.model.AddPayment(this.transaction, type, amount);
    this.Update();
}
Our View does nothing beyond forwarding its button clicks on to the Presenter. But notice the way we did this: the View does not actually call into the Presenter directly; our goal here is to keep our View isolated from the Presenter classes. This way, the vast majority of the "fragile" code -- the code that is most likely to have to change as our requirements evolve -- is contained in one place. To accomplish this, we have our View simply raise its own event, which our Presenter hooks into as needed.

Supervisory Controllers

One thing you may have noticed about the passive view is a lot of repetitive code that simply passes Model properties up to the View. For simple Views with only a few properties, this is probably acceptable to keep the View itself very simple. But for a complex screen, it can get tedious.

The alternative is to use the Supervisory Controller pattern. Don't be misled by the name: we aren't introducing an actual controller into our MVP pattern (this pattern is also sometimes called the Supervisory Presenter). Under this style of MVP, we will bind parts of our View directly to the Model for reading or writing simple, primitive properties, and use our Presenter only for the more complex elements.

Switching over to this new pattern is pretty simple. We start by removing those elements from our View and its interface that are "simple" property accessors. A good rule of thumb here is to look for property elements that our Presenter only uses in simple assignments to or from the model. Anything more complex than that should probably stay in the Presenter code. In this case, we have BalanceDue and ChangedDue, that are simple copies from the Model. We'll remove those from the interface and code-behind, and update our XAML to bind directly to those properties:
<TextBlock Text="{Binding TotalDue}"/>
<TextBlock Text="{Binding BalanceDue}" />
<TextBlock Text="{Binding ChangeDue}"/>
This is where the controller aspect comes into play. We are already relying on our runtime environment, be it the operating system itself, a virtual runtime such as the CLR or JVM, a scripting engine, whatever, to act as the controller on our behalf. Now, we're also relying on it to include some form of notification, or "supervisory", behavior. The runtime provides a way for our model to notify any listening views that it has changes, and the view can automatically refresh itself to adapt. For our example, we're using the WPF data binding features, which will take advantage of the INotifyPropertyChanged interface we implement on our model classes.

With these changes in place, our Presenter no longer needs the Update method; however, we do need a way to hook our view up to its model. To do this, we add a method to our view interface, specifying which type of Model element it wants to bind to:
// ITenderView.cs
void Bind(Transaction transaction);

// TenderView.xaml.cs
public void Bind(Transaction transaction)
{
    this.DataContext = transaction;
}

// TenderPresenter.cs
public int TransactionId
{
    get
    {
        return this.transaction.Id;
    }
    set
    {
        this.transaction = this.model.GetTransaction(value);
        this.view.Bind(this.transaction);
    }
}

The Next Stage

This Model-View-Presenter pattern was a natural evolution from MVC, and enjoys widespread popularity across many development environments and languages. For a while, it was the go-to pattern for implementing ASP.NET and WPF applications. Next time, however, we'll look at the next step in the evolution of the MVC pattern family, which is largely supplanted MVP for WPF application design: the Model-View-ViewModel pattern.

0 comments: