Tuesday, January 17, 2012

MVC, MVP, MVVM, MVPVM, LMNOP -- WTF?

One of the things I and my colleagues at my $DAYJOB have been dealing with on our current project is understanding a popular WPF architectural pattern called the "Model-View-ViewModel" pattern, or MVVM. It is the latest in a growing trend of alphabet soup coming out of the .NET developer's community. For myself, and I suspect many others, it is sometimes a struggle to understand what all the fuss is about, and why I should waste my valuable development time learning some new technique that will just disappear when the next big thing comes along.

Much of the problem is that these new design patterns seem to require me to write code in a dramatically new and different way than I am used to, without providing any real, tangible benefits for doing so. Worse, these concepts seem to be coming out of nowhere, with no background or foundation behind them, and immediately being touted as the next great thing in software development. Recently, however, I have had an epiphany of sorts. Not really anything so dramatic, but a number of things seemed to "click" for me in a way they had not before.

For many of you, particularly if your background is not Windows desktop development in C/Delphi/VB/C#, some of this will be like going back to grade school. However, I suspect I'm not the only one overwhelmed by all these big ideas, so I'm going to try and explain the concepts behind these "new" techniques, at least how I understand them, for the benefit of anyone else that's struggling to figure them out.

The Basics: Architectural Patterns

The first thing we need to figure out is, what do we mean when we say "architectural pattern" anyway? If you've done much line-of-business development, you have probably encountered the concept of a design pattern, which is just a reusable technique for solving a common problem. Design patterns don't apply to particular business problems, they apply to common software problems. Do you need a object that is the same no matter how many times you try to "create" it? That's a Singleton pattern. Do you need to know where some other object changes state? That's an Observer pattern. Etc.

An architectural pattern exists at a higher level than this; it is a reusable template for how the pieces of a system fit together. In this case, the patterns describe how the user interface and business logic in an application are connected. They defines the parts (for which the pattern itself is named), the specific touch points between the parts, and what types of operations each part should and shouldn't do.

Strictly speaking, every program ever written has followed some type of pattern for its user interaction. Prior to the mid 90s, however, they were rarely formally defined (with one crucial exception). If you're anything like me, you spent decades writing software, blissfully unaware that you were using a pattern. In the case of Windows programming, the operating system's architecture mostly dictated this pattern; in today's parlance we would probably call that pattern "Model-ViewController", a term that will start to make more sense in a bit.

Smalltalk and Pattern History

For me, the key piece of information that was missing, that made everything else fall into place, was understanding this new fad in architecture patterns in the context of history. Most of the patterns in widespread use these days are variations of the same basic idea, which first appeared as the "Model-View-Controller" pattern, or MVC. But this first appearance wasn't recently; it was back before most of the software platforms we use today even existed: in 1979, at Xerox PARC, on machines running Smalltalk.

The operating systems in use at the time were pretty primitive compared to what we have today. A lot of the work we take for granted that Windows, or OS X, or whatever does for us, had to be handed in user code. In particular, the whole concept of a graphical user interface, with mouse and keyboard input, was still fairly new, and the kind of messages supplied to applications were much more basic that we're accustomed to with modern systems.

It was in this context that MVC was first developed. The core idea, which forms the heart of all of the successor patterns to come out of MVC, was to keep a clear and distinct separation between the user interface, the business logic, and the "scaffolding" that connects the two. After some debate over what to call these parts, the author of the first paper on MVC, a scientist (back then developers were mostly scientists) named Trygve Reenskaug, came up with the following designations:
  • Model: A representation of the real-world problem in terms of the software system.
  • View: A component of the software system capable of visually representing the model.
  • Controller: A component of the software that translates user input into meaningful operations.
Key to understanding this pattern is recognizing the job of the Controller in this system. Its purposes was to translate raw user input into something meaningful to the model, so it could properly update its state and change the view. Examples of this would be displaying menus and dispatching clicks to them, converting a mouse down and mouse up into a click, or relaying accelerator keys to their appropriate command. It was also responsible for rendering the correct views in the correct locations on the screen.

The Views in question were also much simpler than we think of them in modern applications. A View might be a list box, a text box, or a diagram. Everything else: the data structures, business logic, etc., was part of the Model. The actual user interface for a single portion of the system consisted of several, perhaps dozens, of view/controller pairs (one for each "editor"-type control, and one more overall). And in the original MVC concept, the three elements were much more intertwined than in modern variations.

In this context, its easier to see why MVC got such little attention from Windows developers for so long: two of the three components in the pattern are built into the operating system. This is the basis for my claim that we've been using the MVC in Windows all along, and this isn't all that far outside the bounds of the original MVC description. In the earliest written details of MVC, the View and Controller were tightly bound together into what's called the Tool, and the job of the Tool was to provide some abstract mechanism for translating a software logical Model into a human conceptual model, as in the following diagram:
Early MVC Diagram[src]
This describes almost exactly what a UI Control (be it the Windows API, WinForms, Cocoa, GTK+, etc) does when it is displayed to a user: translate their raw input into something that represents a logical "action" in the system.

Modern MVC Implementations

