A Year in Coffee

| Comments

Last year was the first that I dove deeply into the coffee world, turning what was previously an interest into a full-blown passion. While I had previously ground beans at home and brewed in a french press, I decided sometime in 2010 that I wanted to learn more. Going into 2011, I started brewing with an aeropress and chemex, upgraded my grinder to a Baratza Virtuoso, and furthered my coffee knowledge by reading God in a Cup and Uncommon Grounds. I began taking notes on my home brews and asking questions at coffee bars. And I bought lots of coffee. Lots and lots and lots of coffee.

Lots of coffee

Meaghin has more pictures and a full rundown of our 2011 coffee purchases, but I wanted to highlight a few bags in particular.

Coava and Wrecking Ball

Wrecking Ball Coffee Roasters is a new enterprise from Trish Rothgeb and Nick Cho; I was lucky enough to get one of the first bags they shipped this year. Their coffee presented a perfect example of what makes me love Ethiopian coffees, offering a pleasantly light body without being too acidic. I like to compare good east African coffees to pinot noir - almost all have a juiciness to them, but the best are balanced with strong bass notes. I loved Wrecking Ball’s fully biodegradable package. But beyond the coffee itself, I was happy to order from Wrecking Ball because of Nick Cho. Cho used to run the amazing Murky Coffee in Arlington, VA, which I visited very frequently when I lived in the DC area. Ironically, I didn’t drink much coffee at the time, having been exposed to some swill in college. But Murky is what enticed me to learn more: the intoxicating smell of freshly ground Counter Culture coffee, the precise movements of the baristas as they brewed espressos, the clear passion of everyone involved. Drinking the Wrecking Ball made me feel as if I were making up for the coffee I never enjoyed at Murky.

If Murky induced my coffee passion, Coava revealed the heights to which this passion could be taken. I drank Coava’s David Mancia from Honduras early in the year; later, I would visit Coava’s Portland shop in person. The David Mancia completely blew my mind. Even in my early days of home-brewing, I couldn’t screw this coffee up: chocalate, berries, an amazing finish, thick and juicy and succulent. I couldn’t wait to see how Coava’s shop measured up to the coffee they roasted, and found one of my favorite coffee shops in the country. I can’t wait to go back.

Coffee Collective

One of the highlights of 2011 was my trip to Copenhagen with Meaghin. Before the trip, I greatly anticipated experiencing Danish culture, perhaps most intrigued by their coffee culture. Almost everywhere we bought coffee in Copenhagen, we felt pleased with the product, but Coffee Collective is an entity unto itself. We visited their new location in Torvehallerne, a glorious outdoor food market, a few times, trying various coffee drinks on each visit; the Kieni from Nyeri, Kenya proved particularly delicious.

Two weeks into 2012 and as many bags brewed; I’m currently finishing up a great roast from Cafe Grumpy, from Finca La Coqueta in Columbia. I look forward to finding out what my favorites will be this year.

Better Support for Helpers in Vows-bdd

| Comments

This last week has been a particularly busy one, so I’ve been delayed in blogging, but I released v0.2 of vows-bdd to NPM a week ago. There’s two changes of note. The first is proper documentation for the library: you can see the docco documentation here. If you’re new to vows-bdd, or just want to learn more about how it’s working, the docs should provide all the answers you’re looking for.

The more important change relates to the testing syntax. In some conversations I had online with Graeme Foster, I realized that the vows-bdd syntax left some room for improvement. Specifically, the syntax introduced a potential for redundancy when creating labels for integration tests. While named functions could be used for test statements that were repeated, there wasn’t an easy to way to handle repeated labels.

In order to make the use of test helpers even easier with vows-bdd, I have adjusted the given/when/then/and syntax to allow for array arguments in addition to the previous arguments of label,test_function. It’s easiest to demonstrate the change with an example. One area of code that frequently is repeated is login code in integration tests. Here’s how I had my tests setup with vows-bdd before:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# a test snippet

  .given "I am an admin user", ->
    @user = Model.Factory.create "user", {role: 'admin'}
    @callback()
    return

  .when "I go to login", ->
    zombie.visit Server.path_for("/login"), @callback

  .when "I click login", (browser,status) ->
    browser.fill("email", "#{@user.email}")
           .fill("password", "#{@user.password}")
           .pressButton "Login", @callback

  .then "I should be on the admin index", (err,browser,status) ->
    Test.assert.shouldBeOn browser, "/admin"

