The MVC Colouring Book

Recently I’ve been working on MiniMVC, a very tiny MVC framework based on Mason. When I’ve mentioned it to people, I’ve had a surprisingly high number say that they’ve heard of MVC — the Model-View-Controller pattern — but aren’t quite sure what it means in practice.

So here’s a demonstration, in AMAZING TECHNICOLOR!

First up, some CGI

This is a simple CGI script, very much like what you would’ve been writing in the late 1990s. It takes a web request including the ID of a book in a library and displays that book’s details. You’d call it by going to a URL like http://example.com/show_book.cgi?id=42.

This code is untested — I haven’t actually run it — but you’ll get the general idea. I’ve also left out a certain amount of boilerplate, which I hope you’ll excuse.

Without further ado, I present: Web programming circa 1998!

    #!/usr/bin/perl

    use strict;
    use warnings;
    use CGI::Simple;
    use DBI;

    my $cgi = CGI::Simple->new();
    my $dbh = ... # connect to database here

    my $book_id = $cgi->param('id');

    print $cgi->header();

    unless ($book_id) {
        print qq(
            <h1>Error
            <p>
            You need to provide the ID of a book to display.
            </p>
        );
        exit;
    }

    my $sth = $dbh->prepare(qq(
        SELECT * FROM Books
        WHERE ID = ?
    )) or die "Can't prepare SQL statement: " . $dbh->errstr();

    my $book;
    if ($sth->execute($book_id)) {
        $book = $sth->fetchrow_arrayref;
    }

    unless ($book) {
        print qq(
            <h1>Error</h1>
            <p>
            Couldn't find that book in the database.
            </p>
        );
        exit;
    }

    print qq(
        <h1>$book->{title}</h1>

        <p>
        Author: $book->{author}
        </p>
        <p>
        Published $book->{year} by $book->{publisher}.
        </p>
    );

Three main activities

There are three main types of code going on here.

1. Talking to the database
2. Printing out HTML
3. Everything else.

Let’s do some colouring-in and you’ll see what I mean

MVC CGI

Green for database, red for HTML, blue for everything else (in this case, the logical flow and error handling).

As you can see, it’s all mixed up: there are chunks of colour all over the place. This is only a tiny example, but imagine if you wanted to write a whole library catalogue system like this. Now imagine you want to tweak the HTML slightly. You’d have to go digging through all that CGI Perl code to get at it. Now imagine a change to the database structure, which would mean you have to go through a whole heap of CGI scripts and make sure that all the SQL embedded in there is updated. It gets old really fast.

Splitting it out into M, V, and C

By using a Model-View-Controller layout, you keep these three types of code (database, display, and other) quite separate.

Here’s a demo using MiniMVC, but the principle holds true for any web-based MVC framework, whether it’s Ruby on Rails, Catalyst, or whatever.

Put your database code in a “Model” class

In MiniMVC, and assuming this application is called “Bookshelf”, that’d be `lib/Bookshelf/Model/Book.pm`.

Ordinarily you’d use an ORM (Object Relational Mapping) library for this, to avoid having to write any SQL whatsoever. Since I don’t want to have to explain all that as well, I’m going to more or less just use the old-fashioned DBI techniques you saw above.

MVC Model

Put your display code in a “View”

In MiniMVC, views are HTML::Mason templates and live in the `view/` subdirectory. We’ll need two of them: one to display the book, and one to display error messages.

Here’s book display one, aka `view/book/display.mhtml`, first:

MVC View 1

And here’s the error one, `view/error.mhtml`:

MVC View 2

Everything else goes in a Controller class

Let’s call it `lib/Bookshelf/Controller/Book.pm`.

MVC Controller

Bring it all together

Finally, we need to make sure there’s a mapping between a URL like http://example.com/book/display/42 and the controller we just wrote. In MiniMVC we do that by editing the Dispatcher class, `lib/Bookshelf/Dispatcher.pm`:

    package Bookshelf::Dispatcher;
    use base MasonX::MiniMVC::Dispatcher;

    sub new {
        my ($class) = @_;
        my $self = $class->SUPER::new({
            'book' => 'Bookshelf::Controller::Book',
        }
    }

    1;

Now, when you point your browser at http://example.com/book/display/42, the dispatcher knows to use the controller `Bookshelf::Controller::Book` for any URL with `book` at the start. It then calls the subroutine `display()` passing it the argument `42`, which gets used to fetch the book by ID from the model class.

Et voila!

Having separated out the model, view, and controller code, you end up with something that’s much easier to develop and maintain. Need to change the way the website is displayed? All you touch is the view. Need to swap out your current database and replace it with a new one? No need to touch anything but the model. New business requirements mean you need to add some extra control-flow logic? The controller’s where it’s at.

Read more: Model-view-controller on Wikipedia.

9 thoughts on “The MVC Colouring Book

  1. Bravo. The use of color is very helpful to me. Now I just have to get out the crayons and apply them to my 1998 CGI scripts :)

    I have been making stabs at using CGI::Application and Catalyst, but so far not much traction. I look forward to exploring your MiniMVC work!

  2. I prefer to take it a step further, and never output HTML directly. XSLT is good: it lets you treat HTML as an XML document instead of as a string of greater-thans, less-thans and assorted other ASCII characters. This makes templating systems like Mason less attractive to me.

    Apart from that, I’m in complete agreement. Monochrome source code is the only way to go!

  3. Hey Eric,

    How many XHTML-like views are you providing?

    Surely CSS and (X)HTML is sufficient – XSLT seems an un-necessary addition given that HTML, RSS and REST, etc will all contain different content anyway.

    I don’t use Mason, I use Template Toolkit, I’ve never needed or wanted XSLT yet – the only project where I’ve seen it required was a major document management system for a national standards body (using the Maypole Perl MVC framework).

  4. The problem is that you’re thinking of HTML as a kind of text, but that’s wrong. If you produce a PDF document and then notice there’s an apostrophe missing, you don’t open the document in a binary editor and correct it, do you? You fire up your word processor, correct the bug at the source and regenerate the PDF. Well, HTML should be the same. If you find yourself producing code that generates HTML tags, then (as the cat macros say) “YOUR DOIN IT RONG!”

    So instead you edit the static parts of your site as XHTML in XML documents. You generate dynamic output at the server side as XML. If you must produce HTML at the client side, you do so using the DOM, but that’s outside the scope of this. The goal is to push everything through an XSLT template that slurps in the appropriate content and adds all your navigation and headers and footers (or RSS stuff, or whatever).

  5. But HTML is just marked up text, you’re comparing a document I would write by hand in an application to a generated report – which is apples and oranges – I write and re-edit a document before printing or converting to PDF – very different to generated reports which are tested before deployment.

    Essentially you’re suggesting I use XSLT for templating, which is a bad idea – particularly for automated reports. XSLT is nice for stylising, but not for nontrivial templating. Not only does it require a great deal more work up front, but it’s slower and more error-prone at runtime.

    I have 2 templates, using a far better templating solution than XSLT, one for ODF one for HTML, both very different, if I need to change some of the small ammount of non-generated text, that is both rare and simple.

    XSLT is good if you don’t have a decent templating system, or need simple restyling or formatting of XML, but for 99% of problems you’re better of with a tool designed for the job.

  6. No, HTML isn’t marked-up text. It looks like it, but it isn’t, and that’s the reason it doesn’t make sense to you to use the right tools for the job. HTML is a tree-structured document, with a node called “html” at the root, a “head” and a “body” at the second level, and so on. That’s what HTML is. What it looks like is entirely unrelated.

    The telling point in your argument, from my POV, is that you say XSLT is error-prone at runtime. It’s not. As long as your input is a tree document, your output will be too. If your input is text that kinda sorta looks a little like a representation of a structured document but only does so because you’ve cleverly remembered never to put a slash-foo before a foo or leave an attribute unquoted, THEN you’re going to run into problems.

    Again I say: the right tool for the job is XSLT, or anything else that works with the DOM. Everything else is what I call Programming By Puns: it looks right, but it’s not really.

  7. HTML is as much marked up text as the programming language I write, both are tokenised into nice abstract trees, but both remain human readable text organised into a structure for computer processing.

    In terms of a report – HTML is content marked up for semantic organisation and basic layout, with CSS providing styling.

    XSLT *is* error-prone at runtime – syntax/parsing aren’t the only errors – logical errors are not only harder to spot, but harder to avoid and fix. XSLT makes a problem bigger by providing another layer of complexity and escaping troublesome characters.

    As I’ve said templating works far better for most jobs, a well-formed and valid template won’t stop working or suddenly become invalid, or be thrown by unescaped or double escaped content and can even handle it well.

    I can generate valid XML/HTML/ODF, or create it manually, either way – I still use it as a template and XSLT doesn’t provide any benefits.

  8. Aaron, in what format is your data (which you’re using to generate HTML/HTML/ODF)?

  9. Hi Dave,

    Original data sources are a mix of ICAO, Met Office, FAA and US DOD data feeds – parsed using perl Lexers and stored in a database as plain text, then pulled out as objects with validation and other methods (such as providing lat/lon, dates and other properties).

    My templating system (http://www.tt2.org) allows me to provide arbitary data structures, including iterators of these objects to the templates, as well as direct access to classes for class methods, the ability to call object methods, etc.

    The templating system also provides dozens of built-in filters and hundreds of extensions to make it simple. All of which is heavily tested and proven to work when it matters.

    Writing custom XSLT would not only be a poor use of my time, but introduce the risk of errors and require further unit and regression tests. Changes would also be slower than modifying templates, and with only 2 main templates (or even dozens) for a particular report ‘perl -pie’ allows me to search and replace in an instant.

    Templates are also accessible to designers, and easier to track changes in. XSLT is just lose/lose : slower and more error prone both in development and at run time.

Comments are closed.