Today, it's possible to build rich, sophisticated applications in the browser. Everybody's familiar with GMail and Google Maps, of course, but have you seen stuff like Mozilla's PopcornMaker?

Popcorn Maker multimedia editor

This just blows me away. And applications like this are appearing all over, and they're well within the reach of any tech startup.

Of course, the major problem with building sophisticated applications is that now you need to maintain them. And just hacking everything together with jQuery is probably going to make a mess.

I've built a few rich applications during the last twelve months, both for clients and for myself. Based on that experience, here's a list of tools that have worked well, and tools that look promising for the coming year. This list is shamelessly subjective, and probably already obsolete. Please feel free to contact me with better suggestions; I'll add a bunch of them to the article.

Personal choices: Table of contents

The standard disclaimer applies: In 95% of all cases, it's better to stick with what you're already using, unless something else will offer you an order of magnitude better productivity.

Keep reading for code snippets, rationales and some promising alternatives.

Model View Controller: Ember.js (or Angular.js)

I've used Ember.js on a large, real-world project, and I couldn't be happier with it. Once I was over a two-week learning curve, it was pretty obvious how to cleanly structure an Ember application. We could build rich, interactive UIs in hours or days. The biggest drawback: A couple of key pieces are not yet ready for prime time, including Ember Data, Ember App Kit and ember-cli.

  • Ember Data is a very slick "model" library that runs in the browser. Even though this is officially not production-ready, I've used in production code successfully. If you choose to do so, be prepared to deal with the upcoming breaking changes described in The Road to Ember Data 1.0.
  • Ember App Kit provides a standard directory structure, ECMAScript 6 module support, a build system, an asset pipeline, and a rather nice unit test runner. However, this is really just a source tree to get you started.
  • ember-cli will provide a nice command-line wrapper around Ember App Kit, and they promise to have some way to migrate existing applications at some point.

In other words, if you commit to Ember.js today, and if you want a full set of tools (a model layer, a unit test runner, etc.), you'll need to depend on several unstable libraries and port your code forward as those dependencies stabilize. In other words: either unit test the daylights out of everything, or schedule a month or two in 2015 for paying off technical debt.

Of course, Angular.js also looks extremely promising, and it seems to be growing faster than Ember.js at this point. So even though I've been very impressed with Ember, I'm sorely tempted to do a personal project with Angular.

Asynchronous callback handling: Promises/A+

Personally, I'm not a fan of callback-heavy code. I don't especially enjoy transforming all my code into continuation-passing style, and certain callback conventions make it easy to drop errors on the floor. (Sure, if I'm writing a Node.js library, callbacks are the right answer, because they'll integrate better with existing APIs.)

But both Ember.js and Angular.js make heavy use of JavaScript promises. Promises allow us to chain together a series of asynchronous functions and catch all the errors at the end. Here's an example using Ember.js, CoffeeScript and the RSVP promises library:

@store.find('language')
  .then (languages) =>
    @controllerFor("card").set("languages", languages)
  .catch (reason) =>
    message = "Could not load languages"
    @get("flash").displayError(message, reason)

There are quite a few libraries which implement promises, but they're all fully interoperable, except for jQuery's half-broken promise-like whatsits. But those can be worked around trivially.

Module system: ECMAScript 6 modules and a transpiler

ECMAScript 6 modules are thoroughly civilized. Let me quote an example from the Ember App Kit documentation:

import Photo from 'appkit/models/photo';

var PhotosNewRoute = Ember.Route.extend({
  model: function() {
    return Photo.create({
      title: "Beautiful photo"
    });
  }
});

export default PhotosNewRoute;

These modules can be used today, thanks to the ES6 Module Transpiler. This can convert ES6 modules into either CommonJS or AMD modules, which are the two pre-existing module standards.

Package management: Bower.js

