If you read up on the Model-View-Controller (MVC) design pattern, you might find yourself a bit confused. In fact, I found myself confused by it when I first started reading about it, because there are plenty of resources out there to describe it, but so many of them seem to have different flavors of MVC and different diagrams explaining how data flows that it’s no wonder that programmers are bewildered about it. Fully believing that I don’t want perfect to be the enemy of the good, I’ll show a few practical implementation details of one way of looking at MVC, primarily focused on the Web needs.
The primary thing you need to know about MVC is how logic can be distributed:
- Model
- Business logic goes here
- View
- Presentation logic goes here
- Controller
- Application logic goes here
Just like HTML is moving to a separation of structure (semantic XHTML) and presentation (CSS), so should your applications be geared to understanding the different problem domains and separating out their functionality. The details of this separation can vary widely based on technical needs and developer opinions, but it should happen. With MVC, we have one form of separation which is fairly clear. Your view roughly corresponds to what people see (but it might be an RSS feed that a client is reading). Your model is your data model and the business rules. Your controller only contains application logic and tends to act a bit like a mediator between the the model and the view (different implementations can vary widely on this).
The view is the simplest bit as far as the Web is concerned. You typically build HTML pages and the user can fill in forms or click on links and stuff happens. The HTML is what your end user usually sees and there should be little to know application or business logic there. In fact, that’s one of the reasons AJAX is so popular. When done properly, that logic isn’t duplicated in the view layer. When done improperly, it can become a maintenance nightmare. How many times have you written Javascript form validation only to have to rewrite in your back end code? More than once I’ve found that my front end and back end validation didn’t synch. AJAX is a great way of alleviating some of this pain.
Getting back to the presentation layer, imagine the following HTML template (written with Template Toolkit syntax. The rules of the template are that users can win “points” and choose prizes based on those points. Further, they should only see the items they have the points to purchase. However, if you’re an administrator of the site, you should see all prizes when you’re administering things.
<ul>
[% FOREACH prize IN prize_category %]
[% IF user.points > prize.points %]
<li>[% display(prize).as_html %]</li>
[% END %]
[% END %]
</ul>
The above template seems nice, but you see that conditional in there? What happens when you want to reuse this template? The administrator won’t be able to see all prizes unless they have enough points! You could give administrators an arbitrarily large number of points, but that’s an ugly hack and not truly reflective of what you’re trying to do. It would be better to having something like this in your controller code (Perl psuedo-code):
my @prizes = $category->fetch_prizes($user); $view->display( prize_category => \@prizes );
Assuming that the fetch_prizes() method understands the difference between regular users and administrators, your template then becomes reusable:
<ul>
[% FOREACH prize IN prize_category %]
<li>[% display(prize).as_html %]</li>
[% END %]
</ul>
Now why do we have as_html at the end of that? Well, what if you want to send data in plain text, as a GIF image, or in PDF format? Your display() function should know how to render your objects in various different ways so that you have a flexible system which can render things any way your end-user wants it. We used a similar system with one company where we resold data and customers could view the data as HTML, PDF, or Microsoft Excel spreadsheets. Because we kept our views very generic and only included presentation logic, we didn’t have to worry about needlessly duplicating a bunch of logic in our presentation layer.
A more direct problem, though, is something I see all the time in novice’s Perl code. You need to fix a bug in their code which adds products to a shopping cart and you look at the function which contains this:
sub add_product_to_order {
my ( $dbh, $p_id, $o_id ) = @_;
unless ( $o_id && $o_id =~ /^\d+$/ ) {
dienice("Bad order number $o_id");
}
my $o_sql = 'SELECT * FROM orders WHERE id = ?';
my $p_sql = 'SELECT * FROM products WHERE id = ?';
my $order = $dbh->selectrow_hashref($o_sql, {}, $o_id);
my $product = $dbh->selectrow_hashref($p_sql, {}, $p_id);
# snip
my $html = <<'END_HTML';
<html>
<head> ...
}
This is an absolute nightmare to work with, but it’s all too common (particularly the hateful SELECT *, but that’s a rant for another day). When you’re working with Web code, you don’t want to see database handles or HTML. If you’ve done that, you’ve failed. Now let’s clean it up a little bit.
sub add_product_to_order {
my ( $self, $o_id, $p_id ) = @_;
my $order = Order->new($o_id) or $self->add_error(Order->error);
my $product = Product->new($p_id) or $self->add_error(Product->error);
$self->handle_errors; # doesn't return if errors
$order->add_to_basket($product);
$self->show_basket($order);
}
Now that code isn’t perfect (I can see several things I’d probably want to change in it), but it’s one heck of a lot better. You can see that it pretty much only contains application logic, not business rules, knowledge of the data store or anything other than application logic (think “control flow”). Further, because we’ve cleanly separated the model, view, and controller code, when we need to go in and clean this up, you can proceed easier knowing that you’re less likely to violate business rules or break the presentation layer.
Now you might wonder where that order came from? Here’s the beauty of it: you don’t care. If at first you store all orders in a database, you can use that code. Later, if you decide that you want to use memcached or some Web service to store the orders, you can just change your Order code and keep your interface the same. Imagine trying to do that with all of the responsibilities jumbled up as in the first example!
Another question which regularly arises is how to distinguish between business and application logic. Admittedly much of this is dependent on your needs, but a good rule of thumb is that universal logic, that is to say, logic that must always be triggered, should be pushed into the model. For example, if “anonymous” users should never see prizes but they can still get to the page which has the prize list (presumably because there are other things to see), then you don’t want your controller code to be determining this. Your code would be similar to what I showed above.
my @prizes = $category->fetch_prizes($user); $view->display( prize_category => \@prizes );
However, if on some pages they can see the prizes, then your controller code should handle this:
my @prizes = $view->for_everyone ? $category->fetch_prizes($user) : (); $view->display( prize_category => \@prizes );
You may have noticed that I didn’t really explain MVC itself. That’s because there are several flavors of it and I’m less interested in the particular implementation details as I am with properly keeping different parts of the system separated. Also, it’s OK to only have it only partially implemented. When you’re reworking a large system, you take small steps. Maybe you pull your HTML out into templates to start with. That’s OK. By slowly working towards a proper separation of concerns, you’ll build more maintainable systems that become a joy to work on.


"I didn't really explain MVC itself. That's because there are several flavors of it"
But there shouldn't be. MVC's even simpler in a web context because there is no "listener" to code: the web server does the listening for you. This actually simplifies "MVC2" (for the web) down to pretty much a concrete instance of the Mediator pattern: the Controller mediates between the Model and the View.
Anybody who tells you anything different is a liar and a fatmouth ;)
But seriously, in the past 9 or 10 months I've written code in THREE languages which is meant strictly to properly separate the 3 concerns that comprise MVC (rather than being a "full stack" framework replete with ORM layer, etc.) The crux of my code in pretty much any language being
A) the notion of a "ModelTransferObject" (or MTO: Spring WebMVC's "ModelAndView" is actually what I would call a "ModelTransfer Object"),
and B) a "template method" leaving the user to implement the intuitively named methods: applyInputToModel() & applyModelToView(). Here's that template method in PHP:
static function sendResponse(IBareBonesController $controller) {
$controller->setMto($controller->applyInputToModel());
$controller->mto->applyModelToView();
}
And in Python:
class AbstractController(IController):
def sendResponse(self):
self.applyInputToModel().applyModelToView()
Other than that the core framework in either of these languages weighs in at about 50 lines of code!! After successfully that THIS is the very abstraction that ALL more fully-featured web frameworks (with Dispatch and/or Flow controllers) should be built upon
I must be "a liar and a fatmouth", but there is indeed more than one flavour of MVC. With TT you don't need to "applyModelToView" or push stuff from the Model to the View, but instead the the View can pull stuff out of the Model (via the Controller). So there's at least 2 flavours ;)
I do see the value of many flavors of MVC, but I'll call them implementations. The crux of MVC is to try to isolate the domain model (business rules) from its use. The use being not only the presentation, but also the application specific logic that glues the rules together in some order.
There are many implementations of MVC for good reason. Each has a trade off with regard to reuse and coupling. Also language design plays a hand in the implementation.
Stepping back to the basic GoF design patterns shows that a pattern is designed to show a conceptual solution and not the exact implementation. For example, a singleton is often implemented as a class without a public constructor. In Python I usually implement it as a module level attribute. They are completely different implementations, yet the both allow for only one instance of a particular class.
The code you highlighted (with the mixed responsabilities) looks like it was taken straight from my server.
I've been in the proceess of cleaning as much as I can (since reading the excellent Perl Best Practices), but I hadn't thought to take the separation as far as you showed.
Could you please go into some detail about separating control from model? In other words, where would the $dbh finally go?
For instance, what about a subroutine when all I need is to display a list of (say..) invoices. Should I make an Invoice class and then an InvoiceList class?
Jorge: as a general rule, the $dbh should never be seen in your controller code (for those not familiar with Perl, $dbh is the traditional name for a database handle). That belongs in your model or even further down. In fact, if you use an ORM (object relational mapper), that's where the $dbh should generally be with the model layered on top, potentially delegating out to various ORM classes. The reasons for this strategy are probably the subject of another blog entry, though.
As for an Invoice class, that can be handy, but it's generally much better to have a generic Collection class -- or something conceptually similar -- to put them in, rather than an InvoiceList class. That's because a Collection can be reused with other classes and your code will know how to deal with a Collection.
In fact, the only reason I could think of to create an InvoiceList class would be if, for some reason, you had more specific needs than a collection. In that case, you might do something like this:
If you do something like that, you can ensure the same interface as with a collection, but override methods for your invoice-specific behavior. The important thing to remember is that you must be able to use Collection and Collection::Invoice the same way!. The latter might offer additional behavior, but it shouldn't offer less. See the Liskov Substitution Principle for more information.
So, in short, make sure your controller only contains control flow code -- something harder in practice than many would think -- and try to write generic classes which are easy to reuse.
Also, if you're migrating a codebase to an MVC style architecture, trying to do it one piece at a time can help. Do everything at once can be fatal.
I like the way Curtis has defined Model, View, and Controller. Now that if people try to learn the 'usually unnoticed' difference among them.
Good article!