Testing and Node: Building a Toolset

| Comments

This is part two of a series on testing and Node; check out part one, Why do we test.

Despite Node.js’s relative youth, there’s already a vast ecosystem of tooling surrounding end-to-end application testing. But the bounteous availability of tools isn’t as positive an aspect as it may appear; many tools lack maturity, while others have gone beyond the point of maturity to abandonware. Choosing the right testing toolset when starting a new Node project can be daunting, and can be enough to discourage you from testing in the first place.

Don’t delay. Don’t put off. Follow the advice of the excellent Growing Object-Oriented Software, Guided by Tests and set up your test infrastructure when you first set up your application.

Today, we’re going to go step-by-step through creating a new Node app and its accompanying test toolset. Over the rest of the series, we’ll walk through writing a feature from the outside-in.

Let’s get started. Create a new directory for this project; I created one called testing-and-node. cd in and then npm init. If you haven’t used npm init before, it just asks a series of questions to put together a package.json file for you. Fill in whatever answers you want, but when the script asks for the “test command”, make sure to enter grunt test.

Speaking of which… you do have Grunt installed, right? Grunt is a fantastically powerful build tool for JS projects. While some developers prefer the power and unix-ness of Makefiles, and Rubyists long for Rake’s API, Grunt has a comprehensive ecosystem of tasks that’s growing daily. And since you’re coding in JavaScript, you might as well write your build tasks in JS, too.

If you are new to Grunt, you’ll need to install the cli module for use globally:

1
npm install -g grunt-cli

Next, install a local version of Grunt itself:

1
npm install --save grunt

Great. Grunt relies on the presence of a file called Gruntfile.js to configure and run builds. Let’s set that up now. Open a new Gruntfile.js file in your editor and enter the following:

1
2
3
4
5
6
7
module.exports = function (grunt) {

  grunt.initConfig({

  });

  grunt.registerTask('test', []); };

Go ahead and run npm test. It’s green. Hooray! Yes, it’s true your tests don’t currently do anything, but now you’re free to start setting up the rest of your toolset. Let’s install them in one bunch:

1
npm install --save-dev mocha sinon chai sinon-chai grunt-mocha-test grunt-mocha-webdriver

And if you’re a fan of promises, you might as well install the following right now:

1
2
npm install --save Q
npm install --save-dev chai-as-promised

We’ll also need to install a tool that’s not a Node module: PhantomJS. You can install it with Homebrew if you’ve got it; otherwise, there’s binary installers here. If you already have Phantom installed, just make sure it’s on the latest version.

Let’s go over the selection of each of these tools. There’s certainly other sets of modules that would work equally well, but this is the toolset with which I’m most familiar, and the one for which I’ll advocate.

mocha http://visionmedia.github.io/mocha/

There’s a wide variety of testing frameworks available for Node, from the extraordinarily comprehensive (Jasmine) to the extraordinarily minimal (node-tap). Mocha fits neatly in between these two extremes; its one role is to run tests, and it’s agnostic about output, assertion library, and even interface-style (the only thing Mocha isn’t agnostic about is promise support). Mocha’s best feature is its ease of async use; supply a test with a callback, and it will be run asynchronously.

1
2
3
4
5
6
7
8
9
10
11
12
describe('a sync test', function () {
  it('is run synchronously', function () {
    //assert something synchronous
  });
});

describe('an async test', function () {
  it('is run asynchronously', function (done) {
    //do something async
    done(err, result);
  });
});

sinon http://sinonjs.org/

Since Mocha simply plays the role of test-runner, we need other components to complete our testing toolset. Sinon is a framework-agnostic library that provides spies, stubs, and mocks for JavaScript (Martin Fowler provides a useful explanation of those terms). Spies, stubs, and mocks are integral for properly testing the interfaces through which your application objects communicate; Sinon makes it simple to verify how any function is called, and can even indicate whether a function has been new-ed.

chai chaijs.com

Completing our main set of testing tools is chai, a framework-agnostic assertion library. Node provides its own assertion api directly in core, so it’s not strictly necessary to include a third-party assertion module. But Chai provides a choice of excellent APIs, with error messages that should make the path from red to green much clearer. I’m personally partial to Chai’s expect bdd interface. Another benefit of Chai is that it provides an easy mechanism for adding your own assertion language, which has led to assertion-plugins like sinon-chai and chai-as-promised.

sinon-chai http://chaijs.com/plugins/sinon-chai

I’m a big believer that cleaner APIs lead to better code; while it’s perfectly acceptable to test Sinon object properties directly, the sinon-chai plugin makes your tests even clearer. Instead of:

1
expect(mySpy.calledWith("foo")).to.be.ok;

you can just write:

1
expect(mySpy).to.have.been.calledWith("foo");

Since you’re going to the trouble of using an expressive assertion library, it makes sense to make those assertions as clear as possible.

chai-as-promised http://chaijs.com/plugins/chai-as-promised

For promise-users, chai-as-promised provides the same benefits as sinon-chai: more expressive test assertions. Instead of chaining a promise onto the subject of your test to verify the eventual resolution or rejection, chai-as-promised allows you to use the same chaining-API as the rest of Chai:

1
expect(promiseFn({foo: 'bar'})).to.eventually.deep.equal('foobar')

grunt-mocha-test https://github.com/pghalliday/grunt-mocha-test

Because Mocha can be run on both the client and server, there’s a surprisingly large number of Grunt tasks that use the testing framework; I prefer grunt-mocha-test because of its extreme simplicity. grunt-mocha-test uses the same options hash as Mocha itself; in fact, all it’s doing is firing up processes with which to run Mocha instances. Of course, running those instances properly, and catching any weird exceptions, is harder than it sounds — grunt-mocha-test has figured out those fringe cases so you don’t have to.

