Thursday, January 26, 2012

MVPVM: The Best of Both Patterns?

In the past few posts, we've been looking at some architectural patterns that are in common use among .NET developers, including the classic Model-View-Controller, and derivatives like Model-View-Presenter and Model-View-ViewModel. My original motivation for writing these posts, however, comes from an even newer pattern, an extension of the MVVM pattern called the Model-View-Presenter-ViewModel pattern.

Until recently, I had been using these various patterns in different projects without really thinking too much about where they came from or how they were related. I (like many other developers, I suspect) was just using the pattern that seemed to work best: MVP for my Windows Forms app, MVC for my new ASP.NET apps, MVVM for my WPF apps, etc. But as I was reading an article in MSDN magazine from December 2011, on a new pattern for WPF applications, everything semed to "click" for me, how these patterns evolved, how they were related, and why a given pattern works better than any other in a given situation.

I wrote out this series of blog posts, in part, to help crystallize this new understanding in my own mind, and in part to share it with other people who may still be unclear on what all this "pattern" stuff is all about. So, it seemed only fitting to wrap up by giving a brief overview of this new pattern, and my thoughts on it. First, though, a couple of caveats:
  1. I have never used this pattern in production, so I am in no way an expert on it. These are just my early impressions.
  2. This pattern is still fairly new -- even the name is not yet in common use. So I'm pretty confident that this pattern will evolve as people learn and understand more about it.
  3. So far, I'm not entirely convinced that this pattern is something I'll ever use, but see point #1.
  4. Because of point #1, this is going to be a much shorter post, with less code, than usual. Hopefully, as I get more acquainted with this pattern, I can come back and do a better one.
So, consider this just my first impressions and musings on an emerging idea in pattern-based development.

The Composite Application Library

The origins of this pattern, which was largely unnamed until recently, was the Microsoft Composite Application Guidance, also known as the Prism project, which was designed to guide developers writing enterprise-level WPF applications. It takes advantage of other Microsoft frameworks, like Unity or the Managed Extensibility Framework, to combine loosely-coupled elements of your application in various ways at run-time.

Although the guidance talks a lot about the MVVM pattern, if you look closely, you'll see that the actual pattern  is not a typical "triad", like the other patterns we've looked at. Instead, there is a fourth component included in the mix, which is used to coordinate among the other three. For lack of a better term, this component is called a Presenter, since it behaves much like an MVP Presenter is supposed to.

One of the key aspects of Prism is that every element in the application is very loosely coupled to the other elements. Prism uses various techniques at run-time to bind those elements together in combinations as needed, so the elements themselves must be highly reusable and flexible. One of the flaws in the MVVM pattern is the tight binding between the View and ViewModel, especially once your ViewModel starts asking for user input (confirmation dialogs, etc.)

Splitting the View and ViewModel

This is where the MVPVM pattern comes into play. Its target audience is very large-scale enterprise applications where multiple views, with different business requirements, may need to bind to the same ViewModel, which means your ViewModel cannot include view-specific business logic. It also means you will definitely be doing extensive unit testing and coded UI testing of your components, so you need that process to be as efficient as possible.

Here is one place that I start to lose the thread of why this new pattern is really necessary for my purposes. To quote Bill Kratochvil (author of the referenced article) on why this new pattern is needed:
If you have to put code in your WPF code-behind, for any reason, then you've run into a limitation of MVVM alone;  a limitation that will prevent reuse, prevent proper unit testing and cause code bloat. --
(An interesting note from that blog post, that I missed in my original MVP and MVVM posts, is that MVVM is really just a new name for an old pattern, the PresentationModel pattern, updated and enhanced for WPF). But the key here, IMO, is this contention that any WPF code-behind at all represents a serious flaw in your architecture. To me, that's just silly, and represents a strange belief that the code-behind is somehow a separate and independent component of the system. To me, the code-behind class behind a WPF Page or UserControl is part of the View: anything I would logically be able to place in the View I can just as logically place in the code-behind. Obviously, there are a lot of benefits to keeping the code here small and letting WPF do the work, but something like this, for example, represents a perfectly natual use of code-behind for me:
private void DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    var old = e.OldValue as TransactionTenderWindowViewModel;
    if (old != null)
        old.ValidateOperation -= ValidateOperation;

    var value = e.NewValue as TransactionTenderWindowViewModel;
    if (value != null)
        value.ValidateOperation+= ValidateOperation;