# snippet from another test

  .given "I am an admin user", >
    @password = "foo"
    @user = Model.Factory.build( "user", password: @password, passwordConf: @password, role: "admin" )
    @user.save @callback

  .when "I am logged in", >
    user = @user
    cb = @callback
    pw = @password
    zombie.visit Server.path_for("/login"), (e,browser,status) >
      browser.fill "email", user.email
      browser.fill "password", pw
      browser.pressButton "Login", cb
    return

Even with the previous syntax, this code could be improved by creating a named login function that handles the duplicated code. And you could add a property to that function that provides a label. But I felt that the vows-bdd syntax should be improved to make this code repetition even easier. So the new [label,function] syntax looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# first test 

  .scenario("'/admin' is accessible to logged in admin users")

  .when(I.login_as "an admin")

  .then "I should be on the admin index", (err,browser,status) ->
    Test.assert.shouldBeOn browser, "/admin"

# other test

  .scenario("Logging Out")

  .given(I.login_as "an admin")

  .when "I click logout", (browser,status) ->
    browser.pressButton "Logout", @callback

  .then "I should be redirected to the login page", (err,browser,status) ->
    #continues

The login_as function is included in a helper file:

1
2
3
4
5
6
7
8
9
10
11
exports.login_as = (type_of_user) ->
  label = "I login as #{type_of_user}"
  fixture = () ->
    cb = @callback
    @user = user = Model.Factory.create type_of_user.match(/a[n]? (\w+)/)[1]
    zombie.visit Server.path_for("/login"), (err,browser,status) ->
      browser.fill("email", "#{user.email}")
             .fill("password", "#{user.password}")
             .pressButton "Login", cb
    return
  return [label,fixture]

Note that the function returns an array of arguments to be supplied to the vows-bdd method. Also note that the fixture method is using this — which will point to the vows context when the test is evaluated — and that the fixture returns undefined to indicate to vows that the test should be performed asynchronously.

I think this new syntax works really perfectly for integration tests; it goes a long way to supporting declarative testing style.

As always, please let me know if you run into any problems with the library or have any suggestions!

Thanksgiving Week Links

| Comments

I’ve never been a fan of links posts - they always feel like “clips episodes” from sitcoms to me - but I’ve realized that they can be pretty helpful, if they’re well curated. I’m going to be experimenting with the “well curated” sort of links posts. Please feel free to yell at me on twitter if these get boring.

  • A scaffold for your node - scaffoldit is a customizable scaffold generator for your nodejs projects. I don’t think that there’s that much boilerplate for express based apps, but this library is still pretty helpful for getting my tests and basic app configured quickly.

  • Basic metaprogramming in Ruby - If you’re new to Ruby and are confused by some of the metaprogramming enabled by methods like repond_to? and method_missing, check out this helpful post from the Intridea blog.

  • Build first, talk later - Spencer Fry, founder of Carbonmade, offers some fine advice to show don’t tell - a prototype is worth ten thousand words. I particularly like his observation that “The best thinking about your product will come from actually building it.”

  • Productivity geekery - Brett Terpstra reviews the mother-of-all-menubar-apps, Dropzone. I haven’t bought it yet myself, but I’m pretty close to pulling the trigger.

  • Writing your readme - Awhile back, nodejitsu offered some solid advice on setting up your node project’s package.json file. Now they’re back with some more great advice, but this time it’s more universal: how to write a helpful readme for your next open source project.

  • After reading Umair Haque’s excellent New Capitalist Manifesto, I’ve been thinking a great deal about the values of sustainability in business and how value cycles drastically improve upon value chains. I was excited to see Fred Wilson explore the same issues on his blog:

sustainability is all about figuring out how to be in business forever. It is about business models that are win/win and lead to happy long term customer and supplier relationships. It is about avoiding the temptation to overeach. It is about avoiding the temptation to mazimize near term profits at the expense of long term health. It is about adapting the business to changing market dynamics. It is about building a team and a culture that can survive the loss of the leader and keep going. And it is about many more things like this.

Fix That Commit!

| Comments

While it sometimes seems as if everyone has already switched to git (or a similar distributed version control system), I still meet people who are only leaving subversion behind now. A lot of git’s idioms are impenetrable to those who are new to it, but the presence of free resources like Pro Git and git ready make the adjustment much easier.

Even though I’ve used git for awhile, I still need to look up the best way of performing a task every now and then. One trick that comes in handy is editing existing commits. git --amend allows for adding new files or changes to a previous commit, but you can have even more control than that – changing any pre-pushed commit in your history.

