APIs, React.js, STAR

Why I no longer use MVC frameworks – Part 2



My first post on that topic caused a bit of a stir. I even made it to the “Programming Jerk Circle” on Reddit. So I continued my investigations trying to wrap my head around Leo’s comment on “the current state of art in JavaScript frameworks” which I guess most people would sum up these days to be Angular and React, not to mention Angular2 or Mithril. (I know that React is not considered to be an MVC framework, “it is just the View in MVC”, I’ll respond to that question later in the post)

Again, I’d like to disclose that I am a server-side SOA/API/B2B type of guy who sees Apps (Native or Web) as a series of API calls (with and without side effects). I understand there is more to just APIs when you need to deliver the best possible UX, but there is this large class of applications where the DOM (or view) can be considered, for the most part, static between any two API calls. I don’t have a strong preference as to where the DOM is produced (client or server), and ideally you would want to write some isomorphic code such that you can change your mind when needed (SEO, Performance, Scalability…).

You can’t innovate these days without delivering an OmniChannel experience from the customer’s favorite mobile device (including the $#@%! watch) to the old Web and yes, occasionally customers need or want to talk to humans. Soon enough, you’ll start facing the fragmentation of screen formats (Even Apple succumbed under market pressures) and as it stands, IT simply cannot deliver OmniChannel solutions without some form of philanthropy.

The biggest and most painful shortcoming of MVC Frameworks is that they do not support multiple form factors: you can either rely on CSS to do the heavy lifting or create separate views for each form factor. React does come with a cross-platform model, which is a small plus, but still has no support for multiple form factors. When you factor in multi-language support… there is indeed a huge tradeoff between UX, number of devices supported and cost.

Incidentally, what I find fascinating is the ability for all these MVC Frameworks to step on their own toes without ever falling on the ground. When you read some of the design considerations for Angular2:

Angular 1 wasn’t built around the concept of components. Instead, we’d attach controllers to various [elements] of the page with our custom logic. Scopes would be attached or flow through, based on how our custom directives encapsulated themselves (isolate scope, anyone?).

… and take a peek at the (new and improved) semantics of Angular2, the message is: “well with Angular1 we were all wrong, but no worries, this time we got it right”. Is Google telling us that since 1978, when the MVC pattern was first spotted, the cream of their engineering team just realized that it needed to overhaul its semantic foundation? And still they offer no support for the major pain point developers are facing today?

As an MDSE/MDA practitioner, I have had my own share of moments like these and I can assure you that this is the essence of MDE: the metamodel, except in a few rare cases, can never cover all the use cases people will encounter. You just can’t write programs from (anemic) metadata. This is particularly true of UI frameworks where behavior cannot and should not be specified declaratively. That’s why I favor code generators over black box frameworks. A product like Buildup.io has done a great job at building this kind of code generators, with support for iOS, Android and Xamarin.

The second major flaw of just about any MVC Framework is the way they weave (or more exactly, don’t weave) API calls into their programming model. In the case of React, for instance, this was a complete afterthought with Flux and Redux (See the discussion on that topic in the next paragraph). Last year I published a simple pattern ReaCall that helps with the decoupling of the components from the API calls. In the case of Angular 1 or 2, the focus is (as always) on binding the response to the view.

As a starter, one of the big problems in creating the proper API request/response binding model is the arbitrary underlying hierarchical structure of the view. API orchestration does not align well to a hierarchical structure. But the problem of API binding is far more insidious because it gives just enough incentives for the developers to adopt a Vertical Slice pattern, which is characterized by designing API boundaries that automagically bind to a View. In other words, the design of the API is driven entirely by the design of the view.

That is an absolute anti-pattern in the API (and old SOA) world. In the context of OmniChannel, that pattern will kill your organization when applied at scale because it forces you to create new APIs each time the view needs to change or a new view requires similar data. In the late 2000s I witnessed a billion-dollar program collapse under the weight of the Vertical Slice pattern. I published some Math that explains what happens when you choose an “immutable” versioning strategy for your APIs or Services. If you don’t believe the Math, let me tell you that when I audited the program they had a dedicated team of 45 “modelers” that were creating service/api interface specs all day and they were planning to ramp it up 120 people within the following year (yes your read correctly, 120 people which day-to-day job was to create interface specifications, not even write a single line of code).

The rationale for using that pattern is that the MVC framework “saves you some time” when binding the response to the view. How experienced developers feel about having APIs that automagically bind to the view? I did a small experiment in a recent project by removing a redundant piece of data from the API spec that was displayed twice in the view (e.g. when you need to display the value of A and a flag indicating whether A>0). The dev in charge of coding the view got ballistic, she would have gone to a VP just to get me to create an API spec that conformed to the Vertical Slice she was implementing. Not surprisingly, she was also complaining that her code was breaking when the API devs were getting too far ahead of her…

Please hear me on that one: falling into the Vertical Slice pattern trap alone would justify to not ever using an MVC Framework.

The third biggest flaw is a bit subtler and manifests itself in the service layer as well: MVC frameworks ignore control-states altogether, they are CRUD based (from the Angular developer guide):

Angular was built with the CRUD application in mind. Luckily CRUD applications represent the majority of web applications.

Developers and Architects tend to ignore control-states because they are used to build monolithic architectures where the server-side code always acts as a safety net for whatever the client is trying do, this is a recipe for disaster when building composite applications where the APIs’ state machines cannot easily be aligned with the solution’s state machine, since they are built by different teams or even third parties.

The angular2 team is sure falling with their two feet in that trap when they tout the “retry” semantics of the new and shiny observables. Who would believe that “retry” is the adequate response to failure in all circumstances? Compensation anyone?

If you have never read this paper from Dr. Lamport on “Computing and State Machines“, I certainly recommend that you get a cup of your favorite beverage, plan for an hour or two of quiet reading and your vision on CRUD, MVC and Composite Applications shall be transformed. To cry out loud, even React with the Engineering power they had could only come up with Flux, a stateless pattern, which role is to “dispatch” actions. Really? you mean that any user can potentially take any action at any point in time and there shall be no semantics other than “CRUD” (stores) to help the system understand whether an action is allowed at this point in time, from a control state perspective?

That being said, not everyone is as clueless at Facebook and Dan Abramov brought back some sanity recently with Redux which is implementing a basic State-Action model, but that’s still not enough. Common state machine (State-Action) are an approximation which works well when the model of the view is limited (such as a counter), but needs to be upgraded to a State-Action-Model (SAM) structure for real-world applications. The core of the argument behind the SAM pattern is that it should not be the action which decides of the resulting state, it is the model. I have provided a very thin library (STAR) and some samples  that will help you put the SAM pattern in practice.

I would argue that 80% of all the bugs come from the lack of control-state semantics in action-based programming languages and especially patterns like MVC. Making control-states explicit both for the view-model and the model is a game changer. These semantics align well with the ones of BDD and more generally with the separation of problem statements from solution specification.

There are not only major incentives to move away from MVC, but React is already on its way to drive the industry in that direction.

Apple knows a thing or two about MVC since they stole the pattern from Xerox PARC in the early 80s and they have implemented it religiously since:

mvc

What is fundamentally wrong here is the the fact that the controller acts as an “orchestrator” of the state changes. As a starter, unless you use something like Meteor implementing an “innocuous” notify between the model and the view in a Web application has looked like hell (and has been mediated by the controller). But, the absolute worst part of MVC is the “update” between the controller and the view, or phrased differently, the controller “selects” which view to display next. That could not be more wrong, it is the model which decides in which state the system is. The feedback loop between the view and the model (i.e. when Users trigger events).

What Facebook has changed with React is that it has moved the decision of what to display next from the controller to the model, as it should be. The React team is using some euphemism to introduce this pattern (such as “React is just the View in MVC”), but make no mistake, React is the beginning of the end for MVC.

What happens in React is that the loop between the view and the model is now free from deciding what happens next, and in particular, it is no longer about “selecting which View is displayed”. When you implement React correctly, there is only “one” View that reflects the model at any given point in time, not a series of Views to which you navigate too.

React sets the stage for a completely new way think about architecting User-driven applications, based on the SAM (State-Action-Model) pattern:

sam

The major difference between SAM and MVC is that “actions” are 100% functional. They are triggered from the view (or even externally triggered) and they present a new set of values to the model. It is the model, as it is the case with React that decides the resulting state which is then represented in the View.

It is no longer about selecting “which page you display next”, it is simply about reflecting the state of the Model in the View, React-style. The only thing I don’t like about React is the arbitrary shape of a React component. The semantics look attractive at first but their hierarchical composition model is very quickly limiting. In essence, a React component IS-A function, but with a level of ceremony that defeats the tremendous amount of value that you get from its underlying pattern, the SAM pattern.

So, again, my question, as it was in my first post is: “why would anyone want to use an MVC framework?” Their semantics are limited and constraining, if not completely broken and they drive developers to adopt horrific patterns such as the Vertical slice pattern.

When you consider that there are exactly 180 semantics to master just in the Angular2/Core package., why would you make that investment? To declare simple functions? Imagine how the people who invested all their marbles in Angular1 feel? What’s going to happen when Angular3 comes out? Best of all, the SAM pattern can allow you to deal opportunistically with multiple-form factors and can easily be translated to multiple platforms.

No, really, after spending 25 years using MVC frameworks, starting with NeXTStep and Interface Builder in 1990, and building a few of those myself, I give up. It’s a much better value proposition to build functional components and construct “the” view from these components. Having full control over what you need to do, especially with JavaScript, is so refreshing that unless you are financially or emotionally attached to an MVC framework I don’t see any reason to not at least give it a try. #NoMVC.

Leave a Reply

Your email address will not be published. Required fields are marked *

− 4 = 2