.oooooo.     ooooo   ooooo     ooooooooooooo 
   d8P'  `Y8b    `888'   `888'     8'   888   `8 
  888             888     888           888      
  888             888     888           888      
  888     ooooo   888     888           888      
  `88.    .88'    888     888     o     888      
   `Y8bood8P'    o888o   o888ooood8    o888o     
___ ____ ____ _  _ _  _ ____ _    ____ ____ _ ____ 
 |  |___ |    |__| |\ | |  | |    |  | | __ | |___ 
 |  |___ |___ |  | | \| |__| |___ |__| |__] | |___ 
                                                    
        

At CodeConf, I gave a quick lightning talk about one of the products of our recent Hackathon.

It turns out, naming things is really hard (one of the two hard things in computer science). When we went to name our project, pressed for time, we went for the most topical thing we could think of at the time. Thus, charlie_sheen_service was released to production at about 1 am.

charlie_sheen_service has one endpoint, blather that is a live feed of orders with some MSA data.

The service is polled by it’s one client, Warlock. Warlock is a map that displays the orders as the come in real-time. A marker shows where orders are coming from on the map, and as more come in the radius of the marker expands. As the average price of that MSA increase, the color of the marker changes. Images of the products are spewed forth from the map as they come in. The whole thing is winning.

Warlock is built in CoffeeScript and a great JS library called Polymaps.

It’s often displayed on a large monitor in our office.

Yesterday Jeremy Ashkenas came by Gilt to talk about CoffeeScript, a language he’s been working on since 2009. CoffeeScript is a simple language with syntactic roots in Python and Ruby. It compiles into JavaScript and adds interesting features including array comprehensions. CoffeeScript is arguably more readable than JavaScript.

Jeremy gave a great overview of CoffeeScript and who is using it. He gets into detail on the Syntax of the language and also discusses its implementation and how to go about creating your own language.

Gilt’s JavaScript Templating Architecture

Templating is a powerful way of separating concerns on the front end. It’s a natural fit for Gilt’s platform, since much of our content comes to the front end from services that return JSON. Sometimes that JSON is rendered in JSPs with JSTL, but sometimes it’s better to render it with JavaScript.

Until recently, most JavaScript HTML rendering involved messy string concatenation, lots of looping, and an unholy marriage of logic and content in the same file. However, new templating engines, such as Handlebars, allow multiple logic-less templates to be created for the same content, with clean, easy-to-read syntax. Compare:

But which template engine to use? There are many currently vying for prominence. I didn’t want to hitch our wagon to any one engine, since many different pieces of Gilt code need to make templating calls and none of us knows the future, so I decided to create a middle tier API that would accept any templating engine as a plugin. This is generally a good way to approach front end architecture, as it’s all too easy to scatter third-party dependencies throughout a large codebase, leading to difficult maintenance and requiring significant restructuring if the third-party code ever needs to be changed.

What It Is

There are three components in addition to the implementation code:

  • Gilt.Template, which exposes render(), register(), plugin.add() and plugin.get() methods
  • a template file saved using a directory and file naming convention
  • the chosen rendering engine code

How It Works

  1. Templates are stored in a Gilt.Template private cache, by a unique combination of name, engine, and version. Name is typically the type of feed or data that is being rendered, such as a wait list, a single product feed, or a cart. Version indicates which view of the data is required (“default” is the canonical view, and views can exist for third-party sites or other areas on the Gilt site such as a modal window or a specific page). Engine indicates which third-party rendering to use, with Handlebars as the default if none is specified.
  2. For flexibility, all rendering is asynchronous. The render() method does not actually write any markup; instead, it supplies the rendered markup to a passed callback function. This allows the template file or rendering engine to be lazy loaded at the time of invocation, rather than be already present on the page, and it recognizes that often the rendered template is needed for purposes other than writing immediately into an element on a page.
  3. Each template engine is an equal citizen, registered as a plugin with Gilt.Template. Handlebars and Dust are built-in, as we use both of them on the Gilt site; however, any additional template engine can be registered and used. Each plugin must provide a render() method, and optionally can provide a register() method (used, for example, in Dust compilation). When the implementation code calls Gilt.Template.render(), that method delegates to the plugin’s render() method.
  4. If the template is not available in Gilt.Template’s cache, it triggers an asynchronous load of the template file, looking by a naming convention of /templates/<type>/<version>.<engine>.js. For example, a template that handles the default view of a wait list feed using Handlebars would be stored at /templates/wait_list/default.handlebars.js. This convention allows for multiple views of the same data feed. Gilt.Template.render() takes an optional argument for an ajax service to use, with jQuery used by default. This allows for the possibility of use with a different base library, since this is the only point of third-party dependency.