Just get the hash of the commit you want to change. With a simple git rebase <commit>^ --interactive, you can then make any changes you want. For each file, just type git add <file>. When you’re done, git commit --amend and git rebase --continue will finish up your editing.

It’s always useful to review and cleanup your commit history before pushing your changes upstream or issuing a pull request. With the ability to revisit any previous commit, you can be more comfortable in a ‘commit-all-the-time’ workflow.

Cleaning Up Yours Vows

| Comments

Learning a framework as you’re TDD-ing a project can be dangerous. But even if you know what you’re doing, some of the conveniences of node.js can make you a bit sloppy with your code. Namely, the ability to pull functions from files as you need them and pass them around makes for some interesting problems.

foo.js
1
2
3
4
5
6
exports.add = function(a,b) {
  return a+b;
}
exports.subtract = function(a,b) {
  return a-b;
}
bar.js
1
2
var add = require('foo').add;
console.log(add(1,2)); // 3

If your functions are free of side effects, you’re not exactly committing a serious coding sin. But go beyond the simple example above – starting to pass around whole objects, or breaking the law of demeter – and soon your code doesn’t feel right.

I quickly ran into this problem with my vows tests. As I was about to merge a feature branch to master, I reviewed my code and was a bit horrified at what I saw in my tests:

user_spec.coffee
1
2
3
4
5
6
7
{cleanupDB} = require "../helpers"
{vows,server} = require "vows"
mongoose = require "mongoose"
User = mongoose.model "User"
assert = require "assert"
Sinon = require "sinon"
{Factory} = require "../helpers"

And this was just one of my tests. Yikes. Lots of bad things going on here:

  • My test has a dependency on my model implementation, and not just the model itself; if I switch the model off mongoose in the future, my test itself will need to change.
  • My test has a dependency on a particulra spying/mocking framework (Sinon)
  • There’s a lot of confusing imports; why is server required off of vows?
  • Repeating requires - one for cleanupDB and one for Factory.

Bad bad bad.

My tests needed to be refactored to deal with this madness. I realized that there was repeated code throughout my vows tests; not only could I clean things up with some proper encapsulation, I could DRY my vows as well.

One cool feature of node is that if you include an index file in a directory, that file is loaded when you require the directory. So I created a new spec/helpers directory, and placed an index file inside.

spec/helpers/index.coffee
1
2
3
4
5
6
process.env.NODE_ENV = 'test'

module.exports =
  Server:  require "#{__dirname}/server_helpers"
  Test:  require "#{__dirname}/test_helpers"
  Model:  require "#{__dirname}/model_helpers"

And each of these helper files now encapsulates logic and functionality that I use across my tests:

server_helpers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
http = require "http"

exports.port = port = 3003
server = (require "#{__dirname}/../../app")
server.ready = (callback) ->
  if @active
    process.nextTick callback
  else
    @active = true
    server.listen port, (err,result) ->
      process.nextTick callback
  return

process.on "exit", ->
  if @active then server.close()

wait = ->
  if !@active
    process.nextTick wait
  else
    return

server.ready wait

makeRequest = (url,params,method,callback) ->
  params ||= ""
  encoding = 'utf-8'
  server.ready ->
    request = http.request
      host: "127.0.0.1"
      port: "#{port}"
      path: url
      method: "#{method}"
      headers:
        'content-type': "application/x-www-form-urlencoded"
        'content-length': params.length

    request.on 'response', (response) ->
      response.body = ''
      response.setEncoding encoding
      response.on 'data', (chunk) ->
        response.body += chunk
      response.on 'end', ->
        callback null, response
    if params
      request.write params
    request.end()


exports.server = server

exports.get = (url,params,callback) ->
  if arguments.length == 2
    callback = arguments[1]
    params = null
  makeRequest url,params,"GET",callback

exports.post = (url,params,callback) ->
  makeRequest url,params,"POST",callback
test_helpers.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Sinon = require "sinon"
assert = require "assert"
http = require "http"
Model = require "./model_helpers"

exports.spy = (object,method) ->
  Sinon.spy object, method

exports.stub = (object, method, fn) ->
  Sinon.stub object, method, fn

exports.spyRender = ->
  @response = http.ServerResponse.prototype
  Sinon.spy @response, "render"

exports.spyModel = (klass,method) ->
  Sinon.spy (Model.getType klass), method

exports.assert = assert
model_helpers.coffee
1
2
3
4
5
6
7
8
9
10
11
mongoose = require "mongoose"
cleaner = new (require "database-cleaner")("mongodb")

