Web Framework Architecture

2017-11-12

It appears that JavaScript web frameworks are repeating history by moving from a strict MVC push architecture to a push-pull component-based architecture. This is a trend that can be observed during the past two years. AngularJS is a case in point. The popular Angular SPA framework invented by Google has made a complete turnaround from version 1.4 to 2.0 and later. AngularJS 1.x and 2/4/5 are actually as distinct as frameworks of different vendors. Suffice it to say that the 2+ versions are not backward-compatible. It also seems that the current adoption of component-based JavaScript frameworks, such as Vue.js outpaces more conventional MVC architectures. Examples are Backbone.js and Knockout.js which are based on model-view-presenter (MVP) and model-view-viewmodel (MVVM) architectures respectively, both of which are elaborations of MVC.

architecture

But what is meant by repeating history? A similar thing happened in the Java world roughly 8-10 years ago, when first-generation frameworks like Struts 1 and JSF were replaced by newer frameworks such as Spring and Play that decoupled the request from the view/controller layers and introduced a bunch of new concepts such as dependency injection, domain driven modeling, and aspect-oriented programming, just to name a few. The same development could be then be observed in the PHP world, which inevitably follows Java trends with some delay. Case in point is the PHP Symfony framework that switched from an action-based push architecture to a component-based architecture in version 2.

To be frank, why JavaScript programmers have ever attempted to create frameworks with an MVC push architecture is beyond me. The whole approach seems unnatural, since JavaScript is native to the browser, and therefore native to the view layer. A push architecture implies that state changes happen on the server side, the effects of which are then computed and filtered and finally pushed to the view layer. It is easy to see that such a work-flow is more suitable to a Web 1.0 server application than to a JavaScript application. Of course, two-way binding resolves the dilemma partly, but it fails in decoupling controller logic and model changes from individual requests. The resulting problem can be solved by repeating logic across the application (bad!) or by introducing an application service layer (better but still unsatisfactory).

The natural starting point for a single page application is the user interface. The obvious thing to do is to structure the application around UI components based on an event-driven design similar to that of a desktop GUI application. Unfortunately, this is a bad fit for the request/response model dictated by classical web application architecture. A common approach is to decouple client state from server state and to marshal data back and forth through some low overhead protocol like JSON over HTTP/REST. It’s popular because it shields the application from networking concerns such as dealing with failing connections. However, a full-duplex TCP communication using a Websocket, for example, is a much better fit for such an application. As of now, not many web frameworks support using Websockets in a structured way.

There are, however, other areas in which JavaScript web frameworks are currently maturing and becoming more usable, once again following the example of existing server-side language frameworks such as Rails, Symfony, etc. by offering CLI-based scaffolding, support for validation, caching, ORM, DB migrations and whatnot. Possibly as an effect of server-side JavaScript, new build tools, and the growing JavaScript ecosystem, it is getting ever more viable to write large enterprise applications in JavaScript. Quite possibly, the most interesting developments of the upcoming year in web application architecture will happen in the JavaScript world.