grunt-mocha-webdriver https://github.com/jmreidy/grunt-mocha-webdriver

When it comes down to full-stack (aka acceptance or end-to-end) testing, you’ll need a headless browser with which to interact. PhantomJS, which we’ll get to below, provides a headless WebKit browser, but what if you want to run your acceptance tests against more than just a (fake) instance of WebKit? What if you want to know if your application will work on mobile browsers, or legacy versions of IE? That’s where SauceLabs comes into play; it provides an IaaS for testing against any matrix of browsers and devices.

grunt-mocha-webdriver allows you to write and run Mocha tests as you normally would, but with one huge benefit — it automatically inserts a WebDriver/Selenium interface into your tests for you. With grunt-mocha-webdriver, you’ll be able to run a single acceptance test against PhantomJS locally, and then run against a whole suite of browsers on SauceLabs when you deploy to your CI environment.

If all of that sounds incredibly confusing now, it will make more sense in a future post in this series.

PhantomJS http://phantomjs.org/

PhantomJS isn’t a Node module; it’s a headless WebKit browser. Traditionally, the interface through which you’d interact with Phantom would be a JavaScript API, and it was notoriously tricky to setup and integrate into the rest of the testing stack. All that changed with PhantomJS’s 1.8 release, which included Ghost Driver, a pure JavaScript implementation of the WebDriver / Selenium Wire Protocol. With new versions of PhantomJS, you can run:

1
phantomjs --webdriver=4444

That will keep an instance of Phantom running in the background, against which you can run your tests via grunt-mocha-webdriver.

This whole process will be explained more in a later post in this series.



And with that, we have a working testing toolset. We’re ready to build — which we’ll start doing in the next post.

Testing and Node: Why Do We Test?

| Comments

Why do we test our code?

The question itself seems sacrilegious in today’s developer culture. Admitting that you aren’t building a comprehensive suite of unit and integration tests, let alone not testing first, amounts to hanging a giant “newb” sign around your neck. But sacred cows in any culture can lead to stagnation and a lack of innovation; if you can’t provide good cause for a practice that’s demanded of you, why bother doing it?

I’ve worked on a number of different projects, spanning maturity levels, technologies, and team sizes. While most have employed some degree of testing, I can’t think of a single one that employed what would be considered a “robust test suite”. Certainly, open source libraries to which I’ve contributed (and the ones I’ve created) have almost all included solid unit test coverage. But there’s a gap between what many product teams and consulting agencies preach (“We test all our code all the time, and only want developers who believe in testing!”) and what they practice (“We’ve got to get this feature out the door, forget the tests for now.”).

What makes the testing question more complicated is that you can never fully-automate your way to safety. No matter how comprehensive your tests, you’re going to need a QA team. The most glaring need for QA is the fact that you can’t test the appearance of an app — and with the rise of the responsive web, testing appearance (and by extension, usability) becomes even more important. If you need to spend resources on QA-ing an app anyway, why should your development team spend extra time writing tests (or testing first) when they could instead be building features or fixing bugs?

The most compelling answer I’ve found to this question comes from Sandi Metz in her book Practical Object-Oriented Design in Ruby. It’s probably not surprising that a strong case for testing comes from a Rubyist; the Ruby community has been loudly preaching test-first Agile methodologies for years. But Metz articulates ideas in a way that increases their poignancy. “Tests give you confidence to refactor constantly,” she writes. This idea takes the common catchphrase of testing — “red, green, refactor” — and turns it on its head. Instead of refactoring being a part of testing, refactoring becomes the point of testing. “The true purpose of testing,” Metz argues, “is to reduce costs.”

As a Node developer, the idea that testing provides you freedom to refactor is entirely compelling. As I wrote in my article on using private Github repositories for web application submodules, Node developers are constantly on the prowl to refactor common bits of logic into their own encapsulated components. By test-driving feature development, you make it significantly easier to break out common modules:

  1. Test from the outside in: integration, then unit 2. Implement the feature (make the tests pass) 3. Isolate code that’s useful elsewhere, break it off into its own module, confirm the tests still pass.

In Node-land, “red-green-refactor” becomes “red-green-refactor-publish [module]”.

Further, building proper test coverage may require some additional time from your development team, but it should also decrease the pressure on your QA team — and help everyone involved by reducing coordination costs. Think of a scenario in which one developer bumps up an application dependency to a newer version in order to implement a new feature (or fix a bug). The developer sanity checks the application to see if the new version causes any problems elsewhere in the app; finding none, the updated dependency is added to the app’s manifest and deployed. A week later, a bug report comes in that’s vetted and validated by a member of the QA team, who then needs to coordinate with multiple developers to identify the cause of the bug (a regression from the bumped dependency), fix it, and confirm the fix. The cost of coordinating a fix to this regression clearly outweighs the cost of writing tests in the first place, and this scenario is of the sort that automated testing can easily address. In the Node ecosystem, where we frequently rely on many small third-party modules, it’s especially important to automatically test that our integration with these modules is always working.

But testing can’t reduce costs if we aren’t efficient testers. And being an efficient tester is only partially dependent on your knowledge of good OO design; it is equally important to have a full and proper understanding of the tools with which you need to test.

