MVC is one of the most commonly used design patterns in web applications. It can be used both with server and client side rendering. Frameworks like ASP.NET MVC and Angular adopted the pattern and made the development extremely easy and straight-forward.
Despite its popularity, I claim that the MVC pattern is no longer the best solution for creating rich and modern web applications.
MVC – the good parts
In order to support this transition the MVC pattern has moved to the client by creating controllers that manipulate data (the model) that is presented in the views. This makes a lot of sense, as opposed to using just jQuery for some simple DOM manipulation and handling all the heavy lifting in the server.
So instead of rendering the view in the server for each request, now it’s extremely easy to render it in the client and give the users a faster and cleaner experience.
“Magic tricks” like two-way binding allow applications to respond quickly to different events and change the appearance of the app accordingly.
Let’s have a look at the Angular docs website. We can easily navigate through the different sections in the website while avoiding a trip to the server for rendering the next page.
That is a classic MVC case. It works great for the “simple” apps where most of the page content is static and the user’s changes don’t affect different parts of the page.
However, this is not what rich modern applications look like.
Let’s look at this example. What happens when we increase a product’s quantity?
Four different parts of the page change (the header counter, the notification, the quantity of the product and the cart title).
Let’s try to implement it using Angular
Obviously I won’t build the entire app in a single view or use a single controller. That’s the worst practice, since it will break the SOLID principles of development by creating a giant controller that is responsible for EVERYTHING. This will become difficult to maintain over time.
I want my code to be highly reusable and simple to use, which I can achieve with components. Angular provides me with directives and, since Angular 1.5, it also provides components. I will create a controller, a directive and a template (view) for each of the following elements: the header, the notification and the quantity counter. In order to notify the other components that a product was added to cart, I can do 2 things:
- Use $rootScope and raise an event on it while subscribing to it on the other components.
- Use a shared service to pass the data between the components.
MVC doesn’t provide us with an out of the box solution for cross components communication. We need to extend it and create workarounds.
Here we saw just a single use case for cross components communication. For an entire application we’ll have many different events that will be managed using shared services or the $rootScope.
Does MVC help?
MVC forces us to separate the logic that is in the controller from the view that is just a template. It sounds like good practice, but if you think about it (and don’t kill me right away) maybe that’s actually not so good.
We are creating components, self-existing components that, like it or not, have their logic coupled to their view. You can’t really change the controller without affecting the view, and vice versa.
That’s alright! The components can be “smart”, they can have logic, handle their state and respond to different events and properties in a different way. So if that’s the case, why do we try to extract the logic and make the view dumb?
Why not create components that define their functions, handle state and create the view in a single class – a real reusable component. This component will use actions to trigger events that will be dispatched through the application and notify other components that something has happened, and allow them to respond if it’s necessary. This pattern is called Flux and it’s used widely with the promising new framework React.js.
Flux introduces three new features that create the necessary infrastructure:
- Action – A simple class that defines the events that components may trigger.
- Dispatcher – A class that dispatches the events from the Action to the different Stores.
- Store – A store catches the events, processes them and then fires a completion event that components may subscribe to.
Let’s implement the previous example with React and Flux
Here’s a basic Flux file structure. You can find all the parts we discussed earlier here.
The + button will call an action, which will trigger “INCREASE” event.
The CartStore will respond to the event, calling to the server and actually modifying the product’s quantity.
Then the store will fire a “PRODUCT_QUANTITY_WAS_CHANGED” event to notify who ever listens.
Then each component that subscribed to the event will be notified and will act accordingly.
What’s the difference?
Nothing mind-blowing really. However, we don’t need to create a controller and separate it from the view and then subscribe and fire events in order to communicate. We build components that are responsible for themselves. They constantly pass events from and to each other, allowing us to easily change existing behavior, add new components and integrate them with the existing events.
The classic Model View Controller separation seems a little bit redundant, hence it must be completely changed for creating rich and modern web applications.
Share your thoughts.
* I want to thank Yonatan Mevorach for reviewing this post.