Do you really want an SPA framework?

First, sell your soul to the framework maintainer…

What’s wrong with an SPA Framework?

I author and maintain quite a bit of software. Much of my code is available in commercial applications (SnapLogic, Qualaroo), OSS libraries on Github and NPM, or demonstration applications like Typebomb. I am the co-author of the book that Dr. Dobb’s Journal named as one of the best developer books of 2014 and called it the “Master Handbook” for SPAs. Yet despite numerous requests I have not published an SPA framework.

Why? Because I don’t want to lock developers into a platform that must be, by definition, opinionated and limited. An SPA framework provides safety at the cost of an investment into their platform and a loss of flexibility and control. They can hinder our ability to innovate and build quality software. For these reasons, I advocate developers focus on JavaScript language mastery and SPA architecture rather than the promise of a silver bullet SPA framework.

Before we proceed please note that everything has its place. SPA frameworks can be useful to new or casual developers who don’t know or care how an SPA works. But before you hitch your star to Ext, Angular, Ember, Aurelia, Meteor, Backbone, Knockout, Vue, or Mercury or dozens of others, please consider that every shiny new tool has its cost. Here are some precautions you might want to consider before you dive in.

Frameworks and the inversion of control

When we use an SPA framework, the quality and capabilities of our application are strongly limited by it. This inversion of control is a major impediment in building a a nimble, flexible, testable, and maintainable application that can stand the test of time.

When we use a sound architecture and libraries instead, however, we can swap libraries out when they are updated or better one becomes available. Or we can decide not to change a thing if an update doesn’t suit our needs. We can mix and match the best-for-our-purpose libraries instead of using a framework’s mishmash of solutions of varying quality. Why, for example, should one bother overriding the mediocre mechanisms of a framework when just removing the framework can results in simpler and easier to maintain code?

Does this mean we need to write everything from scratch?

Absolutely not. jQuery and other best-in-class libraries can provide a more capable and complete foundation for building a modern SPA compared to many frameworks. We can start with a simple and clean SPA architecture, p10 as detailed in Single page web applications, JavaScript end-to-end (also available directly from Manning), and then add libraries that are best suited to our application. We can leverage jQuery’s maturity, performance, excellent tools, and vast ecosystem instead of competing with it. We also avoid ceding control of our application to an SPA framework.

Frameworks and complexity === insanely long cycle times

SPA frameworks these days are approaching or exceeding the complexity of JavaScript-to-X compilers with sadly similar results. If we want to go all-in, we can get a “two-fer” by selecting Angular 2 + TypeScript. That way we can shoot ourselves in both feet instead of one and greatly increase our cycle times. Who needs short cycle times anyway?

Well, actually, we do. If our overhead for producing working development code is greater than say, oh, 5 seconds, then somebody out there is definitely kicking our ass on cycle times. We can fail 300 times an hour with a 5 second cycle time. In other words, if it takes 200 failures before success, we will need a minimum of 40 minutes to resolve an issue. However, if our cycle time is 5 minutes because of the multi-compile overhead of an SPA framework, our minimum time before success will be 72 times longer, or over two full work-days. You make the call.

Long cycle times not only kill productivity, but they also stifle innovation because only so many solutions can be tried within any given period of time. To paraphrase Thomas Edison, the key to innovation is to learning how to fail really fast.

Frameworks DSLs aren’t portable

SPA frameworks DSLs aren’t the most portable of life skills, just like JavaScript-to-X compilers DSLs. How many developers have moved from GWT to YUI to Dojo to Ext to Backbone to Closure to Knockout to Knockback to Ember to Angular? How about sprinkling some Bootstrap, Sass, TypeScript, CoffeeScipt, Cappuccino, HAML, and a few more compile steps in there just for the fun of it? Maybe one is better at learning HTML5, CSS3, JS really well and taking all the noise about these “silver bullets” with a grain of salt. See The fog of SPA

Been there, got the T-shirt, bombed the airport

I once used a framework (not my choice) and had to wait months for a new version to support a desired feature. Once the framework was updated, I discovered excruciating pain of trying to find and fix all the regressions. It wasn’t easy, of course, because (a) some of the most dastardly bugs were within the framework itself, and (b) frameworks tend to intermingle display and business logic, so testing was tedious and difficult. Which, of course, brings us to our next subject…

What about testing?

Testing a Single Page Framework Web Applications (SPFWA?) often requires an additional framework for testing the simplest of logic. Selenium, ZombieJS, and other intricate solutions are often employed to test the most basic model logic that shouldn’t require display testing at all. Yet there it is. Complexity breeds complexity.

When we use a sound architecture and libraries instead, however, we can easily decouple display and business logic so we can regression test our application in less than a second. My commit hook for the above application eventually ran the full regression suite and JSLint for all changed files in less than 4 seconds with over 600 assertions and ~95% coverage. We could refactor and reorganize the code at-will because only the most obscure bugs could sneak past the regression tests. The architecture and method of testing scales very well on larger projects too.

What are your preferred libraries

Please see hi_score for the most up-to-date list of libraries. Eventually this list will be moved there.

Capability Library Notes
DOM + Util jQuery A powerful, stable, tight library
AJAX jQuery … but prefer WebSockets, see below
Client Data TaffyDB A powerful and flexible SQL-like client data management tool
Coverage Istanbul The best JS code coverage tool I have found
DynamicCSS PowerCSS Insanely fast and efficient JS-CSS engine
Linting JSLint Avoid stupid mistakes with a commit hook
Events, promises Global Events Use the same event and promise methods for both logical and browser events
Reporting Coveralls See
Routing uriAnchor A jQuery plugin for robust routing that includes support for dependent and independent query arguments
SVG D3 Easy graphs and charts
  SVG Low-level jQuery plugin
Templates Dust Uses a powerful template DSL that minimizes the temptation to intermingle business and display logic
Testing Nodeunit Create a lightening fast regression test suite and use it as a commit hook
Touch Unified events Unified desktop and touch events
WebSockets Socket io The WebSockets protocol is faster and more flexible than AJAX for most applications. Consider using pure websockets client with a websocket server on a NodeJs with modern browsers (IE10+)

But I want the comfort of a Framework

We can clone hi_score to get a great starter project. It includes all the tools needed to deploy a modern, well packaged SPA for production. On Linux (Ubuntu 16.10/16.04) first ensure we have to ensure system prerequesites are met, although a professional JS developer will typically have these already installed:

  sudo apt-get install build-essential openssh-server git pandoc
  curl -sL | sudo -E bash -
  sudo apt-get install -y nodejs

Then we can then install, test, assess coverage, and build a distribution all in under a minute:

  git clone
  cd hi_score && npm install   # install dev libs
  npm run setup                # link    dev libs

  npm test                     # run regression tests
  npm run cover                # generate coverage report

  google-chrome coverage/lcov-report/index.html # view coverage
  google-chrome index.html                      # view examples
  google-chrome build/dist/ex*.html             # view distribution

hi__score includes automatic download and linking of best-in-class libraries, code standards, architecture diagrams, example code, and code compression and obsfucation. It employs typecasting to minimize type errors. Check out the code coverage on coveralls, and watch this blog for future hi_score announcements.

A parting thought

Please see this article on Angular which echoes many of the issues discussed above. Perhaps it should have been called “Angular JS: the ColdFusion of the next-generation”??

Cheers, Mike


Written on January 30, 2016