Skip to main content

My Understanding of Frontend MV*

Free2015-08-26#Mind#Design_Pattern#Front-End#MVC图解#MVP图解#MVVM图解#MV*#前端MV*#前端MVVM#前端MVC

There are many articles about MV*, but it's not easy to figure out who is right and who is wrong. This article explains in detail my understanding of MV* after reading many blog posts.

Preface

My first contact with MVC was in Java, not big frameworks like SSH, just simple layered development to make the code structure clearer.

  • V (View) in Java can be GUI made with SWT, Swing, of course, it can also be pages generated by JSP.

    View is a pure interface, responsible for displaying data to users in a friendly form.

  • M (Model) can be a pure Java Bean (dumb bean, only custom data structures and getters/setters), or it can have some data validation logic.

    There are also those who put data validation logic in V or C, depending on the specific scenario. For example, in JSP applications, putting data validation logic in V is more appropriate, which can reduce requests.

  • C (Controller) is a layer where business logic is aggregated; all important business logic is in C.

    C is responsible for receiving user input passed from V, and after processing, updates M, then M notifies V to update. One V can correspond to (depend on) one C, or multiple V's can correspond to one C (if the business logic of multiple pages is basically the same), but one V should not correspond to multiple C's, because this dependency relationship is tight coupling. The correspondence between M and V depends on the implementation method, whether it's the classic Observer pattern or Publish/Subscribe pattern. In the former, M directly notifies V to update; in the latter, M can only update V through C.

Later, I found that some logic doesn't fit anywhere, such as database operations (put in C?) and configuration data/constants (put in V?). So I added Core for constants and DAO layer for database operations; both are considered auxiliary layers of C.

The concepts of MVP and MVVM are different from this; it's not about adding or removing a layer, but rather redefining the responsibilities of layers. Of course, after redefinition, other auxiliary layers were also added.

I. MVC

From input to output, the data flow (reluctantly considered a data flow diagram; Ruan calls this a communication method diagram) is as follows:

[caption id="attachment_730" align="alignnone" width="889"]MVC 数据流 MVC 数据流 [/caption]

