Stacking Up – part 2
In the first Stacking Up I looked at the bedrock of Internet/Web technology and showed that far from being stable it is more like flowing lava. Now I’m taking a quick journey through the frameworks that are layered on top of this lava, where naturally things are on fire.
Part 2 : Frameworks
First let me clarify what I mean by “framework”, as this is often a source of confusion. This definition is only in the context of Web-related technologies:
A framework is a set of generic software elements whose behaviour or characteristics are intended to be customized through extension, configuration and/or combination in order to assist the typical developer in the production of application-specific solutions. Through such customization, the framework faciliates the User Experience (UX), the realisation of data/information from application logic to the user and the marshalling of user input to the application logic.
With the exception of content-oriented Web sites, today’s interactive sites are generally developed as One Page Applications (OPA) where a page presented to the user is constantly manipulated in reaction to a wide variety of events. At the most extreme, the initial page is empty but the accompanying code (almost universally Javascript) then injects and structures content for the user. At the other end, a complete initial page is delivered, which can then be manipulated. In both cases there is just one fetch for the initial markup, and from then on the experience is managed by code.
Javascript, the ubiquitous but not necessarily uniform coding language in every browser certainly makes all of this possible, but the language is exceptionally “wordy”. Even the latest incarnation’s attempt at being terse is long-winded. Consider the simple task of getting the value of a text field in a form, which originally looked like this:
var v = document.getElementById('fname').value;
And improved via ECMAScript 5 to become this:
var v = document.querySelector('#fname').value;
But is still beaten in terms of conciseness by jQuery‘s approach:
var v = $('#fname').val();
Contrary to what some people think, jQuery is not a framework. It certainly simplifies a lot of things during development, and hides a lot of inconsistencies/bugs in a variety of browsers, but essentially it’s a collection of shortcuts to useful/new1 Javascript capabilities. As such, it is better described as a toolbox or library. The typical developer does not customize jQuery, so by the earlier definition it is not a framework.
Nevertheless, jQuery (or subsets/copycats) often play a vital role in true frameworks, especially those that expect customisation via code because jQuery-like approaches make this kind of customisation easy. jQuery UI supports customization, though it’s really just a collection of parameterized widgets heavily styled via CSS to enable the user view the underlying data model and capture interaction events.
Javascript Frameworks
The real (client side) frameworks do more than just provide a fancy visual experience. Most of them support full Model-View-Controller/Presenter (MVC/P) application design patterns comprising the representation of application data and the means of translating the current state of that data into something the user can perceive and manipulate. For maximum flexibility and reusability the View layer tends to be completely passive. In the traditional Web application design the Model would be almost 100% on the server side along with the “composition logic” (Controller or Presenter), while the View was the passive browser. The growing power of the browser gradually attracted the composition logic over to the client side, especially when round-trip latency was found to be too much of an impediment to interactivity. Page-to-page navigation also fell out of favour for much the same reason, to be replaced by partial page updates and the “One Page App”.
In time, the model also started to migrate to the client, though obviously the server’s ability to provide data persistence and security means that not all of the model can or should move client-side.
AngularJS
Version 1 of Google’s AngularJS has garnered a massive following since its debut in 2009. In incorporates its own light version of jQuery though will use a preloaded instance if already present. While it can be considered an MVC technology, it can also be applied in an MVVM model where (browser) events in the View trigger operations in the ViewModel, which in turn manipulates in-scope data within the model and then tells the View to apply any corresponding changes. In this way, changes observed via events in the View can lead to changes in the data model and changes in the data model can lead to changes in the View, a characteristic sometimes called “two-way binding”.
A Web page using AngularJS will contain normal HTML markup whose elements are augmented with certain attributes. Once the page has loaded, a script then “compiles” the page, directed by the augmentation attributes to manipulate the Document Object Model (DOM) representing the page, building new presentation structures, adding style features, attaching event handlers and so on. Within the markup, AngularJS is declarative and thus keeps the markup clear of code.
The app developer supplies the separate Controller logic that accesses the in-scope data associated with the newly compiled views, and AngularJS takes care of binding the whole lot together. The result is a highly interactive application running in a single Web page, and typically interacting asynchronously with a server (whose design and implementation is entirely independent).
For example, the following fragment of AngularJS augmented HTML will automatically present a list and will dynamically update the presentation if the underlying Javascript array of things changes:
<ol><li ng-repeat="thing in things" class="s-{{thing.type}}">{{thing.name}}</li></ol>
AngularJS is a framework as earlier defined. It allows new directives to be defined, so that the compilation phase can produce ever more complex presentations. It allows such directives and controllers to be combined and configured in all manner of ways. Interestingly, the official AngularJS site describes AngularJS as a “toolset for building the framework” rather than as an actual framework.
Mobile hybrid applications (i.e. native containers with embedded Web views) built with ngCordova or Ionic elegantly demonstrate the potential of AngularJS extensions in the mobile Web (which is now bigger than the desktop Web).
Finally, beware of Angular 2. This is cutting edge, so its dependencies can be limiting. It’s not an upgrade of version 1; it’s a complete rethink written in TypeScript. It’s probably going to be seen as the next generation, though I am reminded of the persistence of Perl 5 despite the many, many years of developing the non-replacement Perl 6 and its almost universal lack of use.
React
React is Facebook’s contribution to the frameworks world, first seen in 2011 and subsequently open-sourced. It’s often described as a library, but its flexibility and growing features are moving it into the framework space. Interestingly, it has its own document model (a virtual DOM), its own optional scripting language (JSX) and even has server-side support.
Many uses of Javascript involve the generation of presentation markup (HTML) to be injected into the page. Code like this would be typical:
return '<div class="'+salutationStyle+'">'+person.name+'</div>';
This can be difficult to follow, and potentially risky if one could inject nasty things into the data2. To make the handling of markup within Javascript easy, while also taking care of risks such as data tainting, Facebook introduced JSX, an extension of Javascript (ES6) that mixes script and XML-like concepts. You can get a flavour of this idea with this simple example:
return <div class={salutationStyle}>{person.name}</div>;
React components can be combined and extended, and can be declared as functions or classes (ES6+):
function Hi(props) {
/**/ return <div class={salutationStyle}>{props.name}</div>;
}
class Hi extends React.Component {
/**/ render(){Â return <div class={salutationStyle}>{this.props.name}</div>; }
}
JSX is transformed (or “transpiled”) to pure Javascript at runtime. You could forego the JSX entirely, but JSX has so many advantages that you’re unlikely to see any React solution without it.
Components have internal state (i.e. a data model), which when modified via React’s setState() operation will cause the presentation to be re-rendered. Data is passed by value between the components, thus avoiding tight coupling or dependencies. The data flows down through the component hierarchy. State information will be held in a subset of the components so that their descendants can be passed state values. If a component needs to update state information held in an ancestor component then the ancestor must pass down a callback function to allow its descendants to change the state information that it is managing. This use of pass-by-value and callbacks ensures that the internals of components are locally scoped and free to be re-implemented independently.
Finally, React has an advantage of being able to perform the presentation rendering on the server using Node.js, ReactDOMServer and Babel preset react. In this way you can have React end-to-end.
Backbone
Backbone.js came out shortly before React but after AngularJS. It’s a relatively small framework3 that provides the Model and View, with support for data model Collections to organise data and respond to data changes. It doesn’t have a Controller, leaving that aspect of the solution completely open to the developer. For certain lightweight applications, a Controller can be overkill, so this is not an unusual approach and can be quite pragmatic. So, in a Backbone solution the Models and Views talk directly to each other.
The problem with Backbone solutions is that if they are constantly growing then they can become sufficiently complex to warrant a Controller or similar supports, otherwise you find you have a MVS (Model-View-Spaghetti) design and that’s rather hard to maintain. For this reason, adding some architectural supports (e.g. Marionette) to Backbone is probably a good idea.
Even more from which to choose
I’ve only given a few examples. There are many more, though their market share is quite small. For now. Nevertheless, the Web frameworks space is bubbling over with options. Here are just a few more to consider:
- Ember. Probably not as flexible as you might expect a framework to be, but this rigidity also reduces the scope for mistakes
- Meteor. Another example of a framework that can work both client- and server-side. However, it reminds me too much of scriptlets where logic gets mixed in with the content. It’s just too tempting to put
{{#if...}}
into the markup! - Polymer. Another offering from Google that, rather than stick within the established HTML, unlocks the full Web platform, including Web Components and Progressive Web Apps (PWA) proposed in 2015.
- Knockout. Not as tiny as Backbone but still tiny. An MVVM framework with declarative bindings. Good for small apps.
- SproutCore. This MVC framework had backing from Apple in its early days (late 2000s). Can handle large amounts of client-side data, has an extensive responsive UI collection, built-in accessibility and offline support.
- Sencha Platform. This is a commercial technology for those with big demands and deep pockets.
Thoughts…
In my previous Stacking Up I focussed on what we thought of as the basic Web stack. In this follow-up I’ve taken a quick look at what is currently sitting on top of the stack, which are frameworks comprising the common markup (HTML 5), styling (CSS3) and behaviour (ECMAScript/Javascript) with a multitude of ways of managing the logic of applications, plus an abundance of tool support. What you find is that the frameworks are busy making their own adjustments to the standard elements by extending with custom attributes or altered syntax, and then processing this to produce material that is compatible with the current browser technologies. For example, consider the declarative extensions used by AngularJS, the embedded syntax introduced by Meteor, the hybrid script/markup of JSX in React or TypeScript in Angular 2, or even SCSS and LESS that modify how CSS is developed. It seems that the framework and library developers are all busy re-inventing the Web stack, even while they all target the “standard” Web (which we already know is far from static).
So, nothing stands still. By the time you’ve mastered any of these, something completely new and bewildering will have arrived with a life-expectancy measured in months. Welcome to Web development.
Footnotes
- To get a taste of the fluidity of script/DOM specifications, take a peek at one (Custom Elements) that is in progress at the time of writing. Expecting ordinary developers to make use of such advances is asking a bit much, but the most useful applications of these advances may appear in various libraries.
- For example, suppose you entered your name as “<script src=’example.com/nasty.js’/>” then you might be injecting something nasty into the page! Good developers would include code to de-taint user input, but if the framework/language does it for you automatically then that’s a major bonus.
- The commented source code of Backbone is just 72kb! Even when you add in the dependencies (mainly underscore) it’s still tiny, especially when minified.
Categorised as: Protocols & Specs, Technology, Web