exports.cleanupDB = ->
  mongo = mongoose.connection.db
  cleaner.clean mongo

exports.Factory = (require "#{__dirname}/factories").Factory

exports.getType = (Klass) ->
  mongoose.model Klass

My test logic dependencies are clean and encapsulated, making for both clearer requires blocks and clearer tests themselves.

user_spec.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{Model,Test,Server} = require "../helpers"
vows = require 'vows'
User = Model.getType "User"

#code removed for brevity

  .addBatch
    "Hashes password:":
      "when a new user is created":
        topic: ->
          @user = Model.Factory.build "User"
          Test.spy User, "makeSalt"
          Test.spy User, "hashPassword"
          @user.save @callback
          return

        "it creates a salt and stores it": (err,user) ->
          Test.assert.ok User.makeSalt.calledOnce
          Test.assert.ok user.salt == User.makeSalt.returnValues[0]

        "it encrpyts the password": (err,user) ->
          Test.assert.ok User.hashPassword.calledOnce
          Test.assert.ok User.hashPassword.calledWith @user.password

      teardown: ->
        User.hashPassword.restore()
        User.makeSalt.restore()
        Model.cleanupDB()

Indie Productivity

| Comments

Being a contract web developer means working in a large number of enterprise environments. While clients and projects vary dramatically, enterprise environments almost always share certain characteristics in common: locked down networks, limited use of open source libraries (and certainly no contribution!), extreme caution regarding new technologies, and reliance on libraries and tools which some might consider… deprecated. Most of these characteristics are perfectly logical, given the complexity of enterprise projects and the security required by legal considerations. Enterprise software is frequently disregarded as sloppy, boring, uncreative, and poor – and I’ve certainly worked on these kinds of projects, and dealt with some frustrating situations – but classifying all software in this way is unfair. That said, even the best of enterprise projects feel constraining compared to independent work.

Recent developments have certainly improvemed the enterprise work environment. The proliferation of iOS devices has not only brought Macs into the traditionally Windows-only world of the enterprise; it’s brought a new focus on standards-based webapps, which has forced a reconsideration of existing technology stacks. As enterprises have adopted dynamic languages and agile approaches – albeit slowly – they’ve begun upgrading their toolsets, as well. Github’s announcement of an enterprise plan demonstrates that it’s starting to feel a little bit more human within the confines of corporate intranets.

But even as the enterprise has evolved, the improvements made for individual developer productivity have exploded. The ease with which a single developer can build and deploy a scalable, cross-device, and revenue generating app is beyond remarkable. The maturing of tools, languages, development environments, and deployment strategies has created a fantastically productive environment. To name a few favorites:

  • Macbooks - The new Macbook Airs, when fully tricked out, offer incredibly powerful development workhorses weighing less than 3 pounds and costing less than $2k

  • Homebrew - A package manager for Mac OS, making that Macbook purchase perfect

  • Heroku - Have an idea for a new project? Deploy it for free. Want to scale it? Flip a switch

  • Chef and Puppet - Want more control than Heroku offers? Fine, manage your own boxes with a sane devops solution that you can take with you.

  • Git and Github - Who could have ever imagined that managing code could be so enjoyable?

  • zsh and oh-my-zsh - Tab completion, customizable plugins, persistent Git HUD

  • The incredible profusion of programming languages, libraries, and frameworks - Scala, Clojure, node.js, the Play framework, NoSql solutions, nginx, to say nothing of the maturing of Ruby (especially Rails) and Python - all of these technologies make it easier than ever to work in one’s preferred style without sacrificing power or performance. The communities around each of these technologies, empowered by twitter, StackExchange, and Github, ease learning curves and offer helpful answers to any questions.

  • The Apple App store, Square, Stripe, Recurly, and Samurai enable developers to make money on their ideas and apps with far less effort than in the past.

Is there any other industry in which an individual has such a dramatic advantage in tools, cost, and agility over large organizations?

It’s an exciting time for indie developers. And the future keeps looking better.

Back From Vacation

| Comments

I just returned from a fantastic vacation to London and Copenhagen. I’d visited London, before but had never been to Copenhagen, or any Scandinavian country. As an engineer, I could barely wrap my mind around the brilliant efficiencies of the city. The train system is a wonder - incredibly efficient, clean,and comprehensive, with the ability to get anywhere easily, and even allowing sales of travel tickets via text message. My heart warmed at the first site of a flotilla of bike-commuters sailing by on our walk to our hotel. The Danes themselves consistently impressed us with their warmth and hospitality. I look forward to returning soon.