Until recently, managing third-party JavaScript libraries for the browser tended to be a pain. But lots of people seem to be going with the Bower package manager, which makes it easy to install, download, update and use a wide variety of third-party JavaScript libraries. I've used it, and it does the job, though I do miss some of the more advanced features of Ruby's Bundler.

# Much nicer than updating a big directory
# of scripts by hand.
bower init
bower install 'jquery#1.11.1'

Unit testing: QUnit if I must, Jasmine or Mocha if I can

QUnit is everywhere. I don't like it, because it has a very clunky syntax for shared setup/teardown code. But lots of third-party libraries like Ember.js rely on it heavily, and anything else may be an uphill battle in those cases. Alternatives with better setup and teardown include Jasmine and Mocha. Go with whatever your framework or company already uses; there are no big wins here that would justify being incompatible.

// QUnit.
module("Addition");

test("adds two numbers", function() {
  strictEqual(1 + 2, 3);
});

// Mocha.
describe("Addition", function () {
  it("adds two numbers", function () {
    assert.strictEqual(3, 1 + 2);
  });
});

DOM manipulation and compatibility: jQuery

For short, lightweight pieces of code, there's a lot to be said for working directly with the DOM. And there are a couple of lightweight libraries such as Zepto.js which provide jQuery-compatible APIs with a 5K or 10K footprint. But if I'm going to be working on a larger application that relies on several third-party libraries, I'm generally going to go with jQuery, if only because so many other libraries rely on it.

Syntax: CoffeeScript (OK, OK) or a couple of other alternatives

JavaScript's actually a pretty nice language, except for the syntatic noise and the gotchas:

// Everybody needs a few extra braces and 'function' tokens.
doSomething({
  compareEqual: function (a,b) {
    return a === b;
  }
});

A bigger danger is that several of JavaScript's built-in operators have semantics that were apparently designed to make debugging horribly annoying. To quote James Mickens' recent epic rant in the Usenix ;login: journal:

JavaScript is dynamically typed, and its aggressive type coercion rules were apparently designed by Monty Python. For example, 12 == "12" because the string is coerced into a number. This is a bit silly, but it kind of makes sense. Now consider the fact that null == undefined. That is completely janky; a reference that points to null is not undefined—IT IS DEFINED AS POINTING TO THE NULL VALUE. And now that you’re warmed up, look at this: "\r\n\t" == false. Here’s why: the browser detects that the two operands have different types, so it converts false to 0 and retries the comparison. The operands still have different types (string and number), so the browser coerces "\r\n\t" into the number 0, because somehow, a non-zero number of characters is equal to 0. Voila—0 equals 0! AWESOME. That explanation was like the plot to Inception, but the implanted idea was “the correctness of your program has been coerced to false.”

The solution, of course, is to always use ===, and to never slip up and use ==. Or you could wrap JavaScript in a language which does something more sensible. Personally, I'm quite fond of CoffeeScript, though many reasonable people will definitely disagree, and it's not the right choice for all organizations.

doSomething(compareEqual: (a, b) -> a == b)

If you like strongly-typed languages, Dart is apparently pretty popular these days. Or, if you want to stick close to JavaScript but you're feeling adventurous, there are ECMAScript 6 transpilers out there, though I'd be careful to use only the syntax that's already pretty stable.

The bad news: These recommendations will be obsolete quickly

The JavaScript world moves quickly. If I'm lucky, maybe half of these recommendations will still be reasonable in May of 2015. (In fact, some of them are probably obsolete already.) We're in that awkward gap between the "Time of Inadequate Tools" and the "Time of Mature Tools." It's sort of like the Cambrian explosion. Tons of cool new possibilities are opening up every day, but a lot of them will be extinct within a year or two.

So at this point, I only recommend investing in rich web applications if (1) you have access to experienced programmers, and (2) these tools can provide you with substantial near-term wins that are worth some maintenance headaches in a year or two. This is probably true for Internet startups, but not for established companies that already have a decade plus of old code that already needs to be updated.