I’ve been writing some CoffeeScript lately, and it’s been fantastic. I wish I had started looking into this language sooner. Here’s some thoughts about it.
the good
Writing CoffeeScript instead of JavaScript feels like I’m fighting a whole new battle. JavaScript is not a verbose language. Writing JavaScript properly, and in an OO manner, requires you to be verbose. What I like best is that CoffeeScript is simply…spartan.
You bring only this snippet of code to battle?
You! What is your keyword?
It’s function
, sir.
And you?
I’m _.bindAll
, sir.
CoffeeScript! What are your keywords?
-> ! => ! -> !
See old friend, I brought better code than you did.
functions & binding
I’m most excited about how accessible functions have become in CoffeeScript, and
how the worry of doing _.bindAll
to keep the current object in this
just
vanishes. Even our old friend $(document).ready
loses a few pounds of syntax
weight:
$ ->
new ItemsRouter()
Backbone.history.start()
It’s ridiculously neat to me that it just works. If you’re doing a loop or
something in a Backbone.View
to render many things, you can use the “fat
arrow” to make sure this
stays as the current object.
class ItemView extends Backbone.View
render: ->
@options.items.each(@renderItem)
renderItem: (item) =>
@el.append item.get("title")
No more worrying about _.bindAll
! Oh yeah, using @
for instance methods (it
substitutes this.
) is a great little cupcake of syntax sugar that makes code
so much easier to read.
hashes/objects
We know the Ruby 1.8 syntax for hashes is
dead, but CS takes
this one step further. In this example, Item
is a Backbone.Model
:
item = new Item title: "Awesome", id: 2
Omitting parentheses is something I’ve been trying with this transition. My philosophy here is to push it to the limit and see how it feels. We’ll see if it passes code review in the next few weeks.
local variables
By default, JavaScript creates all variables in the global scope. How useful.
By default, CoffeeScript makes local variables by default and makes sure to
stick var
in front of declarations.
test = ->
foo = "bar"
console.log(foo)
>> test()
"bar"
>> foo
ReferenceError
This is reason enough to use CoffeeScript. I think anyone writing JavaScript has to pay such close attention to scope that it’s simply just a waste of time.
string interpolation
How many times have you written something like:
var html = "<option value='" + this.id + "'>" + this.get("title") + "</option>";
This is such nonsense. Why did we put up with this? In CoffeeScript, you can write:
html = "<option value='#{@id}'>#{@get("title")}</option>"
By the way, the latest version of Backbone has a make method that helps doing little element creation like this.
inheritance
The official docs on the subject put it best:
JavaScript’s prototypal inheritance has always been a bit of a brain-bender
So far I’ve used inheritance only in context with subclassing Backbone’s core
classes, but I like what I’m seeing so far with the class
and extends
keywords.
class Item extends Backbone.Model
url: ->
"/events/#{@get('event_id')/items/#{@id}"
The bad
Debugging
This has been a major concern of mine since we’ve switched. Luckily it hasn’t been too bad yet, the JavaScript that is generated is actually readable. Of course, there’s the problem of there’s not a one-to-one mapping between the JS and CS, but we manage to get by with Sass/CSS just fine.
I have a feeling this will be an issue going forward, at least until Chrome or Firefox can understand CoffeeScript natively.
Silly keywords
“Silly” is probably the only way I can describe this:
true, yes, on true
false, no, off false
Not sure why we couldn’t just stick with true
and false
. There are always
quirky parts to every language, but if I see @item.has("title") == yes
in a
pull request I’ll be sending a storm of commit comments.
Deploying
I’ve been using Barista to integrate with Rails 3.0 which has worked out quite well.
Our current config/initializers/barista_config.rb
looks like:
if Rails.env.development? || Rails.env.test?
Barista.configure do |c|
c.root = Rails.root.join("app", "assets")
c.output_root = Rails.root.join("public", "coffeescripts")
c.bare = true
c.add_preamble = false
end
end
This tells Barista to look for coffeescripts in app/assets
, which hopefully
will make the move to Rails 3.1 a little easier. We’re dumping them into
public/coffeescripts
, which is is ignored by git so we don’t check in the
generated files. Finally, there’s some extra unnecessary noise that Barista adds
so the two final configuration options turns that off.
We’re also using Kumade to deploy to Heroku’s bamboo stack. I’m really hoping this entire situation gets easier in the next few months, because right now it’s a real annoyance to set up all of this.
the end
Hopefully this gives you a good overview of the nice additions that CoffeeScript provides. We talked internally about using CoffeeScript for months before integrating it. Part of me wishes we had done it sooner, but to really enjoy it fully you have to understand the problems JavaScript has, especially in a large codebase.
Huge thanks go out to the folks at DocumentCloud and Jeremy Ashkenas for making JavaScript application development less painful. There’s plenty of features I didn’t cover and pages of beautifully documented source code on the project’s site that you should read.