Click here to monitor SSC
  • Av rating:
  • Total votes: 12
  • Total comments: 0
Konrad Lukasik

The JavaScript Landscape in Broad Brushstrokes

30 July 2014

JavaScript has come a long way from its humble origins as a simple interpreted object-oriented language for browser-side scripting of web pages. Its many inadequacies, poor debugging and testing, and its design weaknesses, have now been circumvented by frameworks and libraries. JavaScript is now ubiquitous, but is it now suitable for a central role in corporate applications?

Intro

A couple of years ago I was deeply involved in an IT project within the pharmaceutical sector, which was mainly in maintenance mode. It was an ASP.NET Web Forms application with some JavaScript (JS) and CSS. At the time, I’d been focused primarily on the complex business logic and customer relationship, so I didn’t have much time to keep up-to-date with the evolution of the JS world, especially since that was not required for the project: Then suddenly my company got a new opportunity – a totally green-field project with some quite sophisticated logic on the browser side. I wanted to assist with this, and was given the chance from managers. When I looked at the JS landscape, I realized how much it had changed. Here are few of my insights of its current state, from my own particular perspective.

Origins

JavaScript, which was initially called LiveScript, was developed at Netscape in 1995. It was originally intended to be the Java-world equivalent to Microsoft’s Visual Basic – a lightweight, ubiquitous, interpreted language for IT people who weren’t necessarily programmers. The name ‘JavaScript’ caused confusion because many people thought it is derived from the Java programming language. It isn’t. It was intended to be simple to use, in much the same way as CGI scripts (does anybody remember that?) or Classic ASP. Over time, JS got more popular, and important; particularly when AJAX (Asynchronous JavaScript and XML) allowed the development of browser-based applications, requiring JavaScript to be used in advanced ways within the browser. For long period, developers were focused on the architecture of the server-side and data layers, so called ‘back-end’, to the detriment of the browser-based code. That led to ‘spaghetti code’ in JS.

$(document).ready(function () {

    $('#combo').change(function () {

        var value = $(this).val();

        var result = myframework.getDisplayMessageFromServer(value);

        $('#messagediv').html(result);

    });

});