My brain is struggling to return to coding productivity after its extended vacation, so I’ve mostly been reviewing my RSS reader to aid in the transition. Assaf Arkin, to whom I owe a massive debt for his creation of Node testingtool Zombie.js, wrote a great article on Self that deserves mentioning. Self, as most JS developers know, played an important role in inspiring Brendan Eich’s creation of Javascript, but I was unaware of the details of the language.

Assaf’s whole article is worth reading, but one particular quote stood out:

language and environment come together to achieve a common goal: to create an environment that is malleable, that allows learning through sharing and exploration, that uses minimalism and consistency to foster reuse.

Minimalism, consistency, malleability.

These words work not just as signposts of good language design, but of everything from API construction to individual units of code. I’m certainly planning on using them as my mantra as I slowly get back up to speed with work.

Introducing Vows-bdd

| Comments

My work with Node.js has recently transformed from the occassional experiment to the building of a full-on side project. It’s fascinating to be working with a set of tools that are so rapidly developing; the energy and excitement in the Node ecosystem far outweighs any annoyances with needing to adjust to changing APIs.

Embracing Vows

One of the tools which I’ve really enjoyed learning is Vows.js. Vows.js is a fully async Javascript testing library that allows for blazingly fast execution. (It’s amazing how little changes in test speed can make TDD feel much less onerous.) Vows’ syntax can be a little tough to adjust to, but the speed, combined with the ability to construct “test batches”, make the barrier to entry worth the effort.

While Vows is a near pefect tool for unit testing, I began to run into trouble with full-stack integration testing. Check out the contrived example below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
vows.describe("Creating a User")
  .addBatch
    "To create a user":

      "Given the server has started":
        topic:
          server.ready, @callback

        "and the DB is populated":
          topic:
            setupFixtures @callback

          "and another setup function is required":
            topic: ->
              anotherSetup @callback

            "When visiting the form at /user/new":
              topic: ->
                ctx = this
                server.ready ->
                  zombie.visit "http://localhost:#{port}/user/new", ctx.callback
                return

              "then should allow entry of a username": (err,browser,status) ->
                assert.ok browser.querySelector ":input[name=username]"

              "should allow entry of first and last name": (err,b,s) ->
                assert.ok b.querySelector ":input[name=firstName]"
                assert.ok b.querySelector ":input[name=lastName]"

              "should allow entry of a password": (err,b,s) ->
                assert.ok b.querySelector ":input[name=password]"

              "should allow confirmation of a password": (err,b,s) ->
                assert.ok b.querySelector ":input[name=passwordConfirm]"

              "and submitting the form":
                topic: (browser,status) ->
                  browser.fill("username", "test")
                         .fill("firstName", "Justin")
                         .fill("lastName", "Reidy")
                         .fill("password", "foobar")
                         .fill("password", "foobar")
                         .pressButton "Sign Up!", @callback

                "should create a new User": (err,browser,status) ->
                  assert.ok findNewUser()

        .export module

Ouch. All that nesting makes for pretty unreadable code - even in CoffeeScript.

vows-bdd: an easier way to test

I’ve never been a huge Cucumber fan, but modeling integration tests in a “given-when -then” format makes them much easier for me to construct mentally. While the prenup library made long Vows tests easier to read by introducing a fluent interface, I thought that I’d love to marry this fluent approach with BDD’s “given-when-then”.

A couple days later and vows-bdd was born:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Feature("Creating a User")
  .scenario("Create a User via Form")

  .given "the server is running", ->
    server.ready @callback

  .and "the DB is popuplated", ->
    setupFixtures @callback

  .and "another setup function is called", ->
    anotherSetup @callback

  .when "I visit the form at user/new", ->
    zombie.visit "http://localhost:#{port}/user/new", @callback

  .then "I should see a username field", (err,browser,status) ->
    assert.ok browser.querySelector ":input[name=username]"

  .and "I should see entries for first and last name", (err,browser,status) ->
    assert.ok browser.querySelector ":input[name=firstName]"
    assert.ok browser.querySelector ":input[name=lastName]"

  .and "I should see a password entry", (err,browser,status) ->
    assert.ok browser.querySelector, ":input[name=password]"

  .and "I should see a password confirmation", (err,browser,status) ->
    assert.ok browser.querySelector, ":input[name=passwordConfirm]"

  .when "I submit the form", (browser,status) ->
    browser.fill("username", "test")
           .fill("firstName", "Justin")
           .fill("lastName", "Reidy")
           .fill("password", "foobar")
           .fill("password", "foobar")
           .pressButton "Sign Up!", @callback

  .then "a new User should be created", (err,browser,status) ->
    assert.ok findNewUser()

  .complete()
  .finish(module)

