MVVM – Lessons Learned from the Trenches
There is considerable discussion on the use of the MVVM (Model View View-Model) pattern within the Roche as well as the industry in general. This pattern is a derivative of the MVC (Model View Controller) pattern that evolved out of the Smalltalk development circles. Basically the patterns divides the data, control and display along simple boundaries separating out each concern in a simple and testable fashion. Over the years this family of models, MVC, MVP (Model View Presenter) and MVVM has become more and more influential in the design of modern applications especially in the Microsoft .Net world.
Although this document does not concern itself with a lengthy discussion of the MVC family it is recommended that the reader invests some time in researching the current literature available on this subject.
The main topics of this discussion are:
- A short discussion and appraisal of the current level of guidance available for MVVM within the industry.
- A review of the current development based on the MVVM pattern indicating issues with the current MVVM understanding. This section will draw attention to the numerous “code smells” and implementation difficulties based on the above topic.
- A proposal for removing these “smells” and concerns and hence building a more robust and maintainable MVVM application.
Current Level of Guidance
Cardinality within MVVM
The basic MVVM model is one such that all three of the components, Model, View and View-Model appear within any implementation. Central to this is the definition of the cardinality between each of these components. Currently, it is being communicated that the View-Model controls precisely one View and precisely one Model. While the latter is completely understandable the former does not truly portray the View-Model’s full responsibility in such that there are cases where more than one View is being maintained by the View-Model at any one time.
The current documentation available within the industry does not consider this multiple-View scenario hence is a needless limitation of the choices that are available for the architect and developer. Examples of this limitation will be shown when discussing and reviewing the current MVVM development.
Where did the Model go?
A more worrying concern in the current guidance is the complete lack of any real Model within the examples within the current literature. As most applications are confronted with varying degrees of data complexity when dealing with modelling data for a business purpose it can be reasonable to think of data being aggregated from many differing data sources both from heterogeneous sources as well as within a source itself. For example, a user may be required to enter details for a new customer. The data for certain selection entry fields may come from differing sources as well as semi-static data within the main application model. More specifically Combo boxes can draw on data risk levels, previous convictions, credit worthiness and so on. It is therefore incorrect to assume that a simplistic view of customers being a simple list of names, addresses and email accounts hence trivializing the role the Model plays in providing the correct information for the application. Hence the current guidance does not fully define or display the significance of the role of the Model. Moreover, the current guidance relegates the Model to list within the View-Model and hence only effectively indicating a View View-Model pattern.
The guidance and infrastructure provided for the MVVM fails to indicate the complexity of navigation within an application by trivializing the Master-Details relationship. Within the current navigation concept navigation is achieved using both the View and the View-Model. This is dangerous on two accounts; firstly it blurs the responsibility that the View-Model plays in controlling the MVVM. A “pure” MVC will prioritize the building of the Controller in preference to the other members of the pattern. This is also the same in MVVM. Hence navigation should only be achieved using (an instance of) the View-Model. The second and most irritating danger is that the Master (and hence its Model) become the holding area for lists of Detail MVVM instances. Why? Well because the navigation requires a View-Model to function and hence the list’s selected item can also be a Detail View-Model. Although this seems trivial and also that the current literature includes plentiful example of this practice, this has serious repercussions in a complex real-world application. Examples of this problem will be shown as we explore the current shortcomings of the MVVM literature.
The Simplistic Application
While addressing some of the above concerns, most current applications fall into the trap of blindly implementing business functionality based on simplistic MVVM examples and guidance. The modern MVVM application appreciates the roles of the various components within the MVVM by separating each logical component into a project that specifically deals the concerns of that component. Hence an application can implement Models, Views and View-Models as separate projects within a solution.
Considering the Cardinality
Regarding the cardinality within the MVVM and the belief of a 1-to-1-to-1 cardinality it is now expected that every situation where relationship between data exists, this relationship materializes as a Master-Detail form and hence each detail is now implemented as a separate MVVM. A situation arises where, for example, master MVVM allows the drill-down to details based on selecting a graphic (data poor) in a list and then to a callout containing data that would normally be displayed as a row in some kind of grid or list. Using current thought to implement this situation the callout would be displayed as a further details MVVM. However in case that the resulting callout is deemed as being a view displaying more detailed information about the current selection an additional view is needed and hence the cardinality here is a 2-to-1-to-1 relationship between View, View-Model and Model.
Comparing these two differing realizations we see that former results in excess constructing of “viewless” MVVM and associated data access from the Model. The latter however collects all details within the Model associated with the View-Model and the uses differing Views to display the resulting data as required. This results in a single data access. On comparison we have saved one View-Model and one Model and have gained one View. This not only a reduction in the number of “parts” but also a reduction in the complexity of concerns as well as data access times involved. The resulting a 2-to-1-to-1 relationship is not only simpler but also a valid way of implementing the MVVM pattern effectively. The following diagram shows the basic MVVM pattern as implemented currently within most example applications
Considering the Model
The Model performs arguably the most important role within the MVVM as it consolidates and aggregates data access as well as providing validation and consistency check of its view of the data domain. To this end the Model employs the services of a repository to provide actual data access via WCF services for example. The data required for the user to undertake processes, make decisions, select options, and hence provide information back into the system all pass through the Model. For example the model contains:
- Input data resulting from user interaction.
- List or grid data occurring from data access that allow decision making.
- Selection information based on semi-static data such as options available within combo boxes and the like.
- Consistency checking and validation required before updates can be made returned to the data storage.
- Lengthy processing that requires to be coordinated via threads or similar.
Detail View-Model as data
Using the Detail View-Model as a data source in the Master’s Model is the biggest problem area that currently exists within the current industry MVVM literature. As mentioned above, this problem arises from the many examples that actively propose this situation. The concern here is twofold; the automatic generation of the Model and the View(s) from the View-Model via Unity DI or similar. Secondly, the separation of concerns problem that arises from having the Detail View-Model playing (at least) two roles – a View-Model and a data element.
WPF and Silverlight have opened new possibilities for both the designer and developer of modern applications. However, the difficulties that were overcome in previous technologies have risen once again and appear within the examples of MVVM. The problem here is that the Detail View-Model has multiple concerns or roles due to a complete misunderstanding of the role of Model within the system. Where once Data Transfer Objects (DTO) and Business Object (BO) were central to the data flow within the system, we now have the situation where the View-Model incorrectly performs this task. This is unacceptable. An example of the difficulties that arise from this situation can be easily shown:
- The implicit building of the Detail View-Model results in the building of the associated Model at least. As the Model requires data to fulfil its responsibilities data access takes place.
- As the Master will normally display a number of options within a list or data grid the above process will be executed a significant number of times resulting in a performance hit in the first line.
- As the user will only select a single or few items from these lists there is no good reason for building complex MVVM instances when the most will not be used.
- During failure within the building of these Details View-Models the situation arises that each MVVM reports the same exception multiplied by the number of entries within the list. The resulting error information is unnecessarily duplicated and, when these exceptions result in user interaction then the user is confronted with multiple messages on the screen.
This is detailed in the following Sequence Diagram:
Reassessing this situation leads to the following improvement points:
- Introduction within the Master Model of object (DTO or BO) data access required for each list. This would reduce the possible exception conditions to minimal reporting.
- Building this light-weight object (DTO or BO) supports the separation of concerns principle leading to more understandable code. The question of whether the object is a BO or DTO depends of any associated functionality that the object needs to provide. Generally speaking a BO is preferred to a DTO.
- The building of light-weight objects improves application response as well as simplifying the selection process. Consequently, the selected object will be provided as a parameter for the resulting Detail MVVM.
In conclusion, the trivialization of the role of the Model within the MVVM leads the developer to make incorrect decisions as to what objects to employ where, especially within the Master-Details pattern. Moreover, the Model is not correctly analyzed as to its concerns and roles and hence can be reduced to an object or a collection residing within the View-Model as can be seen in the current literature.
Considering the Navigation
It is recognized that the current navigation concept is being reviewed and may not bear any resemblance in the future to its current implementation. However, this discussion is based on the current navigation concept.
Navigation Given a View and a View-Model
Following on from the points made above over the use of the Details View-Model as a data source in the Master Model a compounding of the above problems arises – based on the selected item of a list or grid navigation occurs. This is not a problem in itself, however since the navigation requires a View-Model the tendency is to use Detail View-Models as the selected item occurs.
A further question arises in the navigation concept regarding the use of a Detail View as well as a Detail View-Model when performing navigation. Augmented with the situation that the controlling role within the MVVM lies with the View-Model makes the requirement for an additional View difficult to understand. More natural would be that the View-Model decides which View would be displayed. However, the current situation where the View takes the master role when building an MVVM requires both parameters to be present, e.g. the View receives the View-Model injected into its constructor. Consequently, within the example applications the MVVM is being used in an unnatural constellation thus leading to difficulties in its deployment and integration.
In conclusion, it has been shown that the current guidance is lacking when discussing how to correctly implement the MVVM revealing flaws in the correct interpretation of the basic MVC/MVVM pattern with respect to the cardinality between the component parts of the MVVM. Additionally the trivializing of the role the Model plays as well as the dubious use of a list of View-Models as a data source to support navigation also indicates areas where more realistic industry guidance is necessary. Furthermore, the lessons learned from previous application design with respect to DTOs and BOs for the transporting of data within the process and between layers need to be relearned for the current generation of MVVM advocates and developers.