zoo/ blog
Back to all articles
javascriptcoffeescriptsdkengineeringhistory

CoffeeScript for the Commerce SDK: A Love Letter and a Cautionary Tale

Why we wrote the Hanzo commerce SDK in CoffeeScript in 2010, what we gained, and why we eventually moved back to plain JavaScript.

CoffeeScript was released in December 2009. Jeremy Ashkenas had written it to address what were, in 2010, genuine ergonomic problems with JavaScript: verbose function syntax, inconsistent this binding, class inheritance done through prototype chains, no string interpolation, no list comprehensions.

We adopted CoffeeScript for the Hanzo commerce SDK in the latter half of 2010. For about eighteen months it was the right tool. Then it was not.

What CoffeeScript Fixed

The JavaScript of 2010 was ES3/ES5. Function expressions were verbose:

var add = function(a, b) {
  return a + b;
};

In CoffeeScript:

add = (a, b) -> a + b

For a codebase full of callbacks — which the Node.js and event-driven browser code we were writing was — the syntactic reduction was substantial. Deeply nested callbacks in vanilla JS were hard to read. In CoffeeScript, the significant-whitespace syntax made nesting explicit and readable.

The class syntax was the other major win. Building the Cart, Coin, and Checkout objects with proper inheritance in ES5 required explicit prototype manipulation that was tedious and error-prone. CoffeeScript's class syntax compiled down to the correct prototype chain but looked like any other class-based language:

class Cart extends EventEmitter
  constructor: (@currency = 'USD') ->
    super()
    @items = {}

  add: (product, qty = 1) ->
    @items[product.id] = qty
    @emit 'change', @snapshot()

This was genuinely cleaner code than the ES5 equivalent. For a team coming from Ruby and Python backgrounds, it was also immediately legible.

The Build Step Problem

The cost was a build step. Shipping a JavaScript library meant compiling CoffeeScript to JavaScript as part of the build process. In 2010 this was more friction than it sounds.

npm had no standardized build convention. Makefiles were the common approach. The published npm package had to include the compiled JavaScript — you could not require CoffeeScript compilation in the end user's install process. This meant maintaining both the .coffee source files and the compiled .js output in the repository, which created confusion about which files to edit.

Source maps did not exist in their modern form in 2010. When an error occurred in the compiled JavaScript, the stack trace referenced line numbers in the compiled output. You had to manually map those back to the CoffeeScript source. Debugging errors in production was measurably harder.

Why We Moved Back

By 2012 the JavaScript ecosystem was moving fast. Node.js was maturing. The CommonJS module system was becoming standard. The browser module problem was being addressed by Browserify. AMD and RequireJS were competing for the browser module spec.

All of this tooling assumed JavaScript. CoffeeScript files required additional toolchain support at every step: editor integration, linting, testing, documentation generation. As the JavaScript ecosystem developed its own solutions to the problems CoffeeScript had solved — ES6 brought arrow functions, destructuring, template literals, and class syntax — the CoffeeScript advantage shrunk.

The tipping point was new engineer onboarding. Developers joining the team in 2012 knew JavaScript. Most of them did not know CoffeeScript. The productivity gain from CoffeeScript syntax was smaller than the productivity loss from the learning curve for developers who already knew JS.

We migrated the SDK back to JavaScript in stages across 2012 and 2013. The migration was mechanical — CoffeeScript's compiler is deterministic, so compiled output gave us a starting point — but it took real time.

The Honest Assessment

CoffeeScript was the right choice in 2010 for a team writing a lot of Node.js and browser JavaScript with ES5 constraints. It was the wrong choice by 2013 when ES6 was on the horizon and the JavaScript ecosystem had grown around vanilla JS conventions.

The lesson is not that CoffeeScript was a mistake. It was a good solution to the problems of its moment. The lesson is that compile-to-JavaScript languages are bets against the rate of JavaScript's own improvement, and in the early 2010s, that rate turned out to be faster than expected.