Which brings me to the point of this post. The Node community has a very effective toolbox for testing first, testing well, and testing comprehensively. But despite the capabilities of these tools, there’s very little discussion on the web of how to use them. An introduction to Mocha or Jasmine doesn’t really explain how to use them to TDD a Node app, and it certainly doesn’t explain how to integrate these libraries into a continuous-deployment setup with Grunt.

In the next few posts, I’ll be stepping through my own “best practices” for testing a Node app. I’ll be the first to admit that there are probably better approaches to testing, and I’ll be quite happy to receive feedback, but hopefully this series can serve as a guide to get the Node testing discussion started. If there’s anything you’re particularly curious about, please let me know and I’ll try to address it.

Private Github Repos With NPM & Heroku

| Comments

As you spend time coding in the Node.js ecosystem, you become increasingly reliant on small modules, both consuming them and building them yourself. This habit of building and composing modular toolsets begins to extend beyond library code, and you start to think of web application code as a collection of modules. Data models, for example, can be easily packaged into a separate Node module for re-use in related applications (and to chunk off a set of application dependencies).

Seeing code that can be broken off into its own module, you dutifully follow your Node.js instincts, break off the code, and move it to its own directory. You create a new private Github repo for this small module, and push it up. But how do you re-integrate this new (actively developed) sub-project back into its containing projects?

NPM has always made it easy to manage Node modules as Git submodules. The NPM submodule command will add a package dependency as a Git submodule, and from then on will basically ignore the containing folder, letting you update and modify the package as you will. There’s also NPM’s link command, which will install a package dependency from a symlink on your development machine rather than from the npmjs.org repository.

But when it comes to the common use case of deploying a web app with a Git submodule package to Heroku, things get complicated:

  1. Your submodules are private Github repositories, so you need to get access to them without sacrificing account security;

  2. Assuming you get around the first challenge, Git submodules are autotomatically installed on Heroku deploy, and then NPM will stubbornly refuse to install the submodule dependencies;

  3. If you’re using npm shrinkwrap to lock down your app dependencies, the presence of Git submodules or linked directories screws up the shrinkwrap metadata and makes install difficult.

There’s a very specific approach you need to take to work around these issues.

First, there’s the account security issue. HTTPS access to your Github repositories allows you to use a username and password instead of an SSH key, but then you’re putting your account credentials in plaintext – an obvious problem. Thankfully, you can use Github’s OAuth token support to better secure your repositories. Follow Github’s instructions for creating a token with “repo” scope. Then, in your package.json, add the following for your submodule:

1
  "package-name": "git+https://<github_token>:x-oauth-basic@github.com/<user>/<repo>.git"

Great! Now you’ve got an installable submodule that can be deployed to Heroku and/or shrinkwrapped without a problem.

But if your module is changing frequently (e.g. its under active development along with its parent project), you probably want a “live” version of the code in your project folder. Using a Git submodule solves some problems but introduces others. The best approach is to use npm link to link a checked-out copy of the submodule from elsewhere on your filesystem.

Sadly, link-ing to a project will cause problems for you if you use npm shrinkwrap. Shrinkwrap tracks the origin of each node module, and when you link, you lose that nice OAuth-ified Github url. There’s only one way around this problem, and while it feels a bit hacky, it works. Add that git+https url from above (the one with the OAuth token) to a _from field in each submodule’s package.json. shrinkwrap will defer to this field whenever it’s run.

So the succint list of steps:

  1. Create a Github OAuth token.

  2. Add Github module dependencies to your main app’s package.json file with the URL scheme specified above.

  3. Add the same URL to your submodule packages’ _from fields.

  4. npm link the submodules if you’re actively working on them.

  5. Deploy to Heroku as normal and everything will just work.

…Hopefully.

In Theory, Not Practice

| Comments

In my previous post, I wrote about the quest towards unifying web application architecture around a single shared codebase. Airbnb’s Rendr library provides one path forward on that quest. In this post, I’d like to provide a high-level explanation of my own solution for unifying application code.

There’s a few segments of an application’s code that will almost certainly be repeated on both the client and server: views, view state, and data models (excluding data access). To a certain extent, routing could be repeated as well; if you’re not using hashbangs, you’ll need to implement the same named routes on the client and server (although the actions you perform for those routes will be dramatically different).

The solution I’ve put together is still a work in progress, and is more a set of practices and conventions than a library. This flexibility means that while I’ve been implementing the approach using Handlebars, Backbone, and Express, you could theoretically use a completely different set of libraries. In this post, I’ll go over the basic ideas behind my approach; I’ll be putting together a sample implementation on Github that I’ll be able to write about in more detail in the future.

Unifying View Templates

Sharing template code is perhaps the easiest step towards achieving web application unity. With a full-JS stack, you’re compiling the same templates for rendering both server-side and client-side. So why not use the same templates for each?

In my experiments, I’ve been using Handlebars as my templating system. It’s based on the Mustache syntax, but has a number of powerful features, including partials and custom helpers. Handlebars is also the templating system behind Ember.js.

The key to sharing templates is the realization that what constitutes a “partial” can be relative to where the template is used — that is to say, the same template can be used as a full template on the client, and a partial template on the server. My templates are divided into three groups:

  • client – client only templates
  • shared – used on both the client and server
  • server – server only templates

For the client, the templates in the client and shared folders are pre-compiled in a Grunt step, so for all intents and purposes there’s a single flat collection of templates. The server, however, references all of the templates in the shared folder as partials. What’s more, view helpers (in this case, special Handlebars tags) are stored in a shared/helpers directory that is referenced by both the client (in a Grunt step) and the server.

If you’re confused now, you won’t be when you see the actual implementation in my next post. What sounds complicated here is quite straightforward in practice.

Populating View Templates

