MVC in Web Development

Model-View-Controller is an architectural pattern that originated in 1979 in the smalltalk language (paper) for non-web purposes, and set foot timidly but with increasing appeal around 2001 (paper, requires registration). Its primary objective is the separation of concerns:

  • Regardless of how it is accessed by the users, the state of the application should be represented both as data (database or file storage, in-memory representation for performance) and as constraints on its functional behavior (keeping the state consistent, reacting correctly to events). This set of concerns is represented by the model.
  • The program will receive requests from users. These requests will usually follow a medium-specific definition, such as an HTTP GET or POST request, Java RMI or command-line execution of a program, and must be parsed and translated before they can be applied to the underlying model.This set of concerns is represented by the controller.
  • The program will display data back to the users. This representation will usually follow a medium-specific definition, either human-readable or computer-readable, such as HTML, XML, JSON, AMF, CSV, PDF or some other format. The data to be displayed, extracted or computed from the model and the request received by the controller, is then translated and wrapped in renderer-specific details. This set of concerns is represented by the view.

At its core, MVC is nothing more than a set of classification rules which answers the question “where should the code for this functionality go?” with a simple high-level answer. As a consequence, a lot of different flavors exist, each with their own (often slightly distinct) approach, and no universally accepted definition of the One True MVC.

A quick example of minimalistic Model-View-Controller in PHP:

// Controller 
$target = $_GET['target']; 

// Model
session_start();
$stats = array();
if (isset($target)) {
  $stats = array( 'hits' => ++ $SESSION[$target]['hits'], 'last' => $SESSION[$target]['last'] );
  $SESSION[$target]['last'] = date();
} 

// View
echo json_encode($stats);

This example receives a GET HTTP request containing a target. It then computes the number of times that target was queried from within the same session, along with the last time it was queried (if any), and updates the data in memory. Finally, it returns the extracted data through HTTP, encoded as JSON. This would be usable, for instance, as an AJAX helper to determine how many times a certain piece of content (article, video) has been viewed recently.

Large MVC frameworks have evolved. One such example, which was discussed on this blog a few months ago, is the Zend framework, which provides a Controller system (which comprises a Front Controller, responsible for dispatching the request to an user-implemented Action Controller that matches the request URI) and a View system (which is mostly a way of using PHP as a templating system by use of phtml files), along with utilities such as Zend_Db to help the implementation of models.

Another MVC framework I could recently get my hands on is the Alfresco Web Scripts system, which uses the filesystem (and a description XML file) for parsing and dispatching HTTP requests to a set of javascript controllers that can access and manipulate the underlying Alfresco data model, with the output being sent in various formats including XHTML formatted with FreeMarker.

As a whole, the Web Development world earns particular benefits from MVC due to the very nature of the HTTP protocol: every web application reacts in the same “dispatch and parse request, apply modifications and extract data, send back formatted response” archetypal sequence. As such, MVC is an excellent means of separating these three steps into cleanly defined blocks.

Common errors in MVC design

The absence of a precise definition of MVC makes it possible to create a seemingly conforming implementation and label it as MVC, have it go unnoticed by the community at large, but cause issues down the road because the implementation does not, in fact, support the usual benefits of MVC.

A frequently encountered situation is the Anemic Domain Model antipattern, where storage of the application data remains in the model, but the entire verification and behavior code is moved to the controller instead. For instance, the model stores and retrieves a plain text password value, and the various controllers related to authentication, registration and password reset all perform a hash on the password before storing it or comparing it.

In this example, one major advantage of the Model-View-Controller is lost: adding a new controller must now respect the invariants required by the other controllers (the new controller would have to manipulate passwords by using the same hash as the other controllers). By contrast, if the invariant had been made part of the model, then it would have been impossible for a new controller to forget about the invariant.

Consider the common situation where the model in Model-View-Controller is a simple database wrapper around several tables. In such a setup, the views and controllers cannot and should not assume any additional constraints or invariants on top of the constraints and invariants guaranteed by the table structure. If your controller assumes that a VARCHAR(16) database column contains at least four alphanumeric characters because another controller put it there, then there is a high probability that this assumption will break at some annoying point in the next few months. A VARCHAR(16) database column contains sixteen random characters of the database’s current encoding. If you wish to enforce an additional invariant (such as being four or more alphanumeric characters), add that invariant to the model (even if this involves adding more model code than originally envisioned).

The anemic domain model problem appears whenever the separation of concerns (the original objective of the MVC approach) is not correctly performed: the concern of enforcing invariants of data is not cleanly encapsulated by the model and is instead left to float freely in both the model and the controller.

Similarly, failure to correctly separate concerns between the view and model or between the view and controller lead to similar issues. For instance, if a view finds itself computing renderer-agnostic data, it’s quite possible that this computation belongs in the model instead, and keeping it in the view will inevitable lead to reimplementation once the same data will be displayed with a different renderer (such as a web service API).

MVC as a recursive pattern

Resist the temptation to create one controller, one model and one view for your program. In several cases, it can be interesting to have several controllers, models and views. It can be interesting to implement part of a model as a complete model-view-controller triad.

For instance, I would point to the analysis by Morales et al, which in an RIA model (where the client keeps its own Model-View-Controller triple) defines the server-side data manipulation as being a model: in order to support querying the server-side model by several means (local API, REST API, JSON/AJAX/AMF, HTTP-HTML and so on) the actual data model must in turn be separated from a server-side view and a server-side controller. Then, the client-side model interacts with the server-side model through the server-side view and controller, as illustrated here.

However, when considering the situation from the eyes of the client code, the server in itself is just part of the implementation of the client-side model: a remote entity which supports read/write queries through an appropriate protocol, which essentially amounts to a model.

Another situation is when a model is composed of sub-models. For instance, when a shopping cart aggregates several products, it can be interesting to make the product model distinct from the shopping cart model. In turn, the shopping cart view will own a product view that represents the product within a shopping cart, which may different from the product view that represents a product on its own.

As such, the shopping cart page contains a top-level controller and view, which recursively manipulate internal custom controller and view for the product model. The product model is independent and has its own top-level controllers and views.

The conclusion is that an MVC architecture should not be seen as a fixed high-level structure. Instead, controllers and views may use sub-controllers and sub-views that operate on other models (benefitting from the fact that a given model can have several controllers and views associated to it).

0 Responses to “MVC in Web Development”


  1. No Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



1150 feed subscribers
(readers who polled a feed this week)