Sunday, March 13, 2011

CoffeeScript + Backbone.js + Rails = Superfantasticalness

Lately I've been working on application by writing the front end in CoffeeScript using Backbone.js and the back end in Rails. A few people have asked me about it and so I thought I'd share my experience so far.

Backbone.js

I've been looking for a front end javascript framework for quite awhile, ever since I realized that server side MVC frameworks were probably coming to the end of their time in the sun.  I've even tried several aborted attempts to write one. I've spent good amounts of time playing around with both Sproutcore and JavascriptMVC, but when I picked up Backbone.js I didn't want to put it down again. I don't really want to spend the time right now to delve into critiques of the other two, so I'm going to focus on what I like about Backbone.js

For me, the big attraction of Backbone is there's so little to it.  Earlier in my career, I was enamored by frameworks and tools that did "everything I would ever need".  The idea of learning one environment where I could do everything was appealing.  I was attracted by neato whiz bang features even I didn't need them just yet.  But as I've grown older and more curmudgeonly, I now prefer tools that just barely do what I need and then stay out of the way.  In my mind pivotal tracker is such a tool.  Backbone.js  feels like this too.  It provides a nice structure for the code of a rich client web MVC application.  It allows me to continue to use html, css, and jquery without insisting that I give up one of these or do all my design and layout in javascript.  I prefer to work a designer who can create visually appealing UI in html/css, so frameworks that don't accomodate this workflow are a non-starter for me.

I don't intend this to be a Backbone.js guide, the excellent documentation is where to go for that.  But I'll briefly touch on my experience with the different pieces I've used thus far.

Views

The first Backbone code I wrote was a view.  I had started building my app in the usual (for me) way of just adding a some jquery to make my client side UI more dynamic.  But this time, when it started to get unmanagable as it always does, I refactored it into a Backbone View.  This is just a "class" that extends from Backbone.View.  The only thing this does for you is allow you to specify an element that the view contains, and a set of events scoped within this element that bind to functions of your view.  But it turns out this feels just right for organizing my code.  In my case I ended with a tree view component that uses jstree to do a lot of the heavy lifting.  Later on, I actually extracted it into a superclass and reused it on a couple other pages.  Over time I've found that my view classes tend to end up as nicely reusable components.

Interestingly, backbone views don't mandate any particular choice for producing the html.  After some experimentation, we came up with a convention we like on our project.  Each of our views generally has a template file, we're using mustache right now so the files are named things like foo_view.mustache.html.  Originally we were just embedding our templates into our rails views as hidden divs or in script tags.  But we found ourselves repeating the same markup in our jquery-jasmine fixtures, and this made us sad so we searched for a better way.  We settled on having templates in a separate file, and then wrote a rails helper method that renders the views template on the page.  We also wrote a jasmine jquery method that loads the template into a fixture so we can use them in our specs as well.  Here's what that code looks like, if anyone else wants it:


There are a couple of other things worth passing along we've learned working with Backbone views.  The first is that you really want to have your view's element have the same lifespan as your view object.  I ran into this issue by creating new view objects inside the listener method of another view.  There's nothing inherently wrong with this (that I know of), but in my case the element for the view I was creating already existed.  The net effect was that if if the listener method that created the view was called multiple times you could end up with a multiple views listening to events on the same DOM element.  This caused no end of confusion.  It was a much better idea to create the view once and just reuse-it as needed with different models (as necessary).

The other idea I feel like we're learning is how to communicate between models and views.  We regularly have views talk directly to models, getting and setting properties, telling models to persist themselves, etc.  But when it comes time for models to communicate with views, it really feels right to use the Backbone event framework.  There are a set of nice built in events on models, and it is trivial to add your own.  It's worked out well for models to trigger events when interesting things happen and let the views listen to them and do what they will.  So our best practice is shaping up that views can interact with models, including listening to events from them, but models should never talk to views directly.  It would probably seem obvious to do it this way for anyone coming from rails-land, but I thought it might be worth mentioning anyways.

Models

Backbone.js models know how to speak json to a restful back end out with little to no coding required.  This ended up being a pretty big selling point for me, as it made it trivially to integrate Backbone with my rails app and it pretty much Just Worked.  The only gotcha here is that rails would prefer to have the attributes for a model be grouped into a name parameter, but telling backbone to do this as as trivial as the following code:



I guess the biggest difference working with Backbone models than Rails models is that everything is asynchronous.  Calling a fetch (think find in rails) or a save in backbone means you also have to specify a function to invoke on success or failure, or listen to an event.  This would seem to add up to a lot of extra code, were it not for...

Coffeescript

I've been searching for Coffeescript without realizing it for many years.  I've been treating javascript as a first class language for a few years, test driving, trying to use clearly communicative object oriented design, etc.  This has made the experience of writing javascript immensely more satisfying, and I hope, helped me produce higher quality code.  But it's always chafed a bit.  I didn't get to choose javascript.  There's a lot of syntax is in it that I don't like, and feels noisier than I wish it was.  I spent a good amount of time looking for solutions to let me use a language of my choosing in the browser, but in the end they've all fallen short.

Until now.  Coffeescript is a lovely language that compiles into readable, debuggable, javascript.  It's documentation is fantastic and it's source code is beautifully documented.  The most annoying bits of javascript go away, and the coffescript code I've written is so much cleaner and less noisy it's been a joy to use.  I'm finding it difficult to convey how big a deal coffeescript is.  Someone smart I know responded to coffeescript allegedly by saying "But isn't it just nicer syntax?".  Yes it is!  And it turns out this is incredibly valuable and important.  I chose ruby because I can express my intent, in elegant, readable code.  Coffeescript feels the same way to me.  But I can use Coffeescript in all the places I would have had to use javascript before.  It's been huge to me.  I'm pretty much at the point where I'll go back to writing javascript when you pry Coffeescript from out of my hands.

Though I dig backbone a lot, it's still possible one of the other frameworks might mature into something awesome and be the way to go.  Coffeescript, on the other hand, doesn't appear to have anything close.