MVC is dead, long live MVC

Modern software development is all about frameworks. The vast majority of projects can be built on top of a vast amount of pre-existing work. Who ever stops to think about the percentage of lines of code in their Rails project that they wrote themselves? These frameworks have made it spectacularly easy to produce very complex applications. Consider an iOS app, written in a weekend by a twelve year old, that goes on to be downloaded a million times. But they have also made us lazy and dependent. Not that a developer should reinvent the wheel, but lazy to learn how the frameworks are designed in order to understand their best usage, and limitations.

Doing modern web (and occasional mobile app) development, I’m constantly working with MVC frameworks. Model–view–controller (MVC) is a software architectural pattern for implementing user interfaces. The key word in that definition is “pattern”. MVC is not a set of rules, its a suggestion. You can implement the pattern without using the words “model”, “view”, “controller” and you can have classes with those names without implementing the pattern. I think that it is essential for a software developer to be aware of the design pattern she is using.

Its easy to to get the impression that MVC is the only reasonable way to build a data driven user interface. Especially web sites. A quick look at this comprehensive list of web frameworks reveals just how popular MVC is. And for good reason, it is an extremely effective way model user interactions with a website (or mobile app).

This article isn’t about the suitability of MVC as a pattern for web frameworks. Rather I want to look a bit deeper at the features of MVC that make it so useful, and to discuss how these can applied outside of the pattern with the same advantages. MVC predates Rails by at least 11 years. It was conceptualised without any intention of being used for modern web applications.

MVC is just one example of the Observer Pattern. Which in turn is a way of following the separation of concerns principle that is a corner stone of object orientated programming philosophy. That is the concept that code should be organised in small components, each with a well defined purpose. And that these logical roles are confined within their module. In fact separation of concerns should be a guiding principle of any software development project; it is essential for creating maintainable code.

The observer pattern is approach for ensuring that your concerns are separated. Of course the different modules of a program need to interact with each other, while each is performing its intended role. The observer pattern accomplishes this communication by having objects, called the subject, maintain a list of dependants that are its observers. When the state changes in the object, it notifies its observes and they can take the appropriate action. No data flows from the observer to the subject. In this way the responsibilities of each object (module, script, whatever) and their relationships to each other are clearly defined.

MVC is easily explained in that context. A program is made up of components which are either a “model”, “view” or “controller”. A controller observes a model, and view observes the controller. The model is represents the underlying data and the user interacts with the view. Each of these components takes on a different appearance depending on the application.

In a Rails application the model classes are responsible for wrapping the database; the controllers are observe the data in the model and make it available to the views; and the views are responsible for presenting the the data to the user. The web page is not the view. The class which parses the templates is the view (of MVC, obviously its convenient to call the template a view). The view does not communicate with the controller. When you make a request, any changes that were made on the data are sent to the server, which updates the model, and then a new MVC stack is instantiated to return the result.

Ember and its cousins are often referred to as frontend MVC frameworks. I don’t have any experience with the others, but Ember is not an MVC. Two way binding - which is essential in a data driven web page - absolutely violates the pattern. There are classes called “model”, “view” and “controller”, and their functions are similar to those in Rails, but not the same. The controller decorates the data in the model for use by the view. However changing a value in the view, updates the model. Models observe views, and views observe models (via the controller).

And that’s just fine. MVC is a powerful pattern and has proven to be very effective for writing web servers, but its not the right fit for all problems. It is crucial as a developer to understand the frameworks that you are using. To know how they are designed, their intended usage and when it is appropriate to bend or break their rules.

Ember views are not supposed to directly interact with models. But they can, there’s nothing stopping you from creating a view that has a model property. I have written an Ember application demonstrating what can be achieved by ignoring the architecture of a framework. This is an implementation of workflowy a hierarchical list keeping application, with source code here. The majority of the code is in this component (components are views in an architectural sense). The component has a property which references a model. By accessing the model directly, the component is able to recursively render itself and all its child nodes. This recursive rendering means that actions on the data are most easily handled within the component that is rendering the model. Such a pattern violates the way the Ember is supposed to be used, but it allowed me to create a very powerful application while writing minimal code.

It is irresponsible as a developer to try to do everything from scratch. There is an unprecedented wealth of open source code covering most application domains. To be an effective developer one must leverage the work of others. However it is too easy to just take their code for granted. One must understand how the framework is supposed to work and when it is appropriate to contravene that. If your code is frustrating you, ask yourself: “am I writing this because of my application’s logic, or in order to fit in with the framework?” Conventions are great they can greatly simplify development, but there are no holy cows, the intended purpose of the application must always be foremost in its development.