christianalfoni - Why we are doing MVC and FLUX wrong

原文出处 christianalfoni - Why we are doing MVC and FLUX wrong

The MVC (Model View Controller) architecture is referenced in almost all Frontend frameworks. Angular, Ember, Backbone etc, but is it really MVC they are implementing? And is Flux really a different architecture? In this article I am not going to go all academic on you, I am going to tell you about why I think Frontend frameworks are not implementing MVC correctly, and that Flux is actually a lot closer to traditional MVC than any of the other frameworks, but still does not quite “get us there.” This is a bold statement, but please read on and I will explain.

I am not going to show any code in this article, but I am going to reason about why I think Cerebral is not only just a library and a development tool, but it fundamentally does not change the way we develop our apps as it goes back to the roots of MVC.

Traditional MVC

When I say “traditional MVC” I am talking about doing all the work on the server. The browser just receives strings of HTML and can do requests to the server by changing the url or posting a form. Lets visualize this:

 BROWSER             SERVER                    DATABASE
  |------|  request   |------------|  request   |-------|
  |      | ---------> |            | ---------> |       |
  | VIEW |  response  | CONTROLLER |  response  | MODEL |
  |      |  | USERMODEL | ---------> |       |
  | name  |            | name      |            |-------|
  | age   |            | age       |
  |-------|            |-----------|

So what we do here is update a client side model and then we pass that information to the server. The point here is that there is no controller handling the exchange of information from the view layer to the model layer, but if you would go to localhost:3000/#/items/123 suddenly the router would act as a controller, preparing the state and create a view to be displayed.

This creates complexity as we now have two ways of defining the flow of our application, it could either be through a router or directly with a model.

 |------|       |--------|      |-------|
| VIEW |  ---> | ROUTER |  | MODEL |
|------|       |--------|      |-------|
                   |               ^
|------|           |               |
| VIEW |   | ROUTER |  | MODEL |
|------|       |--------|      |-------|
                   |               ^
|------|           |               |
| VIEW |   | MODEL |
|      |       |-------|
|      |
|      |       |-------|
|      |  | MODEL |
|------|       |-------|

The second problem is that this model abstraction is for application state related to what is in the database on the server, not application state like; “Loading data from the server”, “Show the settings modal”, “Show tab 3”. This is not something you would store in a database. So where do we put that state?

State in the view layer

Everything not related to what is in the database we often put into to the view layer. There just is no other place to put it. This problem gets even worse as our view layer is no longer a single view, it is dozens of views composed together and each of these views has their own internal state unavailable to the other views. Scaling our applications becomes a big problem.

So to recap this. With traditional MVC we have one view layer, one controller layer and one model layer. We only keep state in the model layer and any changes to that state comes from the view layer and through the controller layer. On each state change/get a new view will be created. When this was moved to the Frontend the complexity increased with:

  1. Multiple views

  2. State also inside views

  3. Multiple models

  4. We bypass the view controller model flow

  5. The router is no longer the only entry point for state change

What FLUX improved

What FLUX helped us with was to introduce a controller layer for the client. This controller was called a dispatcher and any state change had to go through the dispatcher with a payload. This is exactly how traditional MVC works, all state changes has to go through the controller using a request with a payload. FLUX also introduced a new model layer called stores. The great thing about stores is that they are not a wrapper for database entities. It is just plain state for whatever you wanted, it being state from the server or state for the client only.

But FLUX has its issues. There are three challenges:

  1. The FLUX architecture uses multiple models (stores). With traditional MVC you only have one model, your database. Multiple stores quickly causes problems when a dispatch needs to reach more than one store and especially if one store needs to know about state in an other

  2. There is no concept of middleware like in a traditional controller. This quickly introduced the concept of action creators. They are much like a single middleware that is responsible for doing everything needed related to a request from the view layer, often doing multiple dispatches to the stores

  3. When the view layer wants to get some state they still do it directly from the model layer, making unnecessary complex dependencies in the views

Let us try to visualize this a bit:

Traditional MVC

 |------|  request   |------------|  request   |-------|
|      | ---------> |            | ---------> |       |
| VIEW |  response  |            |  response  |       |
|      |  |            | ---------> |       |
| VIEW |  response  |            |  response  |       |
|      |  |            | ---------> | MODEL |----
|      |            |            |            |       |   |
|------|            |            |            |-------|   |
                    | CONTROLLER |                        |
|------|            |            |            |-------|   |
|      |  request   |            |  request   |       |   |
| VIEW | ---------> |            | ---------> | MODEL |   |
|      |            |            |            |       |   |
|------|            |------------|            |-------|   |
   | |                                           |        |
   | |-------------------- |       |
| CONTROLLER |   get  | MODEL |
|            |  |            | -----> |       |
| VIEW |    event   | CONTROLLER |   get  | MODEL |
|      |  |            | -----> |       |
| ROUTER |    event   |            |   get  |       |
|        |  |            | -----> |       |
| VIEW |    event     |            |   get  |       |
|      | < - - - - -  |            | <----- |       |
|------|              |------------|        |-------|

So what benefits do I really get?

Developing applications is all about keeping a mental image. You can not understand a problem or create a solution without having a complete mental image of the task at hand. With traditional MVC it is easy to keep a mental image because the architecture is simple. When MVC moved to the Frontend we did too many changes, breaking the simplicity of the architecture and in the process breaking our mental image. Giving the controller layer back its functionality and place in the architecture you can build this mental image much quicker.

The way we achieve this is two fold. First of all we reduce the number of places changes are made and stored. It does not matter what you implement in your application, all state changes goes through one controller and any state is stored in one state store. Second, having a controller where all state changes flow through lets us build developer tools. With Cerebral you are able to debug and understand the flow of the application just playing around in the UI and using the Chrome Cerebral Debugger. You can even reset, traverse and keep the state of the application after a refresh. You can try that out on cerebral todomvc demo.

Summary

I hope this take on introducing Cerebral made sense to you. Whenever we build our applications we put the user in focus, but I think we can not create good user experiences if we do not have a good developer experience. Great tools gives great developer experience and that is exactly what Cerebral tries to be regardless of you model layer preferences and view layer preferences. Thanks for reading!