If it’s easy to share templates on the client and server, getting the right data into those templates is a bit of a harder proposition. Handlebars renders data by running the template against a “context”, which is just a plain old hash. But how can we make sure that the contents of that hash are synchronized when rendering the same view on both the client and server?

The problem is exacerbated with how Backbone muddles view rendering logic. In Backbone, there’s not a fine line between the View logic (in Backbone.View) and Model logic (in Backbone.Model and Backbone.Collection). Backbone Views end up performing view state management by manipulating model instances, in order to avoid bloating Models with View specific code. But adding stateful logic into a Backbone View causes two problems:

1) it makes for larger, more complex views, as concerns are split between UX event management and controlling model state;

2) it makes it harder to share code with the server, as rendering state gets locked in a Backbone view.

We can get around these problems by reconsidering the role of a Backbone View — separating its concerns into that of Mediator and View Model. The Mediator role is one of event manager and template marshal; the view model is, most basically, a state controller.

By splitting the state controller into an object of its own concern, you can extract the logic into a module that can be shared by both the client (via Browserify) and the server (via require). The Backbone Mediator simply invokes the View Model, declaratively calling functions on it as users interact with the app — transitioning Backbone away from its traditional role of MVC framework into more of an MVVM implementation.

A View Model just returns a hash with the current state of data, which is supplied to the template. On the server, a View Model is instantiated with data accessed from the backend; the results of the View Model instance’s toJSON method are passed to the template for rendering. On the client, the same pattern is repeated, but the data is accessed via AJAX instead.

Sharing Models on Client and Server

Synchronizing model code on both the client and server is perhaps the hardest step towards achieving web application unity. The challenge primarily derives from a characteristic of Model code that we’ve inherited from the Rails world: specifically, a conflation of Model concerns between “data model object” and “data access object”. A data model object should identify a model object’s properties, its getters and setters, its relationships, and some convenient accessors; a data access object should deal with querying data sources for populating the data model objects.

Unfortunately, Backbone follows in the tradition of Rails’ ActiveRecord, flattening data accessing and data modeling into a single object. This flattening causes problems even beyond unifying a web application stack. How many Backbone applications have you seen that globally override the sync method, and use properties on model classes to determine how sync invocation works? (Not to pick on Backbone; it’s just the web application framework with which I’m most familiar.)

For now, I’ve abandoned trying to get Backbone Models and Collections to work on both the client and server. But there’s alternatives that can fill the gap nicely. The first of which I’m familiar is Dan Dean’s Tubbs library. Tubbs provides a DSL for defining data model objects, but also provides a pluggable dataStore. A single model module can be defined in a shared folder, and then required on both the client and server, with both supplying their own dataStore.

In order to make the separation between data modeling and data accessing even clearer, and the sharing of model code on the server and client easier, I created by own voltron-model library. While Voltron isn’t ready for primetime (yet), it should make the unified definition of data models significantly easier.

Whichever modeling library is chosen, the basic approach should be the same: data models are defined in a shared folder. These models are then imported by code on the server (or packaged with Browserify for the client). The server and client should decorate the models appropriately (either by adding to the model’s prototype or adding an accessor component). Thus, a model can be made to access Mongo or Postgres on the backend, or a REST service on the client.

The benefit of using Backbone on the client is that it doesn’t care if you only use limited parts of the library. Arrays of event-emitting models can provide much of the same benefit of Backbone Collections and Models, and Backbone Views and Routers see no difference.

Wrapping Up

All this discussion may be a bit confusing without a concrete implementation to reference; hopefully, I’ll be able to put together a sample application in the next few weeks. But the basic takeaway of the post is that unification of JS web applications can be made significantly easier with two factors:

  • structuring your code so that it can be required by the server or packaged for the client in the same ways, whether by ingesting templates as partials or packaging code with Browserify;

  • following the Node.js approach of writing small, single-purpose modules means that there’s less boilerplate to prevent you from using code in multiple environments

Towards a Unified JS Stack

| Comments

It’s been a long time since I’ve written anything for this site. Neither neglect nor procrastination prompted my absence, but rather, lots and lots of coding. All that code has left me with a surfeit of topics to cover here, so instead of talking about what I’ve been working on, I’m going to dive straight into the good stuff.

I want to write about the current “Holy Grail” of web application development: a unified application stack. Any dev who’s built a thick-client web app (regardless of library – Ember, Backbone, this problem is independent of tool choice) has dealt with the frustration of recreating logic in multiple parts of the application stack. It’s incredibly annoying to be writing the same code to handle model accessors, view state, and rendering logic in two different places; it’s even more irksome to be fixing bugs in one or both areas as your application matures. But let’s back up a bit. Why do we need to be writing the same logic in multiple places at all?

Generally speaking, modern web app development requires a choice from one of three architectural thrusts:

  • thick server, thin client: view logic is written on the server, and rendering happens there as well. The client code deals with interactivity and AJAX requests, but is mostly just updating areas of the page with rendered view content returned by the server. This approach is most famously advocated for by 37 Signals. A thick server simplifies view code, but does so at the expense of larger AJAX payloads; why pull fully rendered code when you can just pull JSON data and render it with a client-side template?

  • thick client, thin server: This architecture inverts the first approach; the server provides an API, which is basically just a wrapper around data access and caching. All of the app logic resides in the client. This approach can make for quick interactivity and rendering on the client, but presents a massive problem with “first load” delay, as the client needs to make two connections to the server: the first to load the client application code, and the second to pull the appropriate data to render. You may remember this problem from Old New Twitter.

  • thick client, thick server: Unsurprisingly, this approach combines both of the previous options. Views are rendered on the server, which means the initial load is fast, but the client handles all the rendering from that point forward. The good news is that you have two fairly independent, (hopefully) highly performant application structures; the bad news is that you’re now repeating logic in view templates, view states, model helpers, even route handlers.

