Monday, May 12, 2014

Really, it's Controller-Model-View!

We have all had our moments when folks are talking about some idea and treat it as such an obvious thing that we are too embarrassed to say that we do not know about it! Well, model-view-controller or MVC as it is called is one of those things that pops up in application development that we think everyone understands. Let's fix that here!

MVC is what we call an "architectural pattern." It is a pattern of design that supports the separation of concerns where we modularize an application and isolate different responsibilities into different components. To put it simply, if you separate the code that formats and presents information to the user (the view) from the code that implements the business rules (the model) then it should be easy to make changes to either module without having a drastic effect on the other.

This does not mean that the modules are truly "black boxes." In fact, most of the time when we design the view we have a pretty good idea of what the business rules are, because they impact how we present the information. The key is that one module does not step on another module's responsibilities. And sometimes that line is blurred a little: for example the view may put business-rule constraints on data entry fields to present to the user, but only because it avoids having to do a round-trip to the model to perform validation. But it is an illusion; while the view does keep the user in line the actual validation of the data still remains in the model. And of course changing one module will have an effect on the other. The best that we can do is to reduce the dependency, we cannot eliminate it all together.

I said in the title that it is the "controller-model-view" pattern because that is the cycle that takes place:

Applications have a flow, and decisions must be made to determine after an action what the user will see next. Controllers were introduced in "model-view" to isolate those routing decisions from the model, again the bit about the separation of concerns. When a controller is present the model contains just the data that supports the application. Now, other than validating the data before it accepts it the model does not have any other responsibilities.

The user initiates the cycle with an action in step one, and may provide some data that needs to be worked on. The controller will act on that request. It decides if data needs to be updated in the model in step two, and then it decides what the user will see next (the view). Along with selecting the view in step three, it usually passes along the model data the view needs to present. The view does have the option of retrieving model data itself in step 3a but we try to avoid that if possible. The controller should make all those decisions. When the view has formatted the data for display it presents it to the user in step four, and then the cycle starts all over again.

So now the data is in the model, and most of the business rules are in the controller. But that means the controller has two responsibilities: making decisions on what happens next, and implementing the business logic of the application. That violates Bob Martin's single responsibility principle, the first and most important fundamental design principle! Single responsibility is really about organization: when everything is organized and related stuff is kept together then the reliability of the application improves, it is more adaptable when changes have to be made, and more maintainable when bugs have to be isolated and repaired. And that is my own RAM principle, although I'm sure that I wasn't the first to discover it.

Well, to solve that problem we can take a page from the Grails framework and once again separate the responsibilities: the decisions of application flow remain in the controllers, and the business rules move into services.

The diagram still shows the controller communicating with the model, which is important because now there are two interactions with the model. The controller delegates to the service the manipulation and updating of the data. But the controller still needs to select the view, and the model data it retrieves to give to the view is separate from the service. In fact, the model data for the view could be completely different from the data the service was responsible for.

Controller-model-view just doesn't roll off the tongue as nicely as model-view-controller, so I guess we're stuck with that :) But the pattern is really is not that complicated which is why everyone assumes that everyone else understands it. Unfortunately when you are guessing you could get it wrong. I certainly had my own early misconceptions about what it meant!

An Important Note

If you have studied MVC before and before you complain, I purposely left out one component from the original description of MVC: the integration of the observer design pattern into the MVC architectural pattern. It is intentional because I believe MVC should focus on the separation of concerns and not on how we choose to update views.

In the first paper published on MVC the statement is made that "Views and controllers of a model are registered in a list as dependents of the model, to be informed whenever some aspect of the model is changed" (Krasner). This is clearly an implementation of the observer design pattern, years before the pattern was identified.

The problem is that the observer pattern untenable in many circumstances, most importantly when a distributed application uses HTTP to link the presentation to the model. HTTP will not leave a link open for a notification message to be sent to the remote view. And we move to a connected link such as web-sockets then the server will soon exhaust its pool of network connections. The usual solution with HTTP is to poll the server to see if the model has changed.

This became a real problem in 1994 when CGI became the first component for building server-side applications, and it is for this reason that we are exactly twenty years past due to separate the observer component from MVC and focus instead on the benefits of the separation of concerns.


See the references page.

No comments:

Post a Comment