Wednesday, February 18, 2009

Tom’s Patterns Cheat Sheet, Part 2 – Model View Controller

MVC is one of the oldest, most widely known architectural patterns. It involves decomposition of the system into three parts, using terminology from patterns god Martin Fowler's GUI Architectures paper:

  • Model: domain object model.
  • View: user interface that displays the state of the model.
  • Controller: an object that receives user input and updates the model, and possibly the view.

Here's the usual MVC dependency diagram:

This means the model is independent of (has no knowledge of) the views and the controllers, the view and the controller have strong knowledge of the model, and the controller has knowledge of the view. So we would expect, for example, to be able to make drastic changes in the view without affecting the model at all, but changes in the model will probably mandate changes in the view.

MVC has two primary uses: rich client GUIs and thin client Web applications. It was originally developed for rich client UIs, but in that space it has mostly been superseded by other patterns. But it's alive and well in the web space, and is the basis of both Ruby on Rails and ASP.NET MVC. See this MSDN article for a good overview.

MVC in Rich client GUIs: mainly uses a variant called active model. "Active" because the model takes action (notifies an observer, raises an event) that lets views and controllers know when its state has changed. The general data flow goes like this:

  • User stimulus happens, controller receives the event (often without the view's involvement at all)
  • Controller updates the model
  • Model raises a data changed event
  • View traps the event and updates itself

Graphically this looks as follows. A good example of this can be found here.

Dotted lines are used to indicate communication via events, solid lines to indicate direct manipulation. Some notes:

  • There may be multiple views and multiple controllers working off a single model.
  • The controller and the view don't depend on one another in this picture. Martin Fowler actually leaves the controller -> view dependency off his dependency chart because, he says, it's not often used in the rich client GUI case. It is used commonly in the web case however.
  • This is often implemented at a very low level of granularity – one MV pair for each widget, or even for each window in each widget.
    • In that case the "model" may represent a value stored in a widget, and not in a database.

Pros:

  • Separation of model from view. Allows changes in the view without affecting the model. Good for cases where the views change more frequently than the model, as is usually the case.

Cons:

  • Use of observers/events increases complexity.
  • Frequent updates to the model could result in many data changed events and suboptimal performance.
  • Separates view from model writes, but not from model reads. Since views are difficult to unit test, this means logic involved in transforming model data for presentation is not covered.

MVC in Web applications:

Uses a variant called passive model. "Passive" because the model makes no effort to inform anyone that its state has changed. Flow is as follows:

  • HTTP request happens, controller on the server receives the request.
  • Controller updates the model, usually resulting in a database update.
  • Controller selects the view appropriate for the request, provides it with any model data it needs, and returns it, typically in the form of HTML, XML or JavaScript.
  • The browser renders the view.

This looks like any well factored web application that you've ever seen, in which the domain model is carefully separated from the web UI code, but there is an important difference. In MVC web applications the web UI code is separated logically and physically into separate view and controller elements. Some notes:

  • The view is as simple as possible, usually just an HTML template containing some simple server-side code snippets.
  • The controller is designed for maximum testability. In the case of ASP.NET MVC, it is free of UI and web server dependencies, which the ASP.NET MVC framework provides to the controller via easily mocked interfaces. In the case of Rails, controllers are designed to be easily testable using functional tests.
  • The view and controller are larger grained than in the rich-client case, generally at the level of one controller/view per page.

Pros:

  • Separation of controller from model helps manage complexity of large web applications.
  • Designed to support Test Driven Development (TDD).

Cons:

  • For small to medium sized web applications, increases complexity.


No comments:

Post a Comment

Followers