One exciting prospect of Node.js is that it makes Javascript an “isomorphic language”, which is to say that “any given line of code (with notable exceptions) can execute both on the client and the server” (h/t Nodejitsu). But that said, there haven’t been very compelling demonstrations that solve the code-duplication problem.

In the last few months, I’ve come up with a solution that allows for code reuse on client and server, leading to a unified codebase for handling view rendering, view states, and model interaction. It’s using components and libraries that you already know: Browserify, Backbone, Express, and Handlebars. But I’m going to hold off on describing that solution for now, and instead write about Rendr.

Rendr is the result of Airbnb’s first Node app, and it’s also the library that finally prompted me to close Vim and start writing here again. It’s the fulfillment of an idea that I first heard about from Tim Branyen: what if we used Express to render the same Backbone Views that we render on the client? That question is what prompted me on my own path towards application stack unity, so I’ve been very eager to learn more about Rendr.

Rendr took Tim Branyen’s initial idea and made it a reality. It’s important to note that Airbnb’s experiments here weren’t an excuse for architecture aeronautics; rather, they were expressly concerned with solving the “time to content” problem, which is to say, the rendering delay that Twitter famously faced. And by unifying client and server code, Rendr not only makes developers’ lives easier, it solves that time to content problem.

Rendr has a number of features and design approaches that I very much like:

  • it’s described as “a library, not a framework”

  • it doesn’t create a server side DOM

  • it doesn’t try to collapse backend data access into the client tier, as some other frameworks have done

  • it utilizes existing, familiar code (Express and Backbone)

  • it keeps the rendered DOM on first load and attaches client objects to it, rather than instantiating client views and replacing the DOM with the results of those client views.

This last item is particularly important: rendering a page on the server, sending it to the client, and then recreating the DOM on the client can lead to odd rendering issues, interactivity problems, and problems with event listeners. But dynamically instantiating client objects and attaching them to an already-rendered DOM is not a trivial problem, and I commend Spike Brehm and the rest of the Airbnb team for taking the time to get this right.

You should definitely take the time to explore Rendr’s codebase. If it existed when I first set out to solve this same set of problems last year, then I probably would’ve abandoned my own quest and just used this library. But the key point of differentiation with the approach I took from Rendr’s design is modularity. Is it possible to achieve application stack unity, while using objects and code that can be implemented with any number of frameworks in any number of ways?

Stay tuned.

Error Isolation With Promises

| Comments

The entirety of the Javascript and Node.js universe is based around a continuation-passing coding style — that is to say, callbacks. This style of async coding greatly aggrevates Node critics, who constantly argue that continuation-passing invariably results in “callback hell” spaghetti code for any non-trivial problem. Node.js proponents respond that continuation-passing presents an easier mental model for async coding than alternative approaches, and that properly abstracted code avoids any gross “chains of doom.”

This post has nothing to do with that argument.

If you’re coding in Javascript, you’re going to be using callbacks, and if you’re building a library, you’re going to be supporting callbacks. It’s the reality of the ecosystem. But there are certain problems for which some syntactic sugar is helpful. Promises provide a wrapper for callbacks that allow for a chainable API around a sequence of continuations. They’re not a native part of the language, but there’s a strawman for the inclusion of Promises in a future version of JS. In the meantime, you can use the excellent Q Library from Kris Kowal. jQuery includes its own Promises implementation ($.ajax calls return Promises), but they’re slightly divergent from the Q spec. You can read this excellent guide explaining the differences between jQuery and Q promises, if you’re coming from one direction or the other.

So much for introductions. I’ve been using promises for awhile now in some of my Node code, and there’s several cases where their inclusion can clean up an API. (One area: Mongo integration, where any simple action can require several callbacks.) One benefit of Promises is that they can provide exception isolation, just like continuation-passing. The Q wiki provides the following example:

1
2
3
4
5
6
7
var info, processed;
try {
  info = JSON.parse(json);
  processed = process(info);
} catch (exception) {
  console.log("Information JSON malformed.");
}

In the above snippet, errors generated from the parser and the process function arne’t isolated. Promises, meanwhile, offer this exception isolation out of the box:

1
2
3
4
5
6
7
8
var processed = Q.call(function (json) {
  return JSON.parse(json);
})
.then(function (info) {
  return process(info);
}, function (exception) {
  console.log("Information JSON malformed.");
})

In the second example, the process function is only executed if JSON.parse doesn’t throw an error. Conversely, this same goal could be achieved with continuation-passing:

1
2
3
4
5
6
7
8
9
var processFn = function(cb) {
  asyncJSONParser(json, function(err, info) {
    if (err) {
      console.log("Information JSON malformed.");
      return cb(err);
    }
    cb(null, process(info));
  });
};

One caveat is that when you’re chaining your promises together, the behavior is slightly different than you might expect:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var existingUser;
var promise = User.findOne({username: username})
  .then(function (user) {
    if (!user) {
      throw new Error("Username is incorrect");
    }
    existingUser = user;
    return User._hashPassword(password, user.get('salt'));
    }, function(error) {
      console.error('error in findOne');
      throw error;
  })
  .then(function (hashedPassword) {
    if (existingUser.get('hashedPassword') === hashedPassword) {
      return existingUser;
    } else {
      throw new Error("Password is incorrect");
    }
  }, function(error) {
    console.error('error in _hashPassword');
    throw error;
  });

In the above example, if there is an error in User.findOne, the error is propagated throughout the chain, which means that your console will have both error in findOne and error in _hashPassword printed. There’s no way of “breaking” from the promise chain early. But here’s the thing: you don’t have to. Unless you’re interested in transforming error objects, there’s not much point in catching promise errors in intermediary steps in the chain. So the above code would be abbreviated:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var promise = User.findOne({username: username})
  .then(function (user) {
    if (!user) {
      throw new Error("Username is incorrect");
    }
    existingUser = user;
    return User._hashPassword(password, user.get('salt'));
  })
  .then(function (hashedPassword) {
    if (existingUser.get('hashedPassword') === hashedPassword) {
      return existingUser;
    } else {
      throw new Error("Password is incorrect");
    }
  });

//later in chain or in a diffent function
promise.then(function (eventualResult) {
    //do something with result
  }, function (error) {
    //handle error
  });
}

There’s simply no point to having then failure handlers that just throw an error, since the library throws and propagates errors for you automatically. In promise chains, then, you have the benefit of isolating exceptions (only proceeding from step to step if everything is ok) without the extra semantics of if (err) return cb(err) from continuation passing.

Client-Side Testing Insanity

| Comments

Client-side unit testing is crazy.

Before you skip below to yell at me in the comments section, I don’t mean that the idea of client-side unit testing is crazy. On the contrary: we need client-side tests more than ever! With ever-increasing complexity in our frontend code, not to mention the reliance on frameworks, building a web application without client-side tests is completely inadvisible.

But the process. Ohhhh, the process of client-side testing is bonkers.

Let’s take the example of a modern Node.js web app setup. I’ve got the app’s configuration wired with grunt.js. (If you’re not using grunt, you should be!) During development, server files are watched for changes and automatically kickoff mocha tests, which display their results in the grunt console. Great!

Client-side changes kickoff their own unit tests, which of course are also using mocha for consitency in testing vocabulary. But because of the nature of client-side testing, we can’t just call require on the unit under test. Instead, we need something like the following setup:

  • requirejs for managing dependencies

  • PhantomJS for running a headless browser

  • grunt-mocha, which manages the PhantomJS process and reports test results to the grunt console

  • an HTML fixture for loading the requirejs config, the browser environment, and test files

This setup worked. It also felt downright medieval compared to the simple server-side mocha testing configuration.

I’m not the only person who’s frustrated with this process. Chris Dickinson at Urban Airship recently released Drive.js, a unit testing framework and test driver that eases some of the above configuration. But in any of the setups I’ve seen, your client-side “unit” tests feel much more like integration tests. If you need to load your entire client-side framework, load a headless browser, or even fire up an instance of your server to test a single function of your client-side code… why not just ignore client-side unit testing and skip straight to integration tests? The lack of true isolation of the system under test could lead to some frustrating false results anyway.

There needs to be a better way. I’m not looking for a lot in my testing setup:

  • I want to run my client-side tests with the same mocha vocabulary and configuration as my server tests

  • I want to isolate my tests to requiring a single file and its immediate dependencies, and testing it

That’s really it. And I think I’ve found a solution.

First, I’ve needed to refactor my client-side code to follow the CommonJS requires model. I’ve also switched to browserify from requirejs, although this switch is no longer a necessity — requirejs has introduced a new configuration option, cjsTranslate, which will wrap CommonJS defined modules. Using the CommonJS approach means that my mocha tests can require my client-side files. Great.

But the much larger problem with client-side testing is those pesky browser globals: the windowobject, the DOM itself, not to mention global code like jQuery, Backbone, etc. How can we test code that relies on the presence of those globals, without resorting to running PhantomJS?

The answer comes in two parts: jsdom, and the Node.js vm module.

jsdom provides a server-side implementation of the DOM, while the vm module provides the “global” object that we can use to provide a fake browser environment to our client-side files. While I’m still fleshing out the implementation, the results so far have drastically improved my ease with client-side testing.

Here’s how it works. In a mocha test file, instead of a strict require call, I’m using a helper (passing this, the mocha test context):

1
setupClientScript.call(this, "admin/postEdit", done);

setupClientScript loads a jsdom window, injects global javascripts (like jQuery), and wires the client-side file being tested. Here it looks in a slightly simplified form:

1
2
3
4
5
6
7
8
9
10
11
12
13
var setupClientScript = function(path, done) {
  var relPath = context.clientRoot + path;
  var self = this;
  jsdom.env({
    html: '<html><head></head><body></body></html>',
    src: context.globalScripts,
    done: function(errors, window) {
    self.clientRequires = requireClientScript(relPath, window, {});
    self.clientRequires[path] = self.clientRequires[relPath];
      done();
    }
  });
};

Remember, the client-side require can’t just inject the DOM into the file under test, it also needs to make sure the file’s dependencies have access to the DOM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var requireClientScript = function(path, window, r) {
  var script = fs.readFileSync(require.resolve(path)).toString();
  var module = { exports: {} };
  var context = vm.createContext(global);

  context.window = window;
  context.exports = module.exports;
  context.module = module;
  context.require = function(path) {
    r[path] = requireClientScript(path, window);
    return r[path];
  };
  vm.runInNewContext(script, context);

  if (r) {
    r[path] = module.exports;
    r.window = window;
    return r;
  } else {
    return module.exports;
  }
};

