Studying the development plans for CMS Joomla, to write one of my
previous articles (in Ukrainian), I came across the abbreviation HMVC. It was not difficult to understand that this is somehow connected with the MVC pattern that has become the standard. The found decoding: “HMVC - hierarchical model-view-controller” - did not explain much. Further searches for information also gave not much, mostly theoretical discourse on the pattern and almost nothing about how to use it in practice. However, after a little reflection, I realized that I had already used it in my previous project on Symfony 2. Moreover, it turns out that very many people use this pattern partially without even realizing it.
MVC problems
Looking ideal in theory, MVC in practice faces a number of problems. To begin, let us recall what the main problem it has to resolve: by dividing the application into three different aspects (controller, view and model), to achieve a minimum dependence between them, as well as between different parts of the application. In the examples from the textbooks, this is all right. There is a model of something, a view for displaying data and a controller for performing actions in response to user actions.
Problem one
In practice, you usually have to operate on several models at the same time, for example: articles, users, comments. In principle, this is not critical, the MVC pattern provides for this, but it increases the number of dependencies — the view and controller depend on more than one model, and more than one type and controller depend on one model.
')
Problem two
To display data from different models I would like to use views created specifically for them. For example, it seems logical to display comments in the same way for articles and for products. Such a classic MVC does not provide, but it partially costs using templates. Those. One view is used that receives data from models, and a combination of several templates is used to display their display. And the number of dependencies increases again.
Problem three
Sometimes actions need to be performed not on one model, but on several at the same time. For example, when deleting a user, you should delete all his articles and comments. As a result, you have to create a controller that describes operations not only on the model to which it belongs (in the example, users), but on models to which it has no direct relation. Thus, there are no obvious dependencies.
HMVC main idea
How to eliminate these problems? Since problems arise from the fact that instead of MVC, something like MMMVVVCC is obtained, where each model and controller can belong to different subsystems, the answer is obvious - return to MVC in which there is only one model, type and controller.
So, the first principle of HMVC: the application uses only rigidly fixed model-view-controller triads, which interact with the rest of the subsystems exclusively through the controller.
From this comes the second principle: for the organization of more complex combinations, hierarchies of triads are used.
At first glance, it may seem that to be able to implement HMVC it ​​is enough to be able to call a controller from another controller. But in a web application, the behavior depends not just on the command sent to the controller, but on the http request as a whole. Both the model and the view can themselves analyze the request and in some way change their behavior. Therefore, it requires the ability to transfer the request to another controller, and not necessarily the same one that was received. This can be done in three different ways.
Client / Server HMVC
The easiest way to send an http request is to use a browser for this. In this case, it does not even require any special support by the framework. And this approach is used everywhere - called AJAX. Yes, yes, that ajax. We can use one basic model-view-controller triad to display the main content of the page (for example, the text of the article), which other necessary fragments (for example, comments) will receive using ajax-requests for the same triads.
This approach allows for some parts of the page to use http-caching (caching data in the browser cache, proxy server or proxying http-server) and partly load in real-time mode. For example, an article page can be downloaded in parts as follows:
- the page with the text of the article is static and, if possible, is retrieved from the browser's cache, which can be stored for quite some time;
- comments are constantly updated and therefore not cached and each time requested from the web server;
- The latest news block is updated from time to time, it can be retrieved from the cache, but not stored in it for as long as the article.
Pros:
- support is not needed by the framework (you can do without it at all);
- flexible http caching;
- the ability to send a request to another web server, thus distributing the load among several servers.
Minuses:
- need to write java-scripts;
- The number of requests from the browser to the server increases, which may increase the page load time and load on the web server.
Server-server HMVC
The next simplest implementation is to send a web server request to yourself. For this, curl can be used, or another library capable of sending http requests. This approach is similar to the previous one, but with the difference that the requests are sent not by the user's browser, but by the web server itself in the process of generating the document.
As an example, consider an article with comments again. The basis of the page is an article, so the controller, type and model of the article are used to display it. But if the classic MVC is used to refer to the model and the type of comments to display comments within the article view, then HTMV provides for sending a request to the controller for comments. In this case, by means of an http request, which initiates the launch of a parallel process, which will produce a ready block of comments for the article.
As in the previous case, with this approach it is possible to use http-caching, but to use it you must use a proxy http-server, for example, nginx.
Pros:
- the finished page is given to the client;
- flexible http caching;
- the ability to send a request to another web server, thus distributing the load among several servers.
Minuses:
- For the formation of one page, several parallel processes are launched, which increases the load on the web server.
In-server HMVC
By the term “intra-server”, I mean that everything happens inside the web application process. As in the previous case, the model-view-controller triads communicate with each other through requests, and they should be perceived by them just like regular http requests, but the framework provides for the transfer of these requests. From the point of view of the programmer, the last two options are not significantly different. In a good framework, the difference should be only in one parameter, which indicates whether the subquery should be internal (within the process), or external (call this http-request).
Pros:
- There is no need to run an instance of the web application in parallel.
Minuses:
- There is no possibility to use http-caching.
HMVC application scaling
If a web resource becomes quite popular, it may be a question that one server is not enough for it. And then the question arises about the distribution of the load between multiple servers. The easiest way to quickly distribute the load is to use multiple copies of the resource and database replication. But HMVC allows you to go another way - to distribute tasks between servers. For example, one server manages articles, one user profile, and a third commentary. In the case of sufficient isolation of the modules, for quick implementation, it is enough to register in the corresponding requests that they are external, and specify the addresses of the servers for their processing.
At last
Creating a real web application is not necessarily limited to any one of the options for implementing HMVC. In each case, you can choose the one that is best suited for him. And the options "server-server" and "intra-server" in general can be switched on the go.