private void ValidateOperation(object sender, ValidateOperationEventArgs e)
    var message = string.Format("Please confirm that you really want to {0} your {1}.", e.Operation, e.Target);
    var result = MessageBox.Show(message, "Validate Operation", MessageBoxButton.OKCancel, MessageBoxImage.Information);
    e.Cancel = (result == MessageBoxResult.Cancel);
Here, my ViewModel is firing an event that says "any Views that are listening to me, if you don't want me to Operation my Target, now's your chance.".

Under the MVPVM model, this code would instead belong in a Presenter class that handles this validation for the views that need it, and ignores the validation for views that don't care. In this model, it is only the Presenter that has any tight coupling to other components: it is bound to a View, a Model, and a ViewModel, and ferries information and operations between the three. This is a Supervisory Controller style Presenter: the View and ViewModel still have some direct data binding, but complex operations are offloaded to the Presenter. The following diagram from the MSDN article shows these relationships (note that the business and data logic, and domain models, all fall under the Model aspect of this pattern):

The MVPVM Architectural Pattern

Of course, the problem here is that the target environment for this pattern are applications on a far larger scale than anything I typically have to deal with. (I don't think I've ever seen the kind of application that Prism considers "enterprise-level", based on their description). The focus of the MVPVM pattern isn't simply to get code-behind out of the View, but to get view-specific logic out of the ViewModel, to make the entire application modular, scalable, and testable.

Kratochvil uses an example of a set of search results screens, all using the same underlying ViewModel, where some views display a certain field and other don't. Instead of polluting the ViewModel with the knowledge of its parent View and logic to set/clear the field's visibility, that logic is moved into a Presenter that coordinates between the two, now decoupled View and ViewModel objects as needed.

Now, in my understanding of the MVVM pattern, it is not common practice to reuse a ViewModel for multiple Views. In the above scenario, there would simply be more than one ViewModel, possibly with the common operations refactored into a base class. (Arguably they may also belong in the Model itself.) However, as your application scales in size, having lots of redundant ViewModels can become a problem. This is particularly true if your application has Views for lots of different target environments (web, client, mobile, etc) that are slightly different in their requirements: maybe none of your mobile Views are allowed to see social security numbers, or something.

Final Impressions

Overall, I'm still getting familiar with this pattern, so take these comments for what they're worth. When I started reading about this pattern, my first thought was an old programming adage:
All problems in computer science can be solved by another level of indirection -- David Wheeler
That clearly seems to be what's going on here: the pattern is solving the "problem" of having tightly-bound View and ViewModel classes by adding an indirection layer between them. The second thought I had was (with sincere apologies to Jamie Zawinski):
Some people, when confronted with a problem, think "I know, I'll use another level of indirection." Now they have two problems.
One of the biggest complaints about the MVVM pattern is that it's adding too much overhead, for too little benefit, to what is already a complex framework (WPF). This pattern takes that overhead and layers on another pile of overhead, for arguably even less benefit.

My impression here is, if you are actually writing an application where the Prism library and guidance can be useful for you, the runtime overhead of adding a Presenter to MVVM will be swallowed up in the noise. And the benefits you gain from testing efficiency and responding to changing requirements will probably add up to a major net gain over the added development complexity. But for me, for now, MVPVM is staying on my shelf as one of those ideas that never found a need for.


Anonymous said...

I feel the same way, unless you're developing applications that have many views per viewmodel than it seems overkill. How have your feelings about it evolved now that some time has gone by?

Michael Edenfield said...

Mostly, we just stopped using Prism and never used this pattern in any real code. We pulled pieces of Prism out and use them where appropriate, but always in an MVVM pattern.