How To Use

So, the three steps required to use the system are:

  1. Add a plugin using Gilt.Template.plugin.add() with the specific code required to interact with the chosen third-party templating engine. Handlebars support is built-in and, for reference, looks like this:

  2. Register a template with Gilt.Template.register(), indicating a unique combination of name, engine, and version. This could be done prior to calling render(); if not, render() will lazy load this template file, thereby calling register():

  3. Call Gilt.Template.render(), passing it the unique name, engine, and version to render, along with a callback to be provided with HTML. The render() method will load the plugin and call register() first if the template is unavailable. The following code is probably in the callback of an ajax request function:

tl;dr;

In summary, Gilt.Template:

  • allows for template storage by engine, version and name;
  • provides flexibility by providing rendered markup to a callback function;
  • treats all templating engines equally; and
  • speeds up page load by asynchronously loading template files.

Templates have helped us to separate our content data from its views on the site, and our middle tier architecture has provided a consistent API and eliminated the need for third-party calls in the Gilt codebase.

Asynchronous Specs

While working on TestSwarm, we ran into the problem that none of the javascript testing frameworks out there had really solved the problem of how to test asynchronous behavior without requiring the test writer to do something different from how (s)he would test non-asynchronous behavior.

e.g. Testing these two lines should be done the same way:

callThisImmediately(function () {});
callThisIn5Seconds(function() {});

Every other testing framework we looked at required using something like wait() and resume(), or mock timers, or completely ignored the problem.

So… I decided to write my own testing framework, with testing asynchronous behaviors (like ajax requests, animations, countdowns, timeouts, etc) in mind from the very beginning. Since we also have a lot of Rubyists here, we wanted the syntax to be as close to RSpec as possible.

Thus was born ASpec:

ASpec

For the most part this was fairly straightforward, but there were two itty bitty little problems. The first was of course… how does ASpec know that there is asynchronous behavior? And two, what should it do about it?

We solved the first one using a little regex and Function.prototype.toString(). Simply put, ASpec counts the number of expects in an it block before it executes that it block. when an expect gets executed, we count that too. When we exit the it block, if the two numbers aren’t the same, well, chances are that there was asynchronous behavior. Either that or unreachable code, conditional statements, or a good old runtime error.

As for the 2nd problem, we solved that too. If we have any pending expects, everything after that gets put into a queue, and is executed after the pending expect is done. Or times out.

When everything is done, we wind up with a nice little report that TestSwarm can take a screenshot of:

ASpec Test Runner

Well, that’s okay (sorry about the purple), but if I’m testing something, I’d rather not have to leave the command line in order to do so. Not to mention, I’d like to have a way to test all my specs at once. And of course, I’d like to be able to test everything before I commit.

Therefore, we created a little rake task: rake spec. If you’re a Rubyist, it probably sounds familiar.

Our version of rake spec even produces output similar to the RSpec version:

ASpec rake tasks

If you peek under the hood, what you’ll see is a couple simple minded tcp servers, and the Mac OSX open command (with the --background flag).

And of course, since we want to be able to test in different browsers, we can run rake spec:firefox, rake spec:chrome and rake spec:safari. Sorry, IE.

Kevan Davis Gilt Groupe

Continuous Integration for JavaScript with TestSwarm

We like the principles of Test Driven Development (or some variation thereof). But we also have an increasingly large JavaScript library, and JavaScript testing is hard.

There are tools like Selenium that offer a full testing suite and there are tools like Webrat that simulate a browser for application acceptance testing, but those tools still don’t solve the “JavaScript testing is hard” problem. That problem is browsers.

John Resig and team ran into this problem while developing jQuery:

The end result is that we need to run 10 separate test suites in 12 separate browsers before and after every single commit to jQuery core. Cross-Browser JavaScript testing does not scale.

That blog post really defined the problem. We Front End Engineers needed some Continuous Integration love: An automated way of testing our JS libraries across multiple browser environments.

Resig also came up with a solution to the problem, and we’ve recently rolled it out here at Gilt: TestSwarm.

TestSwarm provides distributed continuous integration testing for JavaScript.

Users (on various browsers) connect to the server and run the test runner. The runner will wait for new suites to come in from a git hook.

The results are recorded for each commit and hopefully everything is green.

And now we have to begin the hardest part of this task: beginning a TDD practice and making sure our JavaScript has full test coverage.

Mark Wunsch Gilt Groupe