And that’s it. Now, any test function can call this.clientRequires to have access to the client-side file under test. No test server being spun up. No complex configuration or requirejs rewiring. No full-on headless browsers like PhantomJS. Just a single before setup call, and you can test with mocha as you normally would.

As I wrote above, I’m still fleshing out the implementation, working out the interface and fixing deficiencies. I’ll be publishing the code when things are more mature, but in the meantime I’d love to hear some feedback.

Reflections on NodeConf 2012

| Comments

NodeConf 2012 was my first real “developer” conference. I had attended conferences in the past, but because of the heavy sponsorship of industry, most had felt like trade shows or job fairs. NodeConf was advertised as a conference for developers, by developers; Mikeal Rogers, the event’s main organizer, boasted that NodeConf 2012 would feature more core committers as presenters than any other Node.js conference.

As the event grew closer, my curiosity about what NodeConf would entail heightened. Mikeal didn’t divulge a clue as to the event’s schedule, and even perusing the twitter feeds of probable speakers and NodeConf’s site on lanyard didn’t reveal any helpful intelligence. At the opening party on Sunday, a general sense of cautious curiosity permeated the crowd. No one had ever attended a conference where the schedule would be revealed in realtime (appropriately for Node); my own conference inexperience left me more curious than most.

Mikeal had revealed two details: the major themes of each day of the conference. Day 1 was structured around the world of Node; Day 2 around the power of Node. NodeConf began with Node creator Ryan Dahl reconstructing the origins of the framework from livejournal entries and blurry photos of late night coding session in Germany. But as the day continued, I couldn’t see how the talks related to each other, or what I should be taking away from them. Each of the presentations, while excellent and often inspiring, didn’t leave me with a consistent narrative. I had expected “the world of Node” to consist mostly of talks like Isaac Schlueter’s “State of Node” presentation: perhaps a roundup of the big open source projects and frameworks that dominate the Node ecosystem, and a discussion of where they were headed. Instead, talks covered everything from realtime solutions with socket.io, to the creation of a whole new language. I had started the first day of NodeConf curious, but ended it confused.

Day Two changed all that.

As one talk on the “power of Node” led into the next, the topics and structure of the first day of NodeConf started to make sense to me. Each speaker demonstrated amazing new contributions to the Node ecosystem, from the Node-inspired Luvit framework built with Lua, to bleeding edge debugging tooling with dtrace, to ridiculous hardware demonstrations featuring human-detecting arduinos, three-dimensional saws, and radar laser robots controlled by Javascript. These talks didn’t just demonstrate powerful and frequently unexpected uses of Node: they helped me make sense of the previous day’s selection of talks.

Node is not just the Node framework: it’s a philosophy, an approach to solving problems. The first inkling of “Node as philosophy” came in substack’s post on Node’s aesthetic, discussing the “limited surface area” approach to Node’s modular problem-solving. But NodeConf demonstrated that the node philosophy goes much further than that:

  1. async all of the things: Ryan’s initial work with libuv focused on the challenges of creating an async IO layer that worked across platforms, but that work has been extended with new languages like Fedor Indutny’s Candor and Tim Caswell’s Luvit framework. But it’s not just file IO – Max Ogden showed that the importance of a beautiful async API could be extended to browsers (utilizing ideas put forth by substack in day one), while Rick Waldron brilliantly demonstrated how JavaScript’s async nature could be used to solve problems which had always been approached synchronously. (Like robots. With lasers.)

  2. embrace the hard problems: JavaScript may frequently be maligned for its odd “bad parts”, and JS developers have been looked down on in the past because of the history of DOM based spaghetti code, but NodeConf 2012 demonstrated a community that was unabashed in its tackling of serious computing issues. From Felix Geisendorfer’s’s writing of a binary MySQL parser that surpassed a c library in performance, to the community’s embracing of the concept of IO streams, to the use of dtrace in debugging: Node developers on the bleeding edge are not shying away from the toughest technical problems, but instead are taking them on at full speed and with high expectations.

  3. a virtuous cycle of framework and community: Node’s “limited surface area” design of the core framework, along with the ease of use of NPM for publishing open source code and small useful modules, have led to an explosion of code. At NodeConf 2011, around 1800 packages had been published to NPM; now there are over 12000! Modules range from steaming cups of earl grey, to karaoke bar APIs, to websocket adapters and arduino libraries. The design of the framework drove its community adoption, but the community adoption has further developed the framework.

In the last talk of day two, Elijah Insua discussed the hardware hacking he’d done with Node. At one point, he mentioned that he came up with an idea that needed a midi driver, and he said something along the lines of: he never expected needing a midi driver, but as soon as he needed one, he came across one on NPM. The word that came to mind was serendipity: the contributions to Node, and the explorations of its philosophy, are feeding on themselves and driving completely unexpected innovation.

As I thought of the serendipitous nature of the Node ecosystem, Mikeal’s construction of NodeConf finally clicked for me. The two days of talks had been divided into groups of four presentations around a single theme; neither the themes nor the talks were made public, but each talk and theme bled into the next, with later speakers surprisingly stating how happy they were that a previous speaker had touched on a similar topic. The talks seemed to develop naturally, if unexpectedly; the overall direction was unclear to everyone except Mikeal, and gave the impression of the community simply exploring new ideas and pushing boundaries organically. The serendipity of Node’s development, then, found itself reflected in Mikeal’s construction of the conference. Does this sound ridiculously meta? Yes, but it completely worked.

As Node grows up and attracts adoption, it will be increasingly difficult to maintain the philosophically-driven, community-minded hacker ethos of the Node ecosystem, but I hope that Mikeal and the other stewards of the Node community can continue to foster talks and events that focus on the behind-the-scenes developers who are laying the building blocks for the future of this fascinating set of technologies.

