Welcome to the second part of my write-up about the MVC Pattern Language! In case you missed the first part, this two-part piece targets popular misconceptions about MVC and tries to shed some “new” light on the topic by analyzing an oldish Trygve Reenskaug’s paper. This part covers patterns 6.-11.
6. Model/Editor Separation
As we said in the previous post, a user wants to interact directly with his mental model and he does that using business objects. This calls for presentation logic inside the business objects that would allow the user to interact directly with each of them. Those objects can grow very complex without that extra logic and, if you consider different GUIs for different users, mixing the two could make things unmaintainable.
Therefore, we can split the business objects into two parts: model and editor. The model holds information and behavior, while the editor handles presentation and user input.
We’re still mainly concerned by aligning with the user’s mental model and those can vary from user to user. Therefore, it would be nice if this task was aided by a modeling language and/or (semi-)automatic tool generation.
7. Input/Output Separation
The editor object mentioned in the previous pattern combines both presentation and input handling logic. In most non-trivial examples, combining the two responsibilities together is way too much complexity for little-to-none common code between the two.
Therefore, we can split the editor into two objects – view which would be responsible only for presentation, and controller which would be responsible only for handling user input.
As you probably noticed, I’m using words like “can” and “would” all around. This is because the separations I’m describing are not mandatory and sometimes even counter-productive. Sometimes, the roles of model, view, and controller can all be played by a single object as well as they could be played by three different objects. You need to analyze each case carefully considering both code complexity and aligning with the user’s mental model.
8. Tools for Tasks
Merely presenting a single object using an editor is not enough. To do his job properly, the user has to perform tasks which can span across multiple editors.
To support that, we distinguish a tool role, responsible for coordinating different editors in a way that supports user’s tasks.
Similarly to above, the tool/editor separation is also optional (needless) in simple cases. Of course, when talking about editors, we mean them either as a single object or as a view-controller pair.
9. Tool as a Composite
This pattern groups together several of the patterns mentioned before to answer a general problem: A user wants to interact with a with a complex model consisting of multiple interconnected objects.
To enable this, we structure the GUI into the following parts:
- The User with his goals and tasks
- The Model responsible for representing the user’s mental model
- The Editors that display and, if necessary, allow editing relevant information
- The Tool that coordinates the editors
This is the original MVC pattern as presented in the late 70s. If you were to remember one thing from this longish two-part post, remember this pattern with the exact descriptions of each of the parts. In particular, remember that it was the User mentioned as the first thing in MVC and that the model part should correspond to the user’s mental model.
10. Synchronize Selection
If a user selects an object in one of the views, the others should reflect it as well to maintain an illusion of interacting directly with the object model.
To achieve that, we make the tool object responsible for synchronizing the selection between all underlying views.
In case the controller plays the role of the tool, it will be the one to do the synchronization. If we allow for multi-selection, the implementation of this mechanism can get significantly complex.
11. Synchronize Model and View
The underlying model can change, while being presented by a view object, either due to user’s commands or some external party changing it. The view has to reflect this change to the user.
Therefore, we make the view observe the underlying model as in the GOF observer pattern.
It’s important to make sure that the changes don’t occur too often and don’t negatively affect the user’s experience e.g. via constant re-rendering of the whole GUI. Use of transactions can help us achieve the former. The second is rarely a problem when using modern GUI tools.
Summary of Part 2 and Final Words
In this part, we went through the lower-level patterns that make our GUI code more manageable and the user experience more pleasant. If you were familiar with MVC before, you most likely knew the patterns presented here. What, I suppose, most have not known is that we’re doing all these for the best possible user experience. We’re constantly trying to bridge the gap between the user and his mental model. It’s not some nerdy, class-separation, cool framework tricks. It’s all about the user.
Congratulations! You’re an MVC adept now and you now much more about creating habitable GUIs for your users. I hope that from now on, whenever you think MVC two words will come to your mind: mental models. If you’re looking for some next steps, I strongly recommend reading the MVC stuff on Trygve Reenskaug’s page. And don’t forget to share all this stuff with others! MVC is like a good TED talk – it contains an idea worth spreading!