The "Smalltalk" MVC Model
Of course, just because the details of the early MVC pattern may not apply doesn't mean we can't use the lessons it taught us. Modern architectural patterns continue to apply the same separation of concerns, simply moving around where we draw the lines. The "modern" version of MVC tends to find heavy use in two key environments: web-based applications, and embedded platforms (such as phones). One thing these two environments have in common is a much more basic user interface experience, leaving open the need for a
Controller to step in. The Android's Java environment and iPhones Cocoa environment, for example, are both designed to be used with an MVC pattern, and there are literally hundreds of such frameworks for web development, including the widely-ported PureMVC, Ruby on Rails, and popular content management systems like Jooma.

The "Rails" MVC Model
Other frameworks refer to themselves as MVC frameworks, but their definition of Controller is vastly different. The work a traditional controller is handled by the browser and web server, by translating clicks into URLs, etc. Instead, the Controller is more of a process controller, driving the user's progress through a given interface. This is more in line with the aggregate controllers from "traditional" MVC, who's purpose was to coordinate the behavior of dozens of child views/controllers together into a single unit. These new Controllers handle tasks like Routing and Redirecting, Persisting and Restoring models, etc.


The "ASP.NET" MVC Model
Of course, programmers being what they are, it should come as no surprise that there is a lot of debate over how many of these frameworks truly represent an MVC pattern. By now you can probably see why: under the "classical" MVC definition, none of them do. In particular, for some web-based Frameworks, it's not intended  for the view to have any direct interaction with its controller. This changes the "picture" of the MVC model. You can see some of these pictures here: the "classic" MVC model from Smalltalk, a newer MVC model from Ruby on Rails, and the MVC model from ASP.NET MVC. In each case, the arrows indicate which components can "talk to" each other; in Smalltalk, you can see that not only are the View and Controller very tightly bound together, but the View directly updates the model (and, in turn, the Model notifies the View of changes.). In the Rails implementation, the View and Model never talk to each other; while in the ASP.NET implementation, the View is bound directly to the Model and posts data updates directly.

The ASP.NET MVC Framework is a good example of the new direction for MVC-style development, particularly since it's the most likely place a .NET developer will run into the MVC pattern. Classically, ASP and ASP.NET applications used a unified architecture, with business and navigation logic melding together with display logic, all in the code-behind for ASP pages; or else a variation of MVC called Model-View-Presenter that we'll cover next time. In about 2009, Microsoft began publishing the ASP.NET MVC extensions, designed to incorporate the MVC pattern into web applications. Under this model, a web application consists of these three elements:
  • Model: Classes representing the application's data and business logic 
  • View: Templates used to display a piece of the model via a browser, along with any code to enhance the UI experience.
  • Controller: Classes that translate URL requests into commands against the model, then provide the updated model data to the appropriate view.
With these new-style MVC frameworks, the focus is less on separating the model from the controller, as it is on separating the view from everything else. In the prototypical ASP.NET MVC application, the model is nothing more than an Entity Framework model, with lots of business logic ending up in the controller classes. For example, you might have methods like the following in your AccountController class:
public ActionResult Accounts ( )
{
    var results = from x in this.db.SearchAccounts("*")
                    where x.RequestStatusTypeId == (int)RequestStatus.Approved
                    select x;
 
    return this.View(results);
}
 
public ActionResult RejectedAccounts ( )
{
    var results = from x in this.db.SearchAccounts("*")
                    where x.RequestStatusTypeId == (int)RequestStatus.Rejected
                    select x;
 
    return this.View(results);
}
The goal here is to keep the View, the user interface, isolated from any business logic to make it easier to change, update, or even replace that view with something else. For example, you might have a view for desktop browsers, and a different view for mobile browsers, and maybe even a touch-screen enabled view. The MVC Framework itself is doing the classical Controller job, as you can see from above: the raw URL requests to IIS are being translated into method calls on a controller class, and the logical View object we provide is being translated into HTML and sent back to the client, all under the hood.

Some people consider this an "abuse" of the MVC pattern, to put so much obvious business logic into the Controller. Instead, our model should simply grow to include the exact data retrieval methods we need. This brings the Controller more in line with its intended purpose, but makes it look almost redundant:
 public ActionResult PendingAccounts ( )
 {
     return this.View(this.db.PendingAccounts);
 }
 
 public ActionResult Accounts ( )
 {
     return this.View(this.db.Accounts);
 }
I have used both patterns for production code, though I lean more towards the latter. It works particularly well with a repository pattern and dependency injection, and taking advantage of the fact that all Entity Framework entities classes are partial classes (allowing me to extend them safely.) Whether or not this is "true" MVC, I think, partially misses the point: this pattern provides clear benefits that increase productivity and lowers maintenance costs.

Modern Derivatives of MVC


While MVC is making something of a resurgence, it has also spawned a number of variations on the theme. The basic concept remains the same: separating the logical components of a system in a clear and consistent manner. But which logical components are defined in the pattern change. Since the controller component from MVC is now typically handled for us, most of these alternatives take the form of Model-View-Something Besides A Controller.

Next time, we'll look at a few more of these, including the MVVM pattern favored by WPF applications.

In the mean time, some further reading on this subject:

1 comments: