Tuesday, 16 September 2014

Brief overview of the MVC pattern

Model-View-Controller is a programming design pattern which was created to solve the design problem of a rather frequent application: Displaying data to the user (and possibly handling input from the user).
http://warp.povusers.org/programming/images/mvc1.pngThe basic idea of this pattern is to divide the program (or module) into three main modules: The Model, the View and theController. In its purest form, the MVC pattern works like this:
1.     The Model is, simply put, the module which handles the data of the program. It could be, for example, a module which interacts with a database. In its simplest form it could simply be some kind of data container (such as a list), depending on the application.
The Model module has no functionality on its own other than as an interface between the data and the rest of the program. It handles the data only to the extent that is needed for it to be stored and restored but otherwise doesn't make any decisions about what to do with the data.
2.     The View is the module whose task is to display data to the user. It does not have any functionality in itself, other than what is needed to transform and lay out the data as needed by the display format. In other words, the View acts as an interface between the display (which can be a physical display or eg. a document format) and the rest of the program, and doesn't have any functionality related to anything else than displaying the data.
3.     The Controller is the core module which makes all the decisions. It has all the relevant functionality of the program and interacts with the Model and the View, commanding them and passing data between them as needed.
http://warp.povusers.org/programming/images/mvc2.pngThere are two schools of thought with regard to whether the View interacts directly with the Model or not. In one school of thought the View and the Model are completely separate and have no connection whatsoever. All the data between the two is handled by the Controller. In the other school of thought the Controller can command the View to retrieve data from the Model so that the data doesn't have to be transferred by the Controller. (This naturally creates a dependency between the View and the Model.) In other words, the functionality of the View is enhanced as much as is needed for it to interact with the Model in order to retrieve data (but otherwise the View has no functionality of its own.)
Case example
A perfect example of where the MVC pattern is useful is a web server:
1.     The Model is the module which interacts with the database (in the simplest designs this could be directly the library which is used to query the database using eg. SQL).
2.     The View is the module which generates HTML from the data.
3.     The Controller contains all the other functionality of the server (eg. it decides which page to display, generates dynamic content, handles session and cookie data, etc.)
One would hastily think: "Don't all web servers actually do exactly this (at least those which produce dynamic content)? Isn't this pattern rather ubiquitous?"
The answer is no: The critical element which distinguishes the MVC pattern from a non-MVC design is the separation between the View and the Controller. They must be completely separate and independent modules. If the Controller outputs HTML directly (which is extremely usual), then it breaks the MVC pattern because now there is no abstraction between the functionality of the Controller and the output that the program produces.
Or put in other words: The Controller must not know that the output is HTML. It must be completely agnostic to what format is being used as output. If it outputs HTML directly, this abstraction is broken and it's not the MVC pattern anylonger.
(The level of abstraction required between the Controller and the Model is debatable. One could argue that SQL is enough of an abstraction, as it doesn't fix the exact format of the database. Others might argue that SQL is not enough, as different database libraries use slightly different versions of SQL, and thus the exact query language should be hidden inside the Model module.)
One could just as well rename this special case as the "DDC" (Database-Document-Controller) pattern.
Motivation
Why go through the trouble of designing your program like this? This design pattern was not devised just for the sake of it. There are good ideas behind it (at least in theory).
The complete abstraction between the Controller and the View means, as mentioned earlier, that the Controller is completely unaware of the actual output format being used. This means that if we want to change the output format to something else, it becomes enormously easier: It's enough to create a new View for the new output format and make the Controller use that instead (the switch can even be done during the execution of the program if needed).
For example, suppose that besides the server returning the data in HTML format you would also want support for it to return the data in PDF format. It becomes as easy as writing a new View with the same interface as the old one, but which outputs the data in PDF format and make the Controller use that. (The layout of the PDF might need to be slightly different from the HTML, but this is what the View module is for.)
As you might imagine, in an optimal case, with a perfect design, this saves an enormous amount of work. If, however, the Controller had printed HTML directly, making this modification would have required a lot more work, if not even a complete redesign.
So now it becomes very easy to add all kinds of different output formats. For example, you might want to be able to output the data in plain text, or even as a Java or Flash application. Moreover, you could even be able to relatively easily port the application to a completely different environment and make it eg. a Windows application (in which case the View would then be a wrapper around the Windows API, QT or whatever).
Likewise the abstraction between the Controller and the Model means that the format in which the data is stored can be easily changed without having to modify the Controller or the View. If, for example, the Controller is directly reading and writing raw data to files, changing it to eg. use a database instead would be a lot more laborious than if an abstract Model had been used instead.
(And this also means that the same program could support many different data storage systems in the same way as it could support different View formats.)
The practice
So all that sounds really nice and fancy, but does it work in practice?
In web servers it might work like a charm. However, the MVC pattern is also being used in many other environments, not all of them being strictly an application for displaying and updating data in a database.
One prominent environment where the MVC pattern is being heavily promoted is the MacOS X and iPhone development environment. Apple uses and recommends using the MVC pattern in all programs created for those platforms. The Cocoa and Cocoa Touch libraries are designed around this pattern.
So, does the MVC pattern work for a graphical application like an iPhone program?
Regardless of what Apple claims, my answer is no. At least not in its purest form. Programs might follow something slightly resembling MVC, but in practice they will end up mixing especially the View and the Controller functionalities because trying to strictly enforce their separation is actually counterproductive. The end result is a program which does not really have the benefits of this separation (ie. those described earlier).
But that isn't necessarily a bad thing. It would be nice in theory if the Controller was so abstract that it could be used as-is in a completely different environment by only changing the View, but in practice this is basically never a necessity. You don't usually write an iPhone program which could output its data to the screen or to a HTML file. It just doesn't work like that. (If you really needed to generate HTML from some data, you would simply write a separate module for that purpose, which has nothing to do with your Views.)
As said, the major problem with trying to enforce a strict MVC design in an iPhone (and in general in any graphical) program is that it's very counter-productive.
The problem is that if you have a very complex view with a lot of elements and lot of functionality (which is typically the case with the main view of a program, eg. a game), if all the functionality is in the Controller (as demanded by strict MVC), your Controller class will start growing out of control and become extremely complex. This, rather ironically, produces a result which is against good object-oriented design principles: The Controller is tasked with way too much. Many of these tasks are things which would better be done by the "View" or the "Model" (so to speak) themselves in a good OO design.
Even if you try to split all the functionality inside the Controller into smaller modules in order to keep the module sizes manageable (and while still trying to impose a strict MVC pattern), you will often end up with needless complexity because now there will be a huge amount of interaction and dependencies between these modules and the View. This might even end up as a broken MVC design where you have several "subcontrollers" all interacting with the View and between themselves.
The fact is that it is often the case that if you move certain functionality from the Controller to the "View", the end result will be simpler, more intuitive and a consirably better OO design. Now the "View" will have a much more active role, will have more functionality of its own (functionality which should be in the Controller in a strict MVC design), but the Controller will now be more manageable and more focused on its own role, rather than trying to manage a million different things, most of which don't really concern it.
In other words, the level of abstraction will now be better, with a simpler class design. Rather than have the Controller take care of everything, the tasks will now be better distributed: Tasks related to the view are now in the "View" class, away from the Controller class. The Controller class can now focus on its own core functionalities.
The same goes, of course, with the "Model" module. Data handling routines can be moved from the Controller to the "Model", giving it a more active role, but at the same time making the Controller simpler and more focused.
Also the "View" can often interact directly with the "Model", completely bypassing the Controller (with tasks which should, once again, be in the Controller in a strict MVC design.)
Of course this is not the MVC pattern anymore (except perhaps in a very loose sense.) The theoretical benefits of that design pattern have been destroyed by doing this, so there's little benefit.
However, the fact remains that in an iPhone application there's extremely seldom any need for the abstraction offered by the MVC, and strictly adhering to it is, on the contrary, very counter-productive. Your Controller classes tend to become very large and complicated, ridden with with tons of functionality which doesn't really concern them, functionality which would be better delegated to the "View" and the "Model" themselves for a much cleaner object-oriented design.
Another problem is that a strict MVC design would require for each View to have its own Controller (although the Model can be shared among several controllers even in a pure MVC design, for practical reasons).
In practice, however, if you adhere to this in an application with dozens of (often similar) views, your class design will also become needlessly complex. In practice a simpler design is to have one Controller handling several (somehow related) views. For example, if you have a Controller which manages help screens, and there are many of such screens (eg. one help screen for each major feature in the program), it's much simpler to have one single Controller which manages all these help views rather than have one Controller for each. Such a Controller doesn't usually need to be very complicated even if it has to handle a half dozen of such views, and thus it makes no sense to create one Controller class for each view.
Thus in practice you end up having a kind of "Model - Multiple Views - Controller" design by necessity. (Although some would argue that this is an acceptable MVC design as it doesn't really break the MVC abstraction model.)
When programming for the iPhone you will probably end up with classes with the word "Controller" and "View" in them, but those will often be misnomers (except maybe with the simplest MVC triplets.)

The same is probably true for other GUI environments.

0 comments:

Post a Comment