Mastering Your Toolset

| Comments

When I originally started thinking about writing this post, I was going to phrase it in terms of spring cleaning. When I moved to Portland, I took the opportunity to reasses my development environment and to cleanup the libraries and source repositories I had scattered across my system. Since then, I’ve become the proud owner of a new retina MBP, so I’ve ended up building a new environment from scratch. Provisioning a new laptop is incredibly fast now; if you have your projects stored in version control, and you keep your dotfiles controlled as well, setting up a new laptop is as easy as:

  • installing Homebrew
  • installing iTerm2
  • brew install git, macvim, tmux, tmuxinator, whatever langs and dbs you need
  • pulling down your .dotfiles
  • installing and syncing your Dropbox

I was developing on my new machine the day it arrived.

That experience of provisioning a machine so easily, and getting productive with it in no time at all, left me reconsidiering my original post on my toolset, which primarily boils down to zsh, tmux, and Vim. There’s plenty of material online to learn about these tools; a few of note are:

So why should you adopt tools with such a steep learning curve? Most discussions of IDEs and development environments quickly devolve into pointless arguments over the superiority of one tool over another, when in most cases the tool isn’t the most important factor; differences in productivity will more frequently boil down to experience and mastery of a toolset, rather than the toolset itself. I’ve seen masters of Vim, Eclipse, IntelliJ, and Textmate; in every case, the interface breaks down and gets out of the way of the user, who always “does” without any thought as to “how to do”.

So if mastery is more important than toolset, does your choice really matter?

Yes.

There’s two huge benefits of the Vim/tmux/shell toolset: ubiquity, and permanence.

Mastery of a tool takes many, many, many hours:

So whatever tool you choose, you want to be able to use it as much of the time as possible, in as many environments as possible.

A mastery of Eclipse, for example, doesn’t help you when you need to ssh into a unix environment (but vi/m would). Knowing Visual Studio inside and out can’t help you if you need to work on a Max or Linux box (but gvim and cygwin will still work on Windows). There’s not a lot that can compete with Vim in the ubiquity category; Emacs is the only other tool that comes to mind.

Permanence is a whole other matter. Technology changes constantly; some tools are improved, others are abandoned, still others fall out of use entirely. Are you a Flex developer who spent spent huge amounts of time mastering FlexBuilder and Eclipse? Out of luck now. Textmate? The tool that influenced countless developers to leave the Windows ecosystem eventually became pseudo-abandonware, leading to the current growth of tools liks Sublime Text 2.

Vim has been around since 1991. Its progenitor vi was written in 1976. (Again, Emacs is the only competitor here, having also been written in 1976.)

All of this is to say: don’t go and abandon your current toolset for mine! Just because what I use works for me, doesn’t mean it’s the best choice for you. If you’ve already mastered your toolset and are happy with it, stay there: you’d be wasting many productive hours on a new tool for the potential of hating it. And as wonderful as Vim/tmux/shell are for most, it’s not the right toolset for everyone or everything. If you’re doing mostly front-end web UX work, for example, Coda 2 would probably be perfect for your needs; iOS means you’re going to be stuck with Xcode, for better or worse.

But if you’re feeling constrained by your current toolset, or are making the jump from one technology to another, and haven’t given “the text triumvirate” a try, I’d very strongly recommend doing so. It’s worth the effort.

Blog Bankruptcy

| Comments

If you only know me through this blog, and have spent any amount of time playing Oregon Trail in your youth, you may have grown a bit concerned. It’s been four months since my last post, in which I wrote about my upcoming move to Portland, OR; since then, there’s been total silence here. I’m happy to report that, over the course of my cross-country move, I didn’t contract dysentery, drown in a reckless attempt at fording a river, or suffer a terrible firearms accident while hunting squirrels. In fact, I had better luck with the move than I possibly could have imagined. Our drive to Minneapolis avoided any nasty weather; our flight from Minneapolis to Portland proceeded without incident; our new house was solidly intact and without any animal squatters; and our movers arrived with all of our belongings at the exactly scheduled time (to the minute!) with nothing broken or lost.

Portland has lived up to, and perhaps exceeded, our expectations. Being able to bike around a city without a constant fear of death and dismemberment has been quite a refreshing change. Living in a house has allowed us to actually grow a legitimate garden instead of stuffing a few pots in a fire escape. We couldn’t be happier with the food scene here; the amount of craft beer in Portland is downright intimidating. And it’s been extraordinarily exciting to meet so many other new Portlanders who’ve moved here for similar reasons. Needless to say, if you’re a developer who’s thinking about Portland as a place to call home, feel free to drop me a line, or introduce yourself if you’ll be coming to node conf in July.

I’ve finally had to declare blog bankruptcy here, in order to just wipe the list of well-intentioned-blog-topics clear and get started writing again. Two topics will survive the culling. First, the move to Portland presented an opportunity for a spring cleaning of my development environment. I’ll be writing about how I organized my dotfiles, and explaining why tmux is not just a cargo culting fad, but a ridiculously awesome tool for maximizing your terminal productivity.

The other surviving topic surrounds Backbone.js. Since moving to Portland, I’ve continued working with Bloomberg Sports in New York on their application for MLB team analytics. (Think a modern web app version of Moneyball spreadsheets.) Working on such a large app has presented me with some difficult lessons on how to best use Backbone, especially for interacting with a polyglot backend, which I think would prove useful to any other web devs working on larger Backbone applications.

So now, back to work so I can actually get these posts written in the next week!