Tuesday, December 4, 2012

Essence of MVC

The Model-View-Controller pattern (MVC) was first described at Xerox PARC by Trygve Reenskaug in 1979:

MVC was conceived as a general solution to the problem of users controlling a large and complex data set. The hardest part was to hit upon good names for the different architectural components. Model-View-Editor was the first set. After long discussions, particularly with Adele Goldberg, we ended with the terms Model-View-Controller.

Trygve Reenskaug

Since then it has become the central pattern of virtually every application framework from the desktop to the web to mobile. I learned MVC from frameworks such as Rails and Cocoa, but my understanding lacked clarity. I wanted to reach beyond these artifacts and understand the essence of MVC, so I went in search of answers. After considerably more effort than I expected, I think I found some. This page is my current, best understanding of what MVC is and why it matters.

What is MVC?

Let's start with a simple, visual definition.

MVC is a pattern for taking a program...

and pulling it apart...

into modules with three well-defined roles:

The structure of a well organized MVC system is usually fairly simple. In general, there can be any number of model, view and controller modules. The communication channels between modules are restricted by an important rule: connections are only allowed between controllers and other modules. Non-controller modules should never talk directly to each other. Though not a rule, one more restriction is typically observed. Usually each view has only one controller associated with it.

NOTE: Advanced systems might use MVC hierarchically.

Now that we have a high-level idea of the structure of a MVC program, let's look at the three roles in detail.

The Model Role

A model's job is to hide and protect the user's important data. This is the data the user might want to access in 10 years - the data that has real-world significance. The model role draws a line between the data the user cares about preserving and the data that is temporary or can be re-generated from the models.

The internals of a model are responsible for storing the actual bytes that represent the user's data. Models are also responsible for ensuring the integrity and consistency of their data. Last, a model must provide efficient methods for querying and altering its data.

More than any other part of the system it is important to maintain a well defined API for each model. In order for a model to do its job properly, all methods of extracting and altering its data must be well defined, understood and respected.

The View Role

Views are the public face of a system. They determine how a user feels about the system. The attributes that make a view great are as much determined by psychology and aesthetics as engineering and science. A view's primary job is to communicate data to the user as effectively as possible. Their secondary job is to communicate the interactive nature of the interface.

Views encompass all aesthetic concerns of their system. All presentation assets, such as images, fonts, styles and layouts, belong in a view. Code that transforms data into pixels also belongs in the views. The view may even have hooks for specifying which elements are to receive user inputs, but all input processing should be done in the controller. The focus of the view is letting the UX designer worry about how the data and interface are presented.

The Controller Role

A controller's job is to process user inputs and coordinate the relevant views and models. In the simple case, it starts by extracting information from a models, doing some preliminary processing and then handing the processed data to a view to be presented. When new user inputs arrive, the controller validates them, performs alterations to the model on the user's behalf and updates the view.

The controller role's modular boundary is not as well defined as the view or model roles. Controllers do everything models and views don't. However, they tend to have a structure which is well defined by the system's use-cases. Controllers are organized around how the system will be used. They provide the glue between any number of views and any number of ways to extract and alter data from the models and align them to fulfill the user's needs.

MVC Roles and Relationships Diagram

This diagram summarizes the MVC pattern, each of the roles and their relationships:

Why use MVC?

With the roles of MVC defined, the next question is why do they matter. What are the benefits of MVC? How do we make use of MVC most effectively to realize those benefits?

There are three main benefits I have discovered.

Separation of Concerns

"The central idea behind MVC is code reusability and separation of concerns."

yiiframework.com

MVC identifies a very specific set of concerns that are repeated in virtually every programming project:

MVC concerns by function:

  • Model: safely and consistently store the data that matters to the user
  • View: present all, a subset or summarization of the data to the user
  • Controller: respond to user inputs and events, update the view and model appropriately

MVC concerns by expertise:

  • Model: data reliability, data consistency, query efficiency, update efficiency and storage-size efficiency
  • View: graphic design, information presentation and UX
  • Controller: expertise in the problem domain and coordinating the other concerns

MVC concerns by people:

  • Model: algorithm and data-engineers
  • View: designers and artists
  • Controller: experts in what the system needs to do

These are very different people. Sometimes we are forced to wear more than one of these hats, but ideally we would have different people responsible for each concern. MVC lets people with different expertise focus on what they do best.

Managing Complexity and Mental Modes

MVC is an abstraction, and like many abstractions it adds complexity. However, like good abstractions, it compartmentalizes complexity. MVC can dramatically reduce the complexity of each part of the system.

MVC is a special case of the general concept of modularity, and is a surprisingly good first-pass for designing a system's modularity. Why is it better than the alternatives? The core reason is the concerns MVC uses to define module boundaries are exceptionally well aligned with the real-world.

The MVC concerns closely parallel how we learn and think and the kind of specialists society produces. The model reflects a highly analytical mindset whereas the view requires the most creative thinking. The controller is the most political because it must balance the needs of many potentially conflicting concerns.

MVC is a good modularization pattern because it isolates three major modes of thinking. All the hard-analytical work of the system is isolated in models and can be done while ignoring everything else. The creative, intuitive and emotional work of a view can be done without worrying about any analytical concerns. The only sane way to make sure every user's needs get met is to ignore the details and instead focus on the big picture. That happens in controllers. Good MVC design not only modularizes code but it also compartmentalizes our mental modes for working on the code.

Decoupling & Evolution

Perhaps the most important aspect of MVC concerns the long term maintainability of code. MVC decouples the system's three main components allowing them to evolve independently.

