Should we use MVC for modern web applications?
MVC is one of the most 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
Single Page Applications rule the web with different client side rendering frameworks like angular, backbone, react and many more. These frameworks made java script development easier and by so made the client “smarter” and the server “dumber” by mostly responsible for communicating with the client and data persistence. Most of the application’s logic moved to the client side.
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 much sense as opposed of 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 how 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 which will get hard 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 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. Now 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.
2. Use a shared service to pass the data between the components.
MVC doesn’t provide us 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 which is just a template. It sounds like a good practice but if you think about it (and don’t kill me right away) maybe that’s actually not that 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 effecting 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 new promising framework React.js.
Flux introduces three new features that create the necessary infrastructure:
- Action — simple class that defines the events that a components may trigger
- Dispatcher — A class that dispatches the events from the Action to the different Stores.
- Store — A store catches the events, process it and then fire a completion event that components may subscribe to.
Let’s implement the previous example with React and Flux
Here is a basic Flux file structure. You can find here all the parts we discussed earlier.
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.
[In my next post I’ll show how to test components using react and compare it to angular]
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.
Originally published at dennis-nerush.blogspot.co.il on April 30, 2016.