Checkout the repo on Github for more documentation and info.

Open-Source is scary!

The vast majority of my career has taken place in enterprise world, where code is rarely, if ever, shared with anyone on the outside, and even using open-source code is considered dangerous. While I’ve contributed to OSS libraries before, I’ve never posted my own creation. It’s fairly nerve-wracking to put your work out in the wild, especially when you’re building on top of such amazing contributions from incredible developers.

In fact, I probably would’ve sat on this little library forever, constantly trying to perfect it, if not for a fantastic blog post written by Charlie Robbins(@indexzero) over at Nodejitsu. I think his post perfectly expresses the spirt and mentality of the Node community right now, and his emphasis on experimentation via small bits of functionality made me realize: this code may not be perfect, and it might not even do that much, but if I find it useful, then maybe someone else will too.

So please - checkout vows-bdd and give it a whirl. Any suggestions or comments would be very much appreciated!

“This” in Anonymous Functions

| Comments

Sometimes it’s difficult to find an easy answer to common coding questions. Because Google ignores most punctuation, even the most exact queries fail to produce relevant results. Questions about the nature and value of this in Javascript present a particularly thorny problem, since “this” is about as common a word as you can find.

A common point of confusion in Javascript is that the value of this depends entirely on a function’s context, and can even be overridden depending on how a function is invoked. Hopefully this post will save time for new Javascript devs trolling through Google’s depths:

In anonymous functions, the value of this refers to the anonymous function itself, and not the calling scope. However, the nature of closures allows the anonymous function to still refer to the calling object.

The above rule is demonstrated with the following nodejs code:

    var that = this;
that.foo = 'bar';
process.nextTick(function() { 
  console.log("this " + this.foo + " and that " + that.foo) });
  

What Does Coffeescript’s “Do” Do?

| Comments

When reading over some Node.js source code written in Coffeescript, I came across a couple uses of the Coffeescript do operator. While do is a very familiar tool for Ruby developers, I wasn’t sure how Coffeescript used it, so I took at look at its documentation, which states:

When using a JavaScript loop to generate functions, it’s common to insert a closure wrapper in order to ensure that loop variables are closed over, and all the generated functions don’t just share the final values. CoffeeScript provides the do keyword, which immediately invokes a passed function, forwarding any arguments.

“All the generated functions don’t just share the final values.” Huh. This statement didn’t mean a lot to me. A little searching on Google led to a fairly helpful post on Stack Overflow. The question there presented the following Javascript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var closures = [];
function create() {
  for (var i = 0; i < 5; i++) {
    closures[i] = function() {
      alert("i = " + i);
    };
  }
}

function run() {
  for (var i = 0; i < 5; i++) {
    closures[i]();
  }
}

create();
run();

The question stated that the result of running this code was 5,5,5,5,5 instead of the expect 0,1,2,3,4. The answer which created the “correct” result provided the code below:

1
2
3
4
5
6
7
8
9
function create() {
  for (var i = 0; i < 5; i++) {
    closures[i] = (function(tmp) {
      return function() {
        alert("i = " + tmp);
      };
    })(i);
  }
}

and also explained:

JavaScript’s scopes are function-level, not block-level, and creating a closure just means that the enclosing scope gets added to the lexical environment of the enclosed function.

OK, this was even less helpful. But after going back and reading the Coffeescript docs again, the concept made sense. As always with Javascript, the context in which a function is called demands as much attention as the function itself. Reading the code in the Stack Overflow post, a developer’s brain automatically thinks of the returned function at the time of evaluation. But in reality, each of those functions created in the create function aren’t called until after the for loop has completed. Thus, by the time each function is called, it evaluates i when i has already finished the loop with a value of 5. The closure-wrapping provided in the answer is exactly what the do keyword in Coffeescript provides!

Here’s an example of the solution’s function, in Coffeescript:

1
2
3
4
5
closures = []
create ->
  for i in [0..5]
    closures[i] = do (i) ->
      -> alert i

Even with this contrived example, I find the Coffeescript easier to read, although of course it’s personal preference. If you wanted to go really crazy with Coffeescript syntax, you could write:

1
  closures = ((do (i) -> -> alert i) for i in [0..5])

Two points for cool implementation, no points for readability!