In a monolithic system there are many opportunities for coupling artifacts. Changes to the visual layout, data-hiding or visual encoding are much more likely to effect data on disk. They may even break file backward compatibility. In the other direction, changes in how data is stored such as adding or removing fields, or restructuring for increased reliability, consistency or efficiency are in danger of breaking views or being exposed directly to the end user. Not only do changes anywhere in the system potentially effect all other parts of the system, but because of those large scale implications, in large projects any number of people may need to be consulted before making those changes.

MVC creates a strongly decoupled system. By minimizing the interface between each part and making sure each concern is handled by the right component, most changes only effect the component being changed. Decoupled views, for example, can change their presentation and even present new slices and summations of the data with no change to any models and little change to its controller.

Decoupling the model allows all kinds of changes to be made without touching controllers or views. It is nearly trivial to maintain backward compatibility when changing a file format: make two models, one for each version. It is much easier to add or remove information from a decoupled model. Placing all model related code inside a well defined module also makes it easy to make powerful changes to its performance. For example, it becomes much easier to add indexes for accelerating queries.

Sometimes it is impossible to make changes in a monolithic system that are trivial in a well modularized MVC system. Decoupling can make the impossible possible. Changes which were previously difficult can become easy, and programmer productivity typically skyrockets. The bottom line is model, view and controller modules can evolve much faster independently than they can as a monolithic whole.

An Alternative Description

Many great people have contributed to MVC over the past 30+ years. Apple has been a strong proponent of MVC design since 2002 with the introduction of OSX. The modern Macintosh operating system is based strongly on Objective-C which in turn is a marriage of C and SmallTalk. Since MVC was the "SmallTalk way", it's only natural for OSX to follow. Apple has a nice description of MVC:

The Model-View-Controller design pattern (MVC) is quite old. Variations of it have been around at least since the early days of Smalltalk. It is a high-level pattern in that it concerns itself with the global architecture of an application and classifies objects according to the general roles they play in an application. It is also a compound pattern in that it comprises several, more elemental patterns.

Object-oriented programs benefit in several ways by adapting the MVC design pattern for their designs. Many objects in these programs tend to be more reusable and their interfaces tend to be better defined. The programs overall are more adaptable to changing requirements - in other words, they are more easily extensible than programs that are not based on MVC.

Objective-C & Cocoa Documentation

The Essence of MVC

The question is not if you should modularize your system but how. Model-View-Controller is an excellent first pass. If you are programming in an object-oriented language you almost certainly should be using it.

The gospel of MVC as I've come to understand it comes down to three carefully chosen definitions with three key benefits:

Definitions of MVC

MVC is a modularization pattern that classifies all modules in the system into three roles:

  • Model: consistently store, query and alter the important data
  • View: communicate model data and user interface to human or computer clients
  • Controller: receive, interpret, validate, act on and respond to client inputs or other events

Benefits of MVC

  • MVC allows data-engineers, UX designers and system experts to focus on what they do best.
  • MVC is an excellent way to compartmentalize complexity and isolate mental modes.
  • The model, view and controller can evolve much faster independently than they could as a monolithic whole.

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License. Copyright (c) Shane Brinkman-Davis, December 2012

8 comments:

  1. Awesome post, Shane - very clear, and enjoyable! A must-read for developers of all bents.

    ReplyDelete
  2. Great content, but the blog theme is downright mobile-hostile.

    ReplyDelete
  3. Thanks Dave :). It's a standard Blogspot theme. Works well on iPhone, but terrible on iPad. Thanks for the feedback. What device are you viewing on?

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. This is the best article I've found that clearly defines and explains the flow of control that each component takes care of.

    There are a couple of questions that I have for you, to see if you can clearly define them.

    If the view is taking care of implementing GUI widgets, how are interactive buttons defined within the controller? From my limited understanding right now, I am convinced that you create a model class, then you create a view class, then you instantiate both of those classes into a controller, that will create the connections between both the model and the view, each not knowing about the other. Am I correct in believing that?

    Also, if all that is true, then I have another question, there is a common belief that the observable/observer design pattern should be used to complement the MVC design pattern. If the Model represents the observable and the view represents the observer, then the model updates (notifies) the view of its changes. Within your (really awesome) diagram, how would you explain this to someone that sees this diagram, which says that, the view and model never interact?

    ReplyDelete
  6. After spending much longer than I care to admit, I figured out a few things that answered some of my questions.

    It seems as though there are two popular implementation methods within the MVC design pattern. The kind you described (my favourite of the two) and another one where the design is more circular. The user interacts with the controller, controller updates/manipulates the model, model updates the view, view is refreshed for the user. In this case, the model is aware of the view and can implement the Observable/Observer design pattern. This design pattern is considered to be synchronous and the communication between the objects is done directly through calls to the other object’s methods.

    However, in the diagram that explains the implementation method you describe, where the model and view are unaware of each other, asynchronous communication is needed. In this case, the pub/sub (Publisher/Subscriber) design pattern can be implemented. Instead of calling an object’s methods, it uses message queues that keep the sender and recipient unaware.

    I am nowhere near understanding all this like I want to yet, but I wanted to give answers to some of my questions, in case anyone else was looking for answers to the questions I asked.

    ReplyDelete
  7. Developers are easily learn many new things from your article. Moreover, we specialize in <a href="https://allmountainlimo.com/airport-transport-services-in-vail-co/>Airport transportation Services in Vail CO</a> from individuals to larger groups with amenity and ease.

    ReplyDelete

Note: Only a member of this blog may post a comment.