Note: This is not a dependency diagram. Because from a dependency perspective, M and V have an Observer pattern relationship; V should depend on M (Observer knows the existence of Subject and its public interfaces), and M does not depend on V (Subject doesn't know who is following it, nor does it care who they are). From an interaction perspective (data flow), M updates V (Subject changes, automatically notifies all Observers), and V has no way to directly update M.

Dependency relationships depend on specific implementations. Personally, I think there's no point in worrying about Trygve Reenskaug's original implementation, so a dependency diagram cannot be drawn. Moreover, years later, the data flow diagram above may also be wrong. From the original C receiving user input to now V can also receive it, who knows what changes will come in the future?

(Gossip: This is the disagreement between Winter and Ruan. In Ruan's view, MVC is broad, a kind of layered development philosophy; while Winter believes MVC is what it was in '79, and everything else cannot be counted as MVC... Both blog posts are listed in the references at the bottom; if interested, you can take a look.)

(Side note: In 1979, Trygve Reenskaug proposed MVC, which is said to be the authentic version. At that time, user input could only be obtained by C, and V's functionality was extremely weak; even the cursor on the input box was controlled by C and drawn by V. So it was stipulated that only one C could exist, and all logic must flow through C for easy control of cumbersome interface display. Now, user input can be directly obtained by V, and tasks like drawing cursors are automatically completed by the operating system. To still insist that only one C can exist is thoroughly stupid.)

Backbone.js

Backbone is a framework example of frontend MVC, providing MVC implementation and basic tools with great freedom. In practical applications, it needs to be combined with other tools; for example, Underscore and jQuery/Zepto are necessities.

Backbone is the spine, indicating it only provides the most critical framework implementation; the rest is very free. For more information about Backbone, please see the references at the bottom.

II. MVP

The original MVP diagram is as follows:

[caption id="attachment_731" align="alignnone" width="690"]mvp mvp[/caption]

Compared with MVC, the biggest difference is not that C was renamed to P (Presenter), nor the additional line from M to V. Wait, isn't it the Observer pattern? How can M directly access V now (Subject can directly access Observer)? We'll discuss this later. The most important difference is that P is not a single object, but the interactor, command, and selection in the diagram combined are called P. In other words, P doesn't exist; P was decomposed into "interactor, command, and selection".

Because in the original Observer relationship between M and V, V cannot directly access M and can only rely on C to pass, which is uncomfortable to use (possibly uncomfortable in terms of efficiency or usability). Then it was decided to enhance V, allowing V to directly access M (V being able to receive user input is also an enhancement, because in the original MVC, only C could receive user input; users were directly interacting with C, and cursors, input text, etc., were all controlled by C and displayed by V). Then C was renamed to P to distinguish from MVC. Actually, calling it M(Fat V)C would also work; V became thicker, so C became thinner (simple data display was handed over to V, directly getting M's data and displaying it (data binding with view?)). Of course, from the diagram above, we can see that V can only read M; writing still needs to go through C. So some people say P is a kind of C; more precisely, it's a thinner C.

MVP doesn't have a suitable example framework because there's controversy about everyone's understanding of MVP. Some articles say P is an enhanced V, others say P contains all presentation logic... So where does business logic go? We can't simply understand from the literal meaning of Presenter and explain presumptuously.

(MVP was proposed in 1996 because some people felt that the 1979 MVC was no longer appropriate. The MVC concept still exists, of course, but the original rigid rules, such as there being only one C and only C being able to obtain user input, are outdated. MVP itself may just be a transitional product; what's useful are the underlying concepts, such as layered development, modularization, event-driven, etc.)

III. MVVM

MVVM is a pattern proposed when Microsoft launched WPF. WPF's characteristic is powerful controls; for example, DataGrid can be directly bound to data tables, greatly reducing the workload of simple data table display. WPF's View is defined using XAML; basic control functions, such as input data validation, can be implemented through simple XAML configuration. This is actually MVVM's biggest feature: two-way binding between V and M.

The benefit of MVVM is further separation of V; even V is described in another language (XAML). This greatly enhances the reusability of controls; you can directly take the XAML code of custom controls from a previous project and use it without carefully extracting logic code from the original project.

The diagram given by Winter is as follows:

[caption id="attachment_732" align="alignnone" width="690"]mvvm mvvm[/caption]

That is to say, V in MVVM is a very powerful, very complete, very thick V, because this V = V + C + E. As for data binding, from a usage perspective, it's V and M that are bound. For example, the value of TextBox will automatically synchronize with Model data. From the diagram above, it's data binding between V and VM; VM can manipulate V through "commands", such as xx.close() and so on. A more detailed explanation is as follows:

How to present is View's business; the caller only needs to give View a piece of data. View is only responsible for displaying this data; the caller doesn't need to worry about how View displays it, only responsible for passing the data. View doesn't need to worry about where the data comes from; it just needs to present the data in its own way and always pay attention to how changes in data are reflected on View.

And two-way binding is an additional product. After all, there aren't many UIs like TextBox, Form, etc., that change data; most UIs just present data in one direction. However, with two-way binding, View and the caller can be separated more thoroughly. That is, obtaining data doesn't need to care about special Views; whether a date is entered by the user in a TextBox or selected with a Calendar doesn't matter, because that's View design and arrangement business.

Angular.js

Angular's MVVM is almost universally recognized. MVVM's characteristic is heaviness; WPF is easy to use because it provides a complete set of powerful common controls, as you can imagine.

For more information about Angular, please see Angular Official Website. Angular is made by Google; perhaps it's the development direction of MVC.

IV. Selection of MV* Frameworks

It is not recommended to directly use business library frameworks, and it is even less recommended to use overly heavy business frameworks. It is best to understand the problems the framework wants to solve and the actual needs of your own project, and build your own wheel with full understanding.

(Quoted from Discussion on Best Practices for Mobile Frontend)

This statement should be very reasonable. A friend from a startup company said the company requires using Angular, without research, without discussion, just must use it. Why? Because it's hot. Whether it's suitable or easy to use doesn't matter.

Of course, your own internal framework should be tailored. If there's a problem, someone will solve it; you don't need to search for solutions. If it's not easy to use, you can modify it yourself; if modified well, it can be directly extended. If it's too large, you can clean it up and extract unused parts as optional modules... Your own will definitely be more comfortable to use than others'; change wherever you're unhappy. For example, with the $() problem, you should choose carefully according to business scenarios, see if document.querySelector can meet the needs. If not, then see if Zepto's compatibility is enough; only if really necessary should you use jQuery.

V. Why Understand MV*

What's worse is that countless interpreted MVC implementations today (such as Backbone) and popular science articles either have authors with very confused concepts mixed with personal opinions, or they modified some concepts and coupling relationships in classic MVC to adapt to modern markup languages and control patterns. Actually, today MVC can no longer serve as a standard vocabulary for communication.

Spending time understanding MV* is to be able to understand what others are talking about. But as mentioned above, MVC is no longer a standard vocabulary that peers can instantly understand. Right or wrong may not be important; if you must worry about it, you need to read N papers to find the original implementation concept of MV*. But there's no need to do this because Winter has done it for us. The original implementation is a reference point; you can compare and understand when contacting other MV* implementations, but don't worry about right or wrong; as long as it's useful and practical, that's fine.

References

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment