My apologies to Rudyard Kipling for hijacking a quote from his Barrack-room ballads of 1892, for the title of this article on the evolution of the Model-View-Controller (MVC)architectural pattern. The rationale for the title is the fact than only of the principles behind MVC is the software engineering design principle ‘Separation of Concerns’, as you will hopefully see.
A few years ago (late 1970’s), in a place not that far away, a very cleaver person (Trygve Reenskaug et al) formulated the Model-View-Controller (or MVC for short) software pattern for the Smalltalk platform.
A key feature of the original pattern was the role of the user as the holder of the ‘mental model’. Another feature is the way in which output is presented to the user by the View but all input in received by the Controller (directly). From the Controller calls are sent to the Model to reflect data updates, the View to effect presentation changes, or both. Data changes in the Model that impact on the presentation are not returned via the Controller but sent directly to the View.
The Architectural pattern (in its more recent MVVM elaborations) typifies the software engineering principle of “separation of concerns”. All user interaction is conducted through the View component, data is maintained by the Model, and to eliminate potential inter-dependency, the View and Model are decoupled via the Controller. There have been many implementations and variations on the pattern including Model-View-Presenter (MVP) and Model-View-ViewModel (MVVM), to list just a couple.
I first came across the pattern many years ago at the heart of a small Visual Basic application. The pattern was employed to coordinate the interaction between the user (through the User Interface) and a small database; and it worked very well. Arguably the most prolific form of the general pattern are represented by dynamic web sites. The View is the combination of the web browser and the server hosting the site. The Controller is represented by the business logic layer or middleware behind the web server, and the database constitutes the Model.
One of the things I particularly like about the pattern is the way, it not only operates at a variety of scales (widget, User Interface to application) but, instances can work in cooperation with each other in a kind of cascade. There is usually an unnamed fourth element to the pattern in all its forms and that is, to use the UML term, the Actor: a human operator, external system or sub-system component that interacts with the MVC. The ‘cascade’ is formed but the Controller of a subordinate MVC communicating (as a Actor) through the View of a superordinate instance.
However, there are many interpretations of the MVC pattern relating to the way in which the Actor interacts with the MVC and the degree of separation between the Model and the View. This has resulted in various patterns such as MVP and MVVM all being grouped under the acronym MV*.
A virtual case study
Image we use a spreadsheet application or text editor to compile a list on songs we have in MP3 format. We create a single data file in CSV (Comma-Separated-Value) format; with one line for each MP3 track detailing its title, artist, album, track number, album artist, genre and duration. We notice there is considerable repetition of data such as album name, album artist, genre and artist. It is also difficult to envisage how we might accommodate playlists, but we “park” these points for the moment.
We want a small application to filter the CSV to list all tracks for a given Artist (track or album), Title (or partial match) or Genre. Being good little Software Engineers we partition the code so one module (View) presents the User Interface (filter terms and result list), another module (Model) manages the data (loading the CSV, filtering it according to terms provided) but we hit a snag.
The View needs to know the name of the Model so it can send it the filter terms, so it needs the Model to be instantiated first. The Model needs to know to whom to send the results of the filter, so the View needs to be instantiated first. Ha, ha, we create a Controller module that we actually instantiate first, it constructs both the View and Model modules telling them only of itself as the communications broker between them.
We decide rather than using another application to update our data file we will enhance the application to enable us to add new tracks. We update the Model to provide a mechanism for adding new rows to the CSV file. We expose the function to the Controller but, to this point, the View is unaffected. We upgrade the UI to include a “add new track” dialog that provides the fields required to enter the details. Finally, we send the details to the Controller where they are passed to the Model (if it’s ready). Each step is a decoupled action and can be performed in a variety of sequences with minimal disruption to the working of the application. The feature itself will not work until all the pieces are in place but the extant functionality will be just fine. Also, the new functions/methods can be tested incrementally and even developed using a Test-Driven-Development (TDD) approach.
Our data file beings to grow, performance starts to suffer and we realise, maybe a CSV file is not the most appropriate mode of storage for efficient filtering. Perhaps something like SQLite might be a more effective component. Here is where the benefits of our architecture begins to pay dividends.
Only the Model needs to be updated and any interface changes (of which there should be none within the application) will be limited to the Controller (which is a simple fellow). The View (User Interface) is completely unaffected.
With the new, more versatile, data store established we can apply normalisation rules to the data to remove duplication, establish relationships between data entities and consider further enhancements such as maintaining play lists.
Time passes and we start to wonder, would hosting the application using a web server enable us to access the list of MP3s from computers were we don’t have our application installed. So we replace the UI within the View module for an API we can call from another application and upload the CSV and application file to a web server. This creates in effect a new higher-level Model.
Final step. We create a new ‘higher-level’ Controller to wire the two components together – in a decoupled fashion of course. We create a couple of (non-standardised) web services that monitor the HTTP line for (AJAJ/X) calls from the web page rendered by a client-side web browser. There are only two messages (create and filter) that map directly to functions exposed by the Model.
There we have it, our application “web-ified” and using a two-level MVC approach. You may think “it has to be more complicated than that”, and I have raced along a bit, but the technology is here, free (on the whole) and standardised (in most cases).
In case you were wondering about the Rudyard Kipling quote “… never the twain shall meet …” in the title, it is just my purist tendencies coming through. Of all the varieties of MVC available, I still prefer the Passive View interpretation that keeps the View and the Model completely decoupled via the Controller. It is fair to argue this variation is not as performant as others as communication between the View and the Model has to go through the Controller which may be adding nothing to the interaction. Performance is an important consideration but the primary reason for adopting the MVC architecture pattern at all is to aid the long-term maintainability and adaptability of the application; a feature vital in these Agile times.
The implementation of MVC employed by Facebook came into difficulties when they attempted to scale the Model and View components. The primary difficulty they found resulted from the bi-directional and direct interaction between the Model and View. Another issue arose through the lack of flow control impose by the Model and View.
The Facebook MVC does not quite match any of the variations described above but their alternative application architecture, called Flux, does have some similarities to the Supervising MVC pattern.
Facebook describes the Dispatcher as a kind of “traffic controller” because it controls the flow of actions coming back into the system via the View and restricts from going into the Store (Model) before the previous update completes.
I am sure purists and academics will disagree with my supposition but the alignment between Flux and the original (Trygve Reenskaug) MVC pattern is quite apparent to me; perhaps if crossed with a message-based Pub-Sub mechanism. In Dave M Bush’s excellent article “An explanation of the Flux pattern” he relates Flux to the PUB/SUB pattern, with the View as a publisher and a Model a subscriber but with the Dispatcher as a message passing hub. According to the article, the flow of data from the Model back into the View does not employ the Pub/Sub pattern and updates in the Store (see diagram above) are applied directly to the View. Dave’s article is well worth a read.