Web Framework Architecture

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.

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.

A brief history of JavaScript

JavaScript is one of the most widespread and most successful programming languages today. Its history is reminiscent of a “from rags to riches” saga. It is said that JavaScript was created in only ten days. I am not sure about the historical accuracy of this claim, but suffice to say that JavaScript was born at a pivotal moment in mid 1995 when the Netscape Navigator browser was driving the commercial breakthrough of the Internet. Things happened fast at the time. JavaScript was conceived as a “glue language” for the browser and the document object model to give programmers a means of making web pages more dynamic. As for glue languages, most of them die when the product into which they are embedded reaches end-of-life. The browser, however, never reached end-of-life, but was continuously improved, and thus JavaScript kept growing and growing.

Its inventor, Brendan Eich, was tasked with creating a Scheme-like language targeted at amateur programmers for the Netscape browser. However, Java happened to be the hype of day and Netscape happened to be in a partnership with Sun Microsystems, the then owner of Java. Therefore, the language was christened JavaScript instead of LiveScript/Mocha and the syntax was made to resemble that of Java. Well, at least somewhat. To that end, the parentheses were dropped and the functional aspects of Scheme were retained. Surprisingly, a prototypal object model was chosen, slightly exotic at the time, possibly to allow easy object creation and extension without the need for complicated OOP constructs. It turned out to be a winning mix, because it allowed people to use procedural, functional, and object-oriented programming styles “al gusto”. Furthermore, one could use objects without even knowing anything about OOP.

Just a year and a half later, at a time when Netscape held over 60% of the browser market, JavaScript was submitted to ECMA International association for standardization and for overseeing the future development of the language. The first ECMA-262 standard was published in June 1997 and since then, JavaScript was also known as ECMAScript of which there are now several competing implementations. Strategically, this turned out to be a brilliant move. It ensured the uncoupling of JavaScript from the Netscape product. Eventually, this meant that JavaScript survived the browser wars, whereas Netscape Navigator did not. Around the same time, arch rival Microsoft created a clone language called JScript, a JavaScript “dialect” with small differences in its implementation. Though imitation can be seen as the sincerest form of flattery, this rang in a long-lasting period of browser incompatibilities, aggravated by Microsoft’s quirky DOM and CSS implementations, that caused web programmers a permanent headache.

The triumph of JavaScript continued, however. Netscape had the bright idea to turn JavaScript into a server language from the very beginning, but for some reason the world wasn’t ready for that in the 90ties. Just before the end of the millennium, the third edition of ECMAScript was released. It added regular expressions, exception handling, and a bunch of other things that made JavaScript a (somewhat) grown-up language. ECMAScript 3 remained the standard for 10 years and it gained significant leverage through Web 2.0 and Ajax. This technology allows data and partial web pages to be loaded from the server in the background through asynchronous application design. JavaScript is well-suited to asynchronous programming due to its functional nature. Since it is already present in the browser, JavaScript+Ajax enabled moving view logic entirely to the browser thus making applications more responsive. Two ingredients played a key role in this development: JSON and the jQuery library. A typical Web 2.0 application mixes HTML with JavaScript display logic and thus allows the creation of dynamic components handling data and visual content.

A natural outcome of this was the inclusion of library support for JSON parsing into ECMAScript 5 released in 2009. Because the complexity of JavaScript code increased with Web 2.0 innovations, “strict mode” was introduced in the same release. If enabled, it disallows the use of error-prone syntax and constructs, a kill switch for the weak sides of the JavaScript language, so to speak. An important event in the JavaScript world was the introduction of Node.js in the same year, a server-side JavaScript runtime environment based on Google’s V8 engine. Node.js allows the creation of server applications with non-blocking IO using an asynchronous reactive programming model. Node.js gained significant traction in the 2010s and is currently making inroads into enterprise server applications where it replaces Java and .NET applications. Another JavaScript driver is the single page application (SPA) model that redraws the screen of a single web page, akin to a desktop application, instead of successively loading web pages. Such applications are commonly implemented using a JavaScript web framework similar to server language web frameworks.

 

ECMAScript 6 (ES6), released in mid 2015, introduced a substantial number of new features and syntax to allow the creation of complex applications. They include block scope, arrow functions, enhanced parameter handling, modules, classes, enhanced object properties, assignment destructuring, iterators, promises, generators and new data types. Some of these features address the special needs of complex asynchronous server-side applications. Many developers perceive ES6 as the most important language update thus far. The ES7 standard published in the following year was a minor upgrade, adding an exponentiation operator and one additional array method. The ES8 standard released in June 2017 is the most recent major upgrade that ties in with the need for more complex language features for building server-side enterprise applications. It adds the async/await syntax which further simplifies asynchronous programming. It also provides new data structures and syntax to support concurrent programming, which opens the door to multi-threaded JavaScript environments.

JavaScript has turned from an ugly scripting duckling into a versatile and feature-rich full-stack web programming language. As of today, it is the web language most in demand and on its way to take over enterprise applications. It’s been quite a journey.