How React brought Model-View-Controller back to the masses
I know of few patterns and software ideas that have aged so well as Model-View-Controller. Originally designed as a pattern for desktop GUIs, MVC proposes that your application should have a single Model and, for each major part of the UI, one Controller and one View.
That’s pretty different from the MVC style that Rails popularized, with one view class, one controller class, and one model class for every domain entity (every database table, if you will). The Rails model works well for the kinds of typical CRUD apps that got Rails popular, but it does not hold up as well in highly interactive and dynamic applications, the kind where all sorts of data are mishmashed together all over the place. The kind that you choose to go Single-Page-App for.
Betteridge strikes again
Today, an article called Is Model-View-Controller dead on the front end? made the rounds, arguing that modern frontend frameworks like React finally put the nail in MVC’s coffin. Its title alone made me choke on my latte, because to me, React represents the movement that finally made developers treat the DOM as just a UI toolkit like any other.
If the DOM is just Yet Another UI Toolkit, can’t we learn from all the patterns and ideas all those other UI Toolkits have? Why, yes we can! In classic MVC, the Model triggers all connected Views when data changed, and then the Views query the Model for the data they need. The Controller handles user actions and uses that to update the Model, which then asks the View to redraw. This is unidirectional data flow pur sang and it comes from 1988. Can we do this in a browser? Sure we can, so people did, and they called it React/Flux.
Views with benefits
The core insight that React+Flux adds to the MVC pattern is that this stuff meshes well with immutable data. React’s Virtual DOM + immutable data solution to figuring out what parts of the view to update is just the last in a long series of pretty good ideas. In the nineties, a technique called damage+repair was popular. It means that you try to keep track of which pixel regions on the screen need redrawing as a result of user actions (damage), work back from those pixel regions to which data you need, and then make the view only fetch that data and use it to redraw (repair) only the damaged areas.
React calls this shouldComponentUpdate and it works way better in React because React operates on the DOM, which is a tree, and not on pixel areas. So there’s no need to try and deduce from damaged pixel areas what things need redrawing; you can just ask little subsets of the data directly, “did you change?”. Immutability makes this fast. To me this is so fundamental that I’d suggest that other UI toolkits consider adopting something like a DOM, insofar they don’t have one yet. React Native shows that you can steamroll a queryable DOM right over an existing UI toolkit and you still get these benefits. This is fantastic, and they didn’t do this in Smalltalk-80. Thanks, Facebook!
Controllers!
Now, here at TalkJS, we’re building a dynamic and interactive application (real-time messaging for marketplaces and platforms) so backend MVC was no option. When we started building, React was new and Flux was even newer. The dust of how to architect a decent React app hadn’t settled yet.
People knew Backbone’s Rails-on-the-frontend approach wasn’t working, but what to do instead was pretty much an open question. For us, classic MVC seemed an obvious route to explore, and Flux was an easy idea to adopt because it’s just the M in MVC under a different name.
But so far we’re the only team I know that has a Controller as well. I’d like to take this opportunity to share a little about how that’s been working out for us. Our architecture looks like this:
We have a single Fat Controller. Sure, that’s an antipattern in Rails but I’m not aware of a downside in classic desktop MVC. The controller is really just a big bag of functions that can respond to user actions, triggered by little event handlers in the view. The controller not only creates actions for the stores (eh, the Model) to process, but it also queries and updates our backend via our Fetcher (a nominee for the 2017 Worst Names In Software awards).
Most of our controller functions are optimistic, in that we send data changes to the stores and to the backend at the same time, so that the UI remains snappy and does not need to wait for the backend to have stored all data. Most React approaches allow this, but our controller code makes it very explicit and non-magic. I really like boring and explicit so I consider this a plus.
Having a controller helped us keep our views clean. They’re all about presentation and UX, there’s no fetching logic in there, no data processing, only stuff about what the user sees.
We’re really quite happy about this. If you’re starting have data molding code all over your views (and a little bit elsewhere too, for good measure), consider a controller. But even if you don’t, definitely consider a model and a view the in classic MVC sense. But you’re probably already doing that.
Back on track
The mistake we webdevelopers made was trying to shoehorn DHH’s backend remix of MVC into the frontend, ignoring decades of interactive GUI building architecture knowledge. I think we easily lost 10 years of progress because of this — in the entire 00’s, the only impactful progress that I can see is Microsoft’s MVVM approach in WPF and even that was largely ignored outside .NET-land.
Don’t dismiss MVC. Look at how old Win32 applications are built. Learn from the great ideas in the CocoaTouch. Have a look at Delphi, which not only makes MVC peanuts, but also reusable components. These are fantastic technologies with fantastic discoveries made by fantastic engineers. Modern single-page web apps are more like these technologies than like your average Rails codebase. I’m sure there’s a lot of untapped potential in there that we, the web crowd, can learn from instead of reinventing every single wheel by ourselves.
I’m happy the Facebook people rediscovered MVC and I’m happy they gave it a new name. MVC frankly has gotten way too many definitions over the years, so sure, this is good!
But saying that Flux/Redux killed MVC is like saying Clojure killed Lisp.
Written by Egbert Teeselink, co-founder and CTO of TalkJS. TalkJS lets you add user-to-user messaging to your online marketplace or platform in minutes, not months. Try it out!