Complex application code written without MV* patterns is hard to test, reuse, and maintain. Patterns eliminate or weaken the connection between View, Model and Controller, separate code and simplify development. We will cover the types of MV* patterns and their use in SimpleOne.
When developing a SimpleOne application, we carefully design the user interface (UI) and design the user experience (UX) to make it easy and convenient for our customers to use the platform. But the UI is only the tip of the iceberg as seen by the user (User). Behind the buttons and fields lies code that must be scalable, maintainable, and reliable. To solve these problems, developers apply MV*-patterns, which are used to separate UI code, logic and data processing.
UI without patterns
Let’s imagine an application that has a form with various elements and widgets. The code of this form contains both the description of logic and code of UI elements, and it may also contain fragments for data processing. For a simple application, supporting this programming principle is not a problem. At any moment you can find interrelationships and make changes without breaking the integrity. When the application becomes more complex, supporting an interface written without patterns becomes a problem.
The problem comes from violating the single responsibility principle (single responsibility principle) – “A class should have only one reason to change”. We have both UI code (View), logic (Controller), and data processing (Model) collected in an interface, so there are multiple reasons to change. When we change the code of one component, we have to change other components as well. This complicates the application support, it is almost impossible to perform automated testing, and code reuse is very limited.
That’s why it’s convenient and correct to use patterns – they separate UI code (View), logic code (Presenter, Controller, ViewModel and others) and data processing code (Model). We can easily change the logic without changing the UI, or make changes only to the data processing routines. Each pattern can be tested independently of the others and further used in other applications.
The most commonly used patterns are Model-View-Controller, Model-View-Presenter, and Model-View-View-Model. Let’s take a look at how they differ and where they apply.
Model and View
All three patterns under consideration have two recurring components. They differ in features, but are the same in essence.
View is a visual interface (UI). It can consist of either individual elements or widgets. Examples of View are form creation code in MFC and WinForms, html in ASP.NET, XAML in WPF and Silverlight.
Model is the application data that is displayed using the interface and the process of retrieving and saving it.
Model-View-Controller
The oldest pattern, which was developed in 1979 for developing applications in Smalltalk. At that time there was no Windows graphical shell with its standard elements. The interface was rendered manually by code. However, even then the separation of display, logic and data code was a revolution in development.
In this pattern, we see three main elements:
- Model – application data with the logic to retrieve and save it. Most often the model operates with data from a database or the results of web services. The data is either immediately displayed on the screen, or adapted.
- View – visual interface, rendering buttons, labels, input fields and other form elements. Can follow the Model and display data from it.
- Controller – monitors user actions (keyboard buttons or mouse movements), decides what to do with them, and updates Model and View.
Let’s describe the principle of the MVC pattern as follows. Controller processes user actions – mouse clicks, keyboard presses or incoming http requests. Processed changes Controller passes to Model and draws on View (passive mode), or the model gets changes directly from View (active mode). The View’s main task is to render the data from the Model using the Controller.
Model-View-Presenter
The development of visual programming and widgets has abolished the rendering of individual View elements, so a separate Controller class is no longer needed. Elements themselves know what actions the user performs with them. But it is still necessary to separate the application logic from the data. Thus, the pattern was replaced by Presenter instead of Controller.
Compared to MVC, the Model function has not changed, View now handles user actions (using widgets, for example), and if this action changes something in the interface logic, it is passed to Presenter.
The main task of this pattern is to separate View from Controller in order to realize interchangeable Views and to be able to test them independently.
Presenter as a conductor is responsible for synchronized work of Model and View. If it receives a notification from View about a user action, it updates the model and synchronizes the changes with View. All communication takes place through the interface, which gives them separation.
MVC has two implementations: Passive View, where View knows nothing about the Model and the Presenter is responsible for getting information from the Model and updating the View, and Supervising Controller, where View knows about the Model and binds data to the display itself.
Model-View-View-ViewModel
The key difference between this pattern and others is the presence of databinding in WPF and Silverlight.
Here there is no direct communication between ViewModel and View, it is done through commands (binding) consisting of properties and methods. This is how you can bind any View and ViewModel, as long as you have the right properties. XAML binding also allows you to bind not only data but also actions to View. We define an object as a Model property and declaratively bind it to the corresponding property in the View. The output is a separate object that contains both data and behavior, independent of View. ViewModel is a combination of Model and Controller.
The main advantages of MVVM are easy interface design, independent testing and reduced code for View.
Optimization and performance
If we use MV*-patterns to separate View, Model and Controller code, in highly loaded systems, an additional benefit can be gained by separating these elements into different computational units.
- View is brought to the client device (laptop, PC, smartphone). SPA single page application technology is responsible for acceleration. Complex calculations are performed on the user’s endpoint, thus reducing the load on backend servers.
- Controller (Presenter, ViewModel) are moved to a separate backend server that handles the logic.
- Model is the most voluminous and productive element, so it requires a server with a fast data storage system, and preferably with the ability to cache “hot” information in RAM.
MVC in SimpleOne
When developing ITSM-system SimpleOne, the Model-View-Controller pattern is taken as a basis, which is significantly optimized. The role of View is played by a single-page SPA application, which runs entirely on the client device and receives only data from Model. And for Model operation we use DDD approach (Domain-Driven Design) – we divide the pattern into layers-repositories through which data is accessed.
In traditional MVC, Model code is designed for a particular database and its syntax, for example PostgreSQL. Using the repository system, we can switch layers and connect any other database without changing the application code.
Layers allow us not only to work with repositories as connectors to the database, but also to split any classes into separate entities. For example, if in a usual MVC Model of the User class contains several thousand lines of code and is responsible for all operations related to the user (search, deletion, sending messages and others), in SimpleOne we split it into several separate layers: the class of user description, the user repository for working with the database, classes of various services related to the user, and others. We get an MVC framework, but more deeply developed, allowing for swapping, much faster query execution and more maintainable.
Conclusion
Patterns are not rigid paradigms that must be followed to create a perfect code organization. They solve very important problems – weakening (eliminating) the links between View, Model and Controller and reducing the complexity of user interface development. The realization of this approach is possible if you understand the essence of interconnections and look for the possibility of their elimination in each particular project. The ESM system SimpleOne is a complex and development-heavy platform, yet it provides a user-friendly interface and can handle heavy loads. This efficiency is the result of using modern technologies and development methods, including the use of MV*-patterns.