Listing- Sample spaghetti code (Source: http://blogs.msdn.com/b/simonince/archive/2011/02/28/javascript-architecture.aspx)

Frequently, identifiers of elements were embedded in the code, there was no structure or separation of concerns whatsoever, blocks were often repeated (breaking DRY rule) and coupling was high.

As soon as the leading browsers had adopted a reasonable measure of shared standards, businesses required more complex apps running in a browser that were portable between platforms and responsive to the size of the screen, from mobile devices to HD screens. Even though JS had been intended originally as a kind of add-on for a browser, being on top of HTML and CSS, it evolved into a solid platform with a lot of supporting libraries and frameworks.

Figure1 - JavaScript usage approaches (Source: http://blogs.msdn.com/b/simonince/archive/2011/02/28/javascript-architecture.aspx)

Architectural options

As Justin Meyer, author of JavaScript MVC says: "The secret to building large apps is never build large apps. Break your applications into small pieces. Then, assemble those testable, bite-sized pieces into your big application.There are architectural decisions to be made that will determine the outcome of the development of any JavaScript application. Nowadays when building JS-based web applications, we have wide spectrum of options available. Let’s look at three of the main categories: Base Libraries, packaged MV* frameworks, and Bespoke JS Architectures.

Base Libraries

For starters, we can stay with just a base library. There is plenty of these available – jQuery, dojo, Zepto, YUI are a few examples. If a high proportion of the heavy-lifting is done by the server, then the decision to use only a base library is rational and anything more may be overkill.

MV* frameworks

Secondly we can build our system on top of MV* framework. Although JS is novel in many ways as a language, those patterns that deal with how to organize the code have been extensively borrowed from other languages. MVC, MVVM and their variations, transplanted into JS, have served as a foundation for a family of frameworks called MV*. There are many options, such as AngularJS or KnockoutJS. This wide choice is both a blessing and a curse: When it comes to selecting a framework, too many options may lead to frustration and confusion (effect a.k.a. Yet Another Framework Syndrome). Fortunately there are knowledge bases such as http://www.ToDoMVC.com that provide the implementation of the same functionality in different MV* frameworks. Sites like this should help you to choose the right one for your exact requirements and circumstances. Developers’ skills are also part of equation – they might already know a particular framework or presentation pattern it uses; it might, for example, be easier to switch from WPF to KnockoutJS. Beware of opinionated frameworks such as Backbone.js or Ember.js because they lock you into specific ways of doing things, theirs to be precise. This is limiting by design and is done for good reasons, but protects developers from figuring out on their own how things should work and in the long term may lead to worse system and its architecture.

Bespoke JS Architectures

Finally you can write your own completely bespoke JS architecture. This might be necessary in large-scale JS applications that are predicted to have a long lifespan, especially those which do most of their heavy-lifting in a browser and will require significant maintenance efforts in future.

Nicholas Zakas and Addy Osmani presented an example of such an architecture. It has three layers: the base library being lowest, followed by the application layer, and topped by sandbox and modules. It particularly stresses loose coupling, scalability, reusability and testability. Each element has limited knowledge of the system – every layer knows only its base.

Figure- Scalable JS architecture by Nicholas Zakas

The Base library provides such basic functionality as browser normalization, DOM manipulation or AJAX communication. The application core layer manages the life-cycle of modules, the communication between them and handles errors. The Sandbox ensures a consistent interface between modules and acts as a security guard. Lastly, the module delivers meaningful user experience, interacts only with the sandbox, does not create global objects or directly reference other modules. With such an approach, it is possible to switch between base libraries quite transparently for performance reasons. Definitely this is not the architecture that fits all requirements, but it is worth knowing as it represents the state of the art with custom frameworks. If you need more, here is a presentation covering the details.

Additional building blocks

Assuming that you have chosen some middle-ground JS architecture, it might be that the MV* framework that you have selected or inherited (in case of maintenance project) does not provide all the building blocks you need. Let’s look at supporting libraries which may help extend your capabilities. A few logical components that we can distinguish are:

  • Modularization / Dependency Injection – These days you cannot use the global scope to declare functions and variables, because they may conflict with other elements of your code, 3rd party libraries or browser extensions. Moreover your code is easier to understand when it’s modularized and its interface & dependencies are clearly stated. Although you can use IIFE (Immediately Invoked Function Expression) to limit visibility, RequireJS is clearly a leader in this area. Not only it does all of the above, but it also supports ‘lazy-load’ of code – only JavaScript required at the moment is downloaded to the browser, thereby minimizing the network overhead. As an addition, it has the R.js optimizer, which combines related scripts together and minifies them.
  • Event messaging – To further decouple the application’s components, you can use messaging. There are two ways to implement this in JS:
  • Observer events – the producer exposes an event and the consumer subscribes to it. This is the standard and most common pattern of handling events, where the producer has a direct reference / callback to the consumer.
  • Mediated events – there is a central hub that both the producers and the consumers use. For example, PostalJS is a library working in this model. As an extra feature, it supports wildcards.
  • It is generally suggested that you should use Observer events within components and Mediated events between them.
  • Routing – When developing state-of-art Single Page Application (SPA) in JS, you will need a framework to switch between different UI views, track the history of navigation and support the browser’s bookmarking. Not all MV* frameworks support this ‘out of the box’. When in need, Crossroads might come to the rescue. It provides the means to register a function to handle a particular route. It: supports optional parameters, decodes the query string, can have multiple listeners and can use regular expressions, functions or arrays to validate parameters.
  • Testing – My favourite testing framework in JS is Jasmine. It is a BDD framework and, as such, allows the tester to define behaviour as a set of test suites consisting of specs. It comes with a nice set of matchers to clearly define how you expect the code to behave. It has the concept of a ‘spy’, which can stub any function and track calls to it. Finally it supports a running spec that requires asynchronous operations. If you are looking for something more traditional, we used qUnit in some projects.
  • Mocking – You might need a way to simulate business services when you are building a dynamic interface without a backend. You’d need to do this when two separate teams work on distinct layers of your solution. Mockjax and mockJSON come in very handy. The former provides a way to simulate the Ajax response; the latter adds controlled randomness to responses.

Outro

Of course, the JavaScript world is much more complex than my outline might suggest. There is node.js for a start; and quite recently the reactive programming paradigm entered JavaScript.

There is a great presentation on YouTube called Angry Birds of Modern JavaScript Development by Elijah Manor. In this presentation he discusses, among other things, what is important from the development perspective. He includes the coding standards you can follow, code quality tools you can use to verify principles and complexity (JSHist, JsLint, Plato), and the tools to generate documentation from code or JS design patterns. Really brilliant! I cannot recommend it highly enough.

The pursuit for better browser programming has led to the creation of strongly-typed languages like TypeScript or CoffeeScript. Although they both add syntactic sugar to the JavaScript syntax and trans-compile to JavaScript, they are not game-changers for the browser. However, it is likely that most of the popular features, improvements and components of JS libraries will enter the ECMA standard in near future.

Gilad Bracha, a Google engineer, predicts that web applications may one day surpass desktop applications in function and usability -- if developers have more programming languages to choose from. The web languages of future need to have built-in support for offline and enable ease of development and testing. Bracha helped author Dart programming language, which Google allegedly designed not to replace JavaScript, but to give developers viable options.

Nonetheless, we are where we are; and when you need an MV* framework then AngularJS is, in my opinion, the best on the market. It is a full MVC / SPA framework. It defines the structure of code, but it is not as restrictive as other frameworks like Backbone.js. It has a corporate sponsor that you have probably heard of called Google. The popularity graph on Google Trends shows that it is way ahead of other frameworks. Similarly in the “Top JavaScript MVC Frameworks” survey on InfoQ.Com, AngularJS is a winner, though it is worth noticing that the study is over one year old. Even ThoughtWorks, a software company known for radical thinking, admits in its recent Technology Radar that it is used widely in their own projects.

Figure3 - Popularity graph from Ingo Rammer's AngularJS presentation at NDC London 2013 conference

Tim Bray in his “Does the Browser Have a Future?” presentation emphasizes that nowadays we diminish our productivity by having to implement the same functionality on multiple platforms (iOS, Android, browser). His opinion is that browser development is like building on sand – DOM, CSS, etc. – it is all too broken. Who knows? Maybe that’s true and maybe the world will find another way to deliver the same functionality more cheaply using better technology. It happened before.

Konrad Lukasik

Author profile:

Konrad Lukasik is an enthusiast of Microsoft technologies in general and .NET in particular. A professional with ten years of commercial experience. Currently works as a Technical Architect at Objectivity (http://www.objectivity.co.uk/) and helps teams deliver high-quality software. He continuously works on making things “as simple as possible, but not simpler”.

Search for other articles by Konrad Lukasik

Rate this article:   Avg rating: from a total of 12 votes.


Poor

OK

Good

Great

Must read
Have Your Say
Do you have an opinion on this article? Then add your comment below:
You must be logged in to post to this forum

Click here to log in.
 

Top Rated

Rethinking the Practicalities of Recursion
 We all love recursion right up to the point of actually using it in production code. Why? Recursion... Read more...

Acceptance Testing with FitNesse: Multiplicities and Comparisons
 FitNesse is one of the most popular tools for unit testing since it is designed with a Wiki-style... Read more...

Acceptance Testing with FitNesse: Documentation and Infrastructure
 FitNesse is a popular general-purpose wiki-based framework for writing acceptance tests for software... Read more...

Prototyping Desktop Deblector
 Deblector is an open-source debugging add-in for .NET Reflector; the Reflector team investigated... Read more...

.NET Reflector Through the Looking Glass: The Pudding
 There a number of ways in which Reflector, either by itself or with an Addin, allows you to analyse... Read more...

Most Viewed

A Complete URL Rewriting Solution for ASP.NET 2.0
 Ever wondered whether it's possible to create neater URLS, free of bulky Query String parameters?... Read more...

Visual Studio Setup - projects and custom actions
 This article describes the kinds of custom actions that can be used in your Visual Studio setup project. Read more...

.NET Application Architecture: the Data Access Layer
 Find out how to design a robust data access layer for your .NET applications. Read more...

Calling Cross Domain Web Services in AJAX
 The latest craze for mashups involves making cross-domain calls to Web Services from APIs made publicly... Read more...

Build and Deploy a .NET COM Assembly
 Phil Wilson demonstrates how to build and deploy a .NET COM assembly using best practices, and how to... Read more...

Why Join

Over 400,000 Microsoft professionals subscribe to the Simple-Talk technical journal. Join today, it's fast, simple, free and secure.