CoffeeScript

After months of hearing about CoffeeScript and having it on my to-do list week after week, I finally got around to really reading up on it during my flight from SFO to IAH. I tweeted that I was in the middle of moving Picplum over to CoffeeScript and got no less than 10 people asking me why.

CoffeeScript is much like Sass and Haml. It compiles into JavaScript, much like Sass becomes CSS and Haml becomes HTML. It's now included in Rails 3.1 if you're using the asset pipeline (we are), so there was nothing for me to setup. I just created a few .coffee files and it Rails generated them automatically when I was developing locally. When I go to deploy, that'll be done with asset precompilation.

CoffeeScript syntax is a joy to work with. It takes up less space, is easier to see what is going on in the code at a glance and helps you write better code by using good JavaScript structure behind the scenes. The CoffeeScript compiles wraps each file in an anonymous function so you don't automatically pollute the global namespace. That new scoping was the first thing I ran into when moving Picplum over. I had to prepend this to our global "namespace" object (the way we internally designed Picplum's Backbone app — mentioned in Ch 3.2.1 in the book Recipes with Backbone).

A lot of the CoffeeScript syntax just feels right. No parens, no semicolons. Working with object literals is a breeze, just make sure your indentation is all good to go (Show Invisibles in TextMate is now my best friend). No more having to keep up with curly braces for every anonymous function you write (oh so many with a JS-heavy app); just this thin rocket ->.

In a nutshell, CoffeeScript helps you write better code. Need I point you to the JavaScript Garden to remind you of how broken JavaScript really is? Probably the first real thing I learned about JavaScript way back when was how messed up typing can be to a newcomer. In short, read The Good Parts and only ever use the strict equality operator. CoffeeScript builds upons this with some smart aliases.

Because the == operator frequently causes undesirable coercion, is intransitive, and has a different meaning than in other languages, CoffeeScript compiles == into ===, and != into !==. In addition, is compiles into ===, and isnt into !==.

But I digress. I'm not trying to write a guide here, there are tons out there already. I'll just point you to them below.

As for my general workflow to migrating a large JavaScript app over to CoffeeScript? Begin by running each file through js2coffee. Manually comb through the new code and keep an eye out for any odd issues. The converter isn't perfect yet. I ran into an issue where it broke on a block with a return and completely ignored one half of the conditional, which had me debugging why our templating wasn't working for a bit. All the while I was testing everything locally and finding the inevitable indentation errors that sprang up.

The next thing I did was further optimize. For example, there were a few places where js2coffee didn't swap out this for @, or didn't do the new string interpolation (ruby-style #{} inside double quotes). I also made sure to have Chrome dev tools open and peak at the generated JS in the resources tab from time to time to see what was actually loading.

Then I started skimming through the CoffeeScript to find sections that were hard to read at first glance. The biggest offender was jQuery code with lots of chaining (backbone not so much as it has callbacks in its options hash); chaining that had inline callbacks. For example:

And imagine what it would look like if each callback was multiple lines long and the entire code block was just part of another conditional. I ended up changing it to use an "outline" style for inline functions wherein you just breakout the callbacks into locally-scoped functions. Though this is now more of a JS-design tip than a CoffeeScript one.

The next step for me will be to get a bit more comfortable with how CoffeeScript does class. There are many places in backbone where this is immediately applicable. For example, something like this:

YourNameSpace.Views.YourView = Backbone.View.extend

Can now morth into this much sexier version:

class YourNameSpace.Views.YourView extends Backbone.View

Yup, just pinched myself. This is not a dream. That is real CoffeeScript magic action right there! Though if you are just starting out you may want to avoid this. It makes use of much native prototypal stuff so the generated JavaScript may not be as readable to you.

Resources

As you can tell this was a bit of a mindless ramble that I just typed up in the last 15 minutes. More and more hiring startups are looking for CoffeeScript experience (Picplum included) so if you are looking for a job, it might be a good idea to skim through these links in addition to the main CoffeeScript site: