Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

January 08 2014

11:00

DevDocs: The Ultimate Work of Reference for Web Developers


  

Thibault Courouble is back. The philosopher and front-end developer from France created yet another useful web service for developers. His new project DevDocs has the potential to become the ultimate work of reference for anybody building web apps. DevDocs integrates a plethora of different documentations and equips them with a spanned search function. This is a very good idea…

October 15 2013

06:30

One-Stop Shop: PHP-Tool Munee Cares for All your Website’s Assets


  

Cody Lundquist, Australian with a Swedish sounding name, created a free asset-management based on PHP 5.3. Its feature-set is astounding, yet demands a special preliminary treatment of the websites, it’s supposed to be working on. Munee is able to manage any kind of possible asset, be it images or other files, JavaScript, CSS, LESS, SCSS or even CoffeeScript.

Sponsored post
feedback2020-admin
14:56

March 28 2013

16:56

Guard is Your Best Friend

A common argument against using preprocessors, like Sass, is that they introduce too much complexity, and are difficult to get started with. Especially today, though, this couldn’t be further from the truth. In this episode, I’ll demonstrate my file monitoring tool of choice, Guard. I’ll think you’ll love it!


Screencast


Show Notes

  • Installed Gems:
    $ gem install guard
    $ gem install rb-fsevent
    $ gem install guard-sass
    $ gem install guard-coffeescript
    $ gem install guard-livereload
    $ gem install guard-concat
    $ gem install guard-uglify
    

    Alternatively, you can use multiple parameters when installing Gems: gem install guard guard-sass.

  • LiveReload Browser Extensions

August 27 2012

18:08

Building and Testing a Backbone App

In this tutorial, we’ll develop a Backbone.js application, while testing it with Jasmine. Not good enough for you? We’ll do it all using CoffeeScript. Trifecta!

We’re going to work on the application in isolation – using a static, serverless environment. This has multiple advantages:

  • Testing and running code is extremely fast.
  • Decoupling our Backbone application from the server side makes it just another client. We could build a mobile application, for example, that would consume the same API.

Our test application will be a simple website where we can manage a database containing nothing more than restaurants.


Starting Boilerplate

To start, we need to move a few pieces into place. Simply download this tarball that contains:

There are also two HTML files: index.html and SpecRunner.html. The former shows our app running, while the latter runs our Jasmine specs.

Let’s test our setup by running the application through a web server. There are various options for this, but I usually rely on a very simple Python command (available on OsX):

python -m SimpleHTTPServer

Backbone provides a nice API to define events in the scope of a specific view.

Next, navigate your browser to http://localhost:8000/index.html, and you should see a congratulations message. Also open http://localhost:8000/SpecRunner.html; the page should contain a sample spec running green.

You should also find a Cakefile in the root directory. This is a very simple CoffeeScript file that you can use to automatically compile all the .coffee files we’re going to write. It assumes that you have CoffeeScript installed as a globally available Node module, and you can refer to this page for instructions. Alternatively, you can use tools like CodeKit or Livereload to accomplish the same result.

To run the cake task, just type cake compile. This task will keep running. You can watch for changes every time you save, but you may need to restart the script if you add new files.


Step 1 – The Restaurant Model

Namespacing

Using Backbone means we’re going to create models, collections and views. Therefore, having a namespace to keep them organized is a good practice, and we can do that by creating an app file and a relevant spec:

touch javascript/app.coffee
touch javascript/spec/app_spec.coffee

The spec file contains just one test:

describe "App namespace", ->

  it "should be defined", ->
    expect(Gourmet).toBeDefined()

Switching to the javascript/app.coffee file, we can add the following namespace declaration:

window.Gourmet =
  Models: {}
  Collections: {}
  Views: {}

Next, we need to add the app file to index.html:

...
<script type="text/javascript" src="/javascript/app.js"></script>
...

We need to do the same in SpecRunner.html, but this time for both app and spec:

<!-- lib -->
<script type="text/javascript" src="/javascript/app.js"></script>

<!-- specs -->
<script type="text/javascript" src="/javascript/spec/toolchain_spec.js"></script>
<script type="text/javascript" src="/javascript/spec/app_spec.js"></script>

Repeat this for every file we create from now on.

Basic Attributes

The core entity of our app is a restaurant, defined by the following attributes:

  • a name
  • a postcode
  • a rating (1 to 5)

As adding more attributes would not provide any advantages in the scope of the tutorial, we can just work with these three for now.

Let’s create the Restaurant model and the relevant spec file:

mkdir -p javascript/models/
mkdir -p javascript/spec/models/
touch javascript/models/restaurant.coffee
touch javascript/spec/models/restaurant_spec.coffee

Now we can open both files and add some basic specs to restaurant_spec.coffee, shown here:

describe "Restaurant Model", ->

  it "should exist", ->
    expect(Gourmet.Models.Restaurant).toBeDefined()

  describe "Attributes", ->

    ritz = new Gourmet.Models.Restaurant

    it "should have default attributes", ->
      expect(ritz.attributes.name).toBeDefined()
      expect(ritz.attributes.postcode).toBeDefined()
      expect(ritz.attributes.rating).toBeDefined()

The test is very simple:

  • We check that a Restaurant class exists.
  • We also check that a new Restaurant instance is always initialized with defaults that mirror the requirements we have.

Refreshing /SpecRunner.html will show the specs failing. Now let’s implement models/restaurant.coffee. It’s even shorter:

class Gourmet.Models.Restaurant extends Backbone.Model

  defaults:
    name: null
    postcode: null
    rating: null

Backbone will take care of sending the correct Ajax requests.

We just need to create a class on the window namespace to make it globally available–we’ll will worry about the namespace in the second part. Now, our specs should pass. Refresh /SpecRunner.html, and the specs should pass.

Validations

As I said before, we will use Backbone Validations for client side validation. Let’s add a new describe block to models/restaurant_spec.coffee to express our expectations:

describe "Restaurant Model", ->
...
  describe "Validations", ->

    attrs = {}

    beforeEach ->
      attrs =
        name: 'Ritz'
        postcode: 'N112TP'
        rating: 5

    afterEach ->
      ritz = new Gourmet.Models.Restaurant attrs
      expect(ritz.isValid()).toBeFalsy()

    it "should validate the presence of name", ->
      attrs["name"] = null

    it "should validate the presence of postcode", ->
      attrs["postcode"] = null

    it "should validate the presence of rating", ->
      attrs["rating"] = null

    it "should validate the numericality of rating", ->
      attrs["rating"] = 'foo'

    it "should not accept a rating < 1", ->
      attrs["rating"] = 0

    it "should not accept a rating > 5", ->
      attrs["rating"] = 6

We define an empty attributes object that will be modified in every expectation. Each time we will set only one attribute with an invalid value, thus testing the thoroughness of our validation rules. We can also use an afterEach block to avoid a lot of repetition. Running our specs will show 6 failures. Once again, we have an extremely concise and readable implementation, thanks to Backbone validations:

class Gourmet.Models.Restaurant extends Backbone.Model

  defaults:
    name: null
    postcode: null
    rating: null

  validate:
    name:
      required: true
    postcode:
      required: true
    rating:
      required: true
      type:     'number'
      min:      1
      max:      5

Our specs will now pass, and with these changes in place, we have a quite solid Restaurant model.

The Restaurants Collection

Because we want to manage a list of restaurants, it makes sense to have a RestaurantsCollection class. We don’t know yet how complicated it needs to be; so, let’s focus on the bare minimum requirements by adding a new describe block to the models/restaurant_spec.coffee file:

describe "Restaurant model", ->
...
describe "Restaurants collection", ->

  restaurants = new Gourmet.Collections.RestaurantsCollection

  it "should exist", ->
    expect(Gourmet.Collections.RestaurantsCollection).toBeDefined()

  it "should use the Restaurant model", ->
    expect(restaurants.model).toEqual Gourmet.Models.Restaurant

Backbone provides an extensive list of methods already defined for a collection, so our work here is minimal. We don’t want to test methods defined by the framework; so, we just have to make sure that the collection uses the right model. Implementation-wise, we can append the following few lines to models/restaurant.coffee:

class Gourmet.Collections.RestaurantsCollection extends Backbone.Collection

  model: Gourmet.Models.Restaurant

It’s clear that CoffeeScript and Backbone are a very powerful team when it comes to clarity and conciseness. Let’s rerun our specs to verify that everything’s green.


Step 2 – The Restaurants View

The Markup

Until now, we haven’t even looked at how we’re going to display or interact with our data. We’ll keep it visually simple and focus on two actions: adding and removing a restaurant to/from the list.

Thanks to Bootstrap, we can easily add some basic markup that results in a decent looking prototype table. Let’s open the index.html file and add the following body content:

<div class="container">
  <div class="navbar">
    <div class="navbar-inner">
      <div class="container">
        <a href="#" class="brand">Awesome restaurants</a>
      </div>
    </div>
  </div>
  <div class="container">
    <div class="row">
      <div class="span4">
        <form action="#" class="well form-horizontal" id="restaurant-form">
          <div class="control-group">
            <label for="restaurant_name">Name</label>
            <input type="text" name="restaurant[name]" id="restaurant_name" />
            <span class="help-block">Required</span>
          </div>
          <div class="control-group">
            <label for="restaurant_rating">Rating</label>
            <input type="text" name="restaurant[rating]" id="restaurant_rating" />
            <span class="help-block">Required, only a number between 1 and 5</span>
          </div>
          <div class="control-group">
            <label for="restaurant_postcode">Postcode</label>
            <input type="text" name="restaurant[postcode]" id="restaurant_postcode" />
            <span class="help-block">Required</span>
          </div>
          <input type="button" class="btn btn-primary" value="Save" id="save"/>
        </form>
      </div>
      <div class="span8">
        <table class="table" id="restaurants">
          <thead>
            <tr>
              <th>Name</th>
              <th>Postcode</th>
              <th>Rating</th>
            </tr>
          </thead>
          <tbody></tbody>
        </table>
      </div>
    </div>
  </div>
</div>

What we really care about is the #restaurant-form and the #restaurants table. The input elements use a conventional pattern for their names (entity[attribute]), making them easily processable by most back-end frameworks (especially Rails). As for the table, we are leaving the tbody empty, as we will render the content on the client with Hogan. In fact, we can add the template we’re going to use right before all other <script> tags in the <head>.

...
<link rel="stylesheet" media="screen" href="/css/bootstrap.css" >
<script type="text/mustache" id="restaurant-template">
  <tr>
    <td>{{ name }}</td>
    <td>{{ postcode }}</td>
    <td>{{ rating }}</td>
    <td>
      <i class="icon-remove remove" id="{{ id }}"></i>
    </td>
  </tr>
</script>
<script type="text/javascript" src="/javascript/vendor/jquery.min.js"></script>
...

Being a Mustache template, it needs the correct text/mustache type and an id we can use to retrieve it from the DOM. All the parameters enclosed in {{ }} are attributes of our Restaurant model; this simplifies the rendering function. As a last step, we can add a remove icon that, when clicked, deletes the corresponding restaurant.

The Restaurants View Class

As previously stated, we have two core view components: the restaurants list and the restaurant form. Let’s tackle the first by creating both the directory structure for views and the needed files:

mkdir -p javascript/views
mkdir -p javascript/spec/views
touch javascript/views/restaurants.coffee
touch javascript/spec/views/restaurants_spec.coffee

Let’s also copy #restaurant-template to the SpecRunner.html file:

...
<script type="text/javascript" src="/javascript/vendor/jasmine-jquery.js"></script>

<!-- templates -->
<script type="text/mustache" id="restaurant-template">
  <tr>
    <td>{{ name }}</td>
    <td>{{ postcode }}</td>
    <td>{{ rating }}</td>
    <td>
      <i class="icon-remove remove" id="{{ id }}"></i>
    </td>
  </tr>
</script>

<!-- vendor js -->
<script type="text/javascript" src="/javascript/vendor/jquery.min.js"></script>
...

In addition, we need to include the .js files in the head of SpecRunner.html. We can now open views/restaurant_spec.coffee and start editing.

describe "Restaurants view", ->

  restaurants_data = [
    {
      id: 0
      name: 'Ritz'
      postcode: 'N112TP'
      rating: 5
    },
    {
      id: 1
      name: 'Astoria'
      postcode: 'EC1E4R'
      rating: 3
    },
    {
      id: 2
      name: 'Waldorf'
      postcode: 'WE43F2'
      rating: 4
    }
  ]

  invisible_table = document.createElement 'table'

  beforeEach ->
    @restaurants_collection = new Gourmet.Collections.RestaurantsCollection restaurants_data
    @restaurants_view = new Gourmet.Views.RestaurantsView
      collection: @restaurants_collection
      el: invisible_table

  it "should be defined", ->
    expect(Gourmet.Views.RestaurantsView).toBeDefined()

  it "should have the right element", ->
    expect(@restaurants_view.el).toEqual invisible_table

  it "should have the right collection", ->
    expect(@restaurants_view.collection).toEqual @restaurants_collection

Fixtures are a simple way to import HTML fragments in our tests without having to write them inside the spec file itself.

It looks like a lot of code, but this is a standard start for a view spec. Let’s walk through it:

  • We begin by instantiating an object that holds some restaurant data. As suggested by the Backbone documentation, it’s a good practice to feed a Backbone app the data it needs directly in the markup to avoid a delay for the user and an extra HTTP request when the page opens.
  • We create an invisible table element without appending it to the DOM; we don’t need it for user interaction.
  • We define a beforeEach block where we instantiate a RestaurantsCollection with the data we created before. Doing it in a beforeEach block guarantees that every spec will start with a clean slate.
  • We then instantiate a RestaurantsView class and pass both the collection and the invisible table in the initializer. The object keys, collection and el, are default Backbone methods for a View class. They identify the container where the view will be rendered and the data source used to populate it.
  • The specs simply check that everything we assume in the beforeEach block is true.

Running our tests throws an error because the RestaurantsView class is not yet defined. We can easily get everything to green by adding the following content to views/restaurant.coffee:

class Gourmet.Views.RestaurantsView extends Backbone.View

We don’t need to override or change the constructor defined by the Backbone.View prototype because we instantiated the view with a collection and an el attribute. This single line is enough to get our specs green; it will, however, do pretty much nothing from the end result point of view.

Assuming there are restaurants added to the collection, the view class should render them on the page as soon as the page loads. Let’s translate this requirement into a spec that we can add at the bottom of the views/restaurant_spec.coffee file:

it "should render the the view when initialized", ->
  expect($(invisible_table).children().length).toEqual 3

We can test the number of children (<tr/> elements) that the invisible table needs to have, considering that we have defined a sample dataset of three restaurants. This will result in a red spec because we haven’t even started working on rendering. Let’s add the relevant piece of code to the RestaurantsView class:

class Gourmet.Views.RestaurantsView extends Backbone.View
  template: Hogan.compile $('#restaurant-template').html()
  initialize: ->
    @render @collection
  render: =>
    @$el.empty()
    for restaurant in @collection.models
      do (restaurant) =>
        @$el.append @template.render(restaurant.toJSON())

…the real benefit is the possibility to work effectively on testable pieces of functionality that follow predictable patterns.

You will see this pattern very frequently in a Backbone application, but let’s break it into pieces:

  • The template function isolates the templating logic we use inside the application. We’re using mustache templates compiled through Hogan, but we could’ve used Underscore or Mustache itself. All of them follow a similar API structure; so, switching would not be difficult (albeit a bit boring). In addition, isolating the template function gives a clear idea of which template a view uses.
  • The render function empties the el (note that @$el is a cached, jQuery wrapped version of the element itself made available by default by Backbone), iterates on the models inside the collection and render the result, and appends it to the element. This is a naive implementation, and you may want to refactor it to append just once instead of doing it at every loop.
  • Finally, we call render when the view is initialized.

This will make our spec green and will give us a minimal amount of code useful to actually show it on the page. Let’s open index.html and add the following:

...
<body>
  <script type="text/javascript">
    restaurants_data = [
      {
        id: 0,
        name: 'Ritz',
        postcode: 'N112TP',
        rating: 5
      },
      {
        id: 1,
        name: 'Astoria',
        postcode: 'EC1E4R',
        rating: 3
      },
      {
        id: 2,
        name: 'Waldorf',
        postcode: 'WE43F2',
        rating: 4
      }
    ];
    $(document).ready(function(){
      restaurants = new Gourmet.Collections.RestaurantsCollection(restaurants_data);
      restaurants_view = new Gourmet.Views.RestaurantsView({
        collection: restaurants,
        el: '#restaurants tbody'
      })
    });
  </script>
  ...

We’re basically replicating the default dataset and the setup needed to get the app running. We’re also doing it inside the HTML file because this code is useful only in this static version of the app.

Refresh the page and behold! The restaurants table will be populated with results.

Our restaurants home

Next, we need to handle what happens when we add or remove a restaurant from the collection. It’s important to remember that the form is just one possible way to act on the collection; we could also have push events from other users, for example. Therefore, it is essential that this logic is separated in a clean and independent manner.

What do we expect to happen? Let’s add this specs to the views/restaurants_view_spec.coffee file (right after the last one):

it "should render when an element is added to the collection", ->
  @restaurants_collection.add
    name: 'Panjab'
    postcode: 'N2243T'
    rating: 5
  expect($(invisible_table).children().length).toEqual 4

it "should render when an element is removed from the collection", ->
  @restaurants_collection.pop()
  expect($(invisible_table).children().length).toEqual 2

In essence, we add and remove a restaurant to the collection, expecting our table to update itself accordingly. Adding this behavior to the view class requires a couple of lines in the initializer, as we can leverage on Backbone events on the collection:

...
initialize: ->
  @render @collection
  @collection.on 'add', @render
  @collection.on 'remove', @render
...

We can re-render the whole table using the collection in the current state (after an element has been added or removed) because our rendering logic is pretty simple. This will make our specs to pass.

When you now open the index.html file, you will see that the remove icon on each table row doesn’t do anything. Let’s spec out what we expect to happen at the end of the views/restaurants_view_spec.coffee file:

it "should remove the restaurant when clicking the remove icon", ->
  remove_button = $('.remove', $(invisible_table))[0]
  $(remove_button).trigger 'click'
  removed_restaurant = @restaurants_collection.get remove_button.id
  expect(@restaurants_collection.length).toEqual 2
  expect(@restaurants_collection.models).not.toContain removed_restaurant

Jasmine spies are quite powerful, and I encourage you to read about them.

The test is pretty verbose, but it summarizes exactly what needs to happen:

  • We find the remove icon of the first row in the table with jQuery.
  • We then click that icon.
  • We identify which restaurant needs to be removed by using the id of the remove button, which corresponds to the id of the restaurant model.
  • We test that the restaurants collection has an element less, and that element is exactly the one we identified before.

How can we implement this? Backbone provides a nice API to define events in the scope of a specific view. Let’s add one to the RestaurantsView class:

class Gourmet.Views.RestaurantsView extends Backbone.View
  events:
    'click .remove': 'removeRestaurant'
  ...
  removeRestaurant: (evt) =>
    id = evt.target.id
    model = @collection.get id
    @collection.remove model

When clicking on an element with class .remove, the view calls the removeRestaurant function and passes the jQuery event object. We can use it to get the id of the element and remove the relevant model from the collection. We already handle what happens when removing an element from the collection; so, this will be enough to get the spec to green.

In addition, you can open index.html and see it in action in the browser.

The Restaurant Form Class

We now need to handle the user input when using the form to add a new restaurant:

  • If the user inputs invalid data, we’re going to display inline validation errors.
  • If the user inputs valid data, the restaurant will be added to the collection and displayed in the table.

As we’ve already added validations to the Restaurant model, we now need to wire them to the view. Not surprisingly, we will start by creating a new view class and the relevant spec file.

touch javascript/views/restaurant_form.coffee
touch javascript/spec/views/restaurant_form_spec.coffee

Once again, let’s remember to add the JavaScript compiled version of the view to index.html and both compiled versions to SpecRunner.html.

It’s a good time to introduce fixtures, a piece of functionality made available by Jasmine-jQuery, because we will be dealing with the form markup. In essence, fixtures are a simple way to import HTML fragments in our tests without having to write them inside the spec file itself. This keeps the spec clean, understandable, and can eventually lead to reusability of the fixture among multiple specs. We can create a fixture for the form markup:

mkdir -p javascript/spec/fixtures
touch javascript/spec/fixtures/restaurant_form.html

Let’s copy the whole form in index.html to the restaurant_form.html fixture:

<form action="#" class="well form-horizontal" id="restaurant-form">
  <div class="control-group">
    <label for="restaurant_name">Name</label>
    <input type="text" name="restaurant[name]" id="restaurant_name" />
    <span class="help-block">Required</span>
  </div>
  <div class="control-group">
    <label for="restaurant_rating">Rating</label>
    <input type="text" name="restaurant[rating]" id="restaurant_rating" />
    <span class="help-block">Required, only a number between 1 and 5</span>
  </div>
  <div class="control-group">
    <label for="restaurant_postcode">Postcode</label>
    <input type="text" name="restaurant[postcode]" id="restaurant_postcode" />
    <span class="help-block">Required</span>
  </div>
  <input type="button" class="btn btn-primary" value="Save" id="save"/>
</form>

Now open views/restaurant_form_spec.coffee and add the fixture along with some boilerplate:

describe "Restaurant Form", ->

  jasmine.getFixtures().fixturesPath = 'javascript/spec/fixtures'

  beforeEach ->
    loadFixtures 'restaurant_form.html'
    @invisible_form = $('#restaurant-form')
    @restaurant_form = new Gourmet.Views.RestaurantForm
      el: @invisible_form
      collection: new Gourmet.Views.RestaurantsCollection

  it "should be defined", ->
    expect(Gourmet.Views.RestaurantForm).toBeDefined()

  it "should have the right element", ->
    expect(@restaurant_form.$el).toEqual @invisible_form

  it "should have a collection", ->
    expect(@restaurant_form.collection).toEqual (new Gourmet.Views.RestaurantsCollection)

The jasmine.getFixtures().fixtures_path attribute change is needed as we have a custom directory structure that differs from the library default. Then, in the beforeEach block, we load the fixture and define an @invisible_form variable that targets the form we just imported. Finally, we define an instance of the class we’re going to create, passing in an empty restaurants collection and the @invisible_form we just created. As usual, this spec will be red (the class is still undefined), but if we open restaurant_form.coffee we can easily fix it:

    class Gourmet.Views.RestaurantForm extends Backbone.View

Next, we need to think about our spec’s structure. We have two choices:

Using Backbone means we’re going to create models, collections and views. Therefore, having a namespace to keep them organized is a good practice

  • We can spy on the form content with jasmine and mock it.
  • We could manually change the content of the fields and then simulate a click.

Personally, I favor the first approach. The second would not eliminate the need for proper integration testing, but it would increase the complexity of the spec.

Jasmine spies are quite powerful, and I encourage you to read about them. If you come from a Ruby testing background, they’re very similar to RSpec’s mocks and feel very familiar. We do need to have an idea of the pattern we are going to implement, at least with broad strokes:

  • The user enters data in the form.
  • When he presses save, we get the form content in a serialized form.
  • We transform that data and create a new restaurant in the collection.
  • If the restaurant is valid, we save it, otherwise we will display validation errors.

As said before, we’re going to mock the first step, and we’ll do so by defining a new describe block where we instantiate an object that represents a well formed, valid data structure coming from a form.

describe "Restaurant Form", ->
...
  describe "form submit", ->

    beforeEach ->
      @serialized_data = [
        {
          name: 'restaurant[name]',
          value: 'Panjab'
        },
        {
          name: 'restaurant[rating]',
          value: '5'
        },
        {
          name: 'restaurant[postcode]',
          value: '123456'
        }
      ]
      spyOn(@restaurant_form.$el, 'serializeArray').andReturn @serialized_data

At the end, we define a spy on the serializeArray method for our form. That means that if we call @restaurant_form.$el.serializeArray(), we already know that it’s going to return the object we created above. This is the mocking facility we needed; it simulates the user input we need to test with. Next, we can add some specs:

it "should parse form data", ->
  expect(@restaurant_form.parseFormData(@serialized_data)).toEqual
    name: 'Panjab',
    rating: '5',
    postcode: '123456'

it "should add a restaurant when form data is valid", ->
  spyOn(@restaurant_form, 'parseFormData').andReturn
    name: 'Panjab',
    rating: '5',
    postcode: '123456'
  @restaurant_form.save() # we mock the click by calling the method
  expect(@restaurant_form.collection.length).toEqual 1

it "should not add a restaurant when form data is invalid", ->
  spyOn(@restaurant_form, 'parseFormData').andReturn
    name: '',
    rating: '5',
    postcode: '123456'
  @restaurant_form.save()
  expect(@restaurant_form.collection.length).toEqual 0

it "should show validation errors when data is invalid", ->
  spyOn(@restaurant_form, 'parseFormData').andReturn
    name: '',
    rating: '5',
    postcode: '123456'
  @restaurant_form.save()
  expect($('.error', $(@invisible_form)).length).toEqual 1

In the first spec, we verify that our RestaurantForm class has a method that parses the data from the form. This method should return an object that we can feed to the restaurant collection. In the second spec, we mock the previous method because we don’t need to test it again. Instead, we focus on what happens when the user clicks ‘Save’. It will probably trigger an event that calls a save function.

We should tweak the second spec’s mock to return invalid data for a restaurant in order to verify that the restaurant doesn’t get added to the collection. In the third spec, we verify that this also triggers validation errors in the form. The implementation is somewhat tricky:

class Gourmet.Views.RestaurantForm extends Backbone.View

  events:
    'click #save': 'save'

  save: ->
    data = @parseFormData(@$el.serializeArray())
    new_restaurant = new Restaurant data
    errors = new_restaurant.validate(new_restaurant.attributes)
    if errors then @handleErrors(errors) else @collection.add new_restaurant

  parseFormData: (serialized_array) ->
    _.reduce serialized_array, @parseFormField, {}

  parseFormField: (collector, field_obj) ->
    name = field_obj.name.match(/[(w+)]/)[1]
    collector[name] = field_obj.value
    collector

  handleErrors: (errors) ->
    $('.control-group').removeClass 'error'
    for key in (_.keys errors)
      do (key) ->
        input = $("#restaurant_#{key}")
        input.closest('.control-group').addClass 'error'

This is a good practice to make sure that we use the fake server only where we need to, minimizing interference with the rest of the test suite.

Let’s see each function:

  • We have an events hash that binds the user’s mouse click to a save function.
  • The save function parses the data (more on that below) in the form and creates a new restaurant. We call the validate function (available by Backbone and defined by Backbone-validations). It should return false when the model is valid, and an error object when it’s invalid. If valid, we add the restaurant to the collection.
  • The two ‘parse’ functions are needed to extract the attribute names from the form and create an object in the desired Backbone-ready format. Bear in mind that this complexity is needed because of the markup. We could change it, but this is a good example of how you could work on top of an existing form to enhance it.
  • The handleErrors function iterates over the errors object and finds the corresponding input fields, adding the .error class when appropriate.

Running the specs now shows a reassuring series of green dots. To have it running in the browser, we need to extend our initialize function:

$(document).ready(function(){
  restaurants = new Gourmet.Collections.RestaurantsCollection(restaurants_data);
  restaurants_view = new Gourmet.Views.RestaurantsView({
    collection: restaurants,
    el: '#restaurants tbody'
  });
  restaurant_form_view = new Gourmet.Views.RestaurantForm({
    el: '#restaurant-form',
    collection: restaurants
  });
});

There’s only one caveat: for now you can’t delete a restaurant that you added because we rely on the id attribute to target the correct model in the restaurants collection (Backbone needs a persistence layer to assign it). This is where you would add, depending on your needs, a real back-end–like a Rails server or a LocalStorage adapter.


Step 3 – Testing server interaction

Even though we’re on a server-less environment, we can take advantage of a couple of extra libraries that let us wire up our application for a server deploy. As a proof of concept, we will assume to be working on top of a Ruby on Rails stack.

To use Backbone with a Rails application, we need to have an additional adapter for syncing; Backbone doesn’t provide that by default (it’s a server agnostic tool). We can use the one included in the Backbone-rails project.

curl -o javascript/vendor/backbone_rails_sync.js http://raw.github.com/codebrew/backbone-rails/master/vendor/assets/javascripts/backbone_rails_sync.js

Next, we need to include it both in index.html and SpecRunner.html, right after the script that requires Backbone itself. This adapter takes care of executing all the asyncronous requests we need, provided that we setup our Restaurant model and our RestaurantsCollection with the right URLs.

How are we going to test this? We can use Sinon.js, a very powerful JavaScript mocking library that is also able to instantiate a fake server object that will intercept all XHR requests. Once again, we can simply:

curl -o javascript/vendor/sinon.js http://sinonjs.org/releases/sinon-1.4.2.js

Don’t forget to add it to the SpecRunner.html file right after Jasmine.

Now we can start thinking about the server API. We can assume it follows a RESTful architecture (a direct consequence of choosing Rails as a backend) and uses the JSON format. Because we’re managing restaurants, we can also assume that the base URL for every request will be /restaurants.

We can add two specs to the models/restaurant_spec.coffee file to make sure that both collection and model are properly setup:

...

it "should have default attributes", ->
  expect(ritz.attributes.name).toBeDefined()
  expect(ritz.attributes.postcode).toBeDefined()
  expect(ritz.attributes.rating).toBeDefined()

it "should have the right url", ->
  expect(ritz.urlRoot).toEqual '/restaurants'

...

it "should use the Restaurant model", ->
  expect(restaurants.model).toEqual Gourmet.Models.Restaurant

it "should have the right url", ->
  expect(restaurants.url).toEqual '/restaurants'

To implement this, we need to define two methods on the Restaurant model and the RestaurantsCollection class:

class Gourmet.Models.Restaurant extends Backbone.Model

  urlRoot: '/restaurants'

...

class Gourmet.Collections.RestaurantsCollection extends Backbone.Collection

  url: '/restaurants'

  model: Gourmet.Models.Restaurant

Watch out for the different method name!

Decoupling our Backbone application from the server side makes it just another client.

This is what is needed to setup server integration. Backbone will take care of sending the correct Ajax requests. Fore example, creating a new restaurant triggers a POST request to /restaurants with the new restaurant attributes in JSON format. As these requests are always the same (that is guaranteed by the rails_sync adapter), we can reliably test that interaction on the page will trigger those requests.

Let’s open the views/restaurants_spec.coffee file and setup Sinon. We will use its fakeServer facility to check the requests sent to the server. As a first step, we have to instantiate a sinon server in a beforeEach block. We will also need to make sure to restore the normal functionality right after running our specs. This is a good practice to make sure that we use the fake server only where we need to, minimizing interference with the rest of the test suite.

  beforeEach ->
    @server = sinon.fakeServer.create()
    @restaurants_collection = new Gourmet.Collections.RestaurantsCollection restaurants_data
    @restaurants_view = new Gourmet.Views.RestaurantsView
      collection: @restaurants_collection
      el: invisible_table

  afterEach ->
    @server.restore()

Next, we add a spec to test that a DELETE request is sent to the server when we press the remove icon for a restaurant:

it "should remove a restaurant from the collection", ->
  evt = { target: { id: 1 } }
  @restaurants_view.removeRestaurant evt
  expect(@restaurants_collection.length).toEqual 2

it "should send an ajax request to delete the restaurant", ->
  evt = { target: { id: 1 } }
  @restaurants_view.removeRestaurant evt
  expect(@server.requests.length).toEqual 1
  expect(@server.requests[0].method).toEqual('DELETE')
  expect(@server.requests[0].url).toEqual('/restaurants/1')

We can easily inspect @server.requests, an array of all the XHR requests made in the test. We check protocol and URL of the first request and ensure it matches with the expectation. If you run the spec, it will fail because our current logic simply removes the restaurant from the collection without deleting it. Let’s open views/restaurants.coffee and revise the removeRestaurant method:

removeRestaurant: (evt) =>
  id = evt.target.id
  model = @collection.get id
  @collection.remove model
  model.destroy()

By calling destroy, we effectively trigger the DELETE request, making our spec pass.

Next up, the restaurant form. We want to test that every time a form with valid data is submitted, a POST request is sent to the server with the correct data. We will also refactor our tests to isolate valid and invalid attributes in two variables; this will reduce the amount of repetition that we already have. For clarity, here is the full Form submit block from views/restaurant_form_spec.coffee:

describe "Form submit", ->

  # attrs need to be alphabetical ordered!
  validAttrs =
    name: 'Panjab',
    postcode: '123456',
    rating: '5'

  invalidAttrs =
    name: '',
    postcode: '123456',
    rating: '5'

  beforeEach ->
    @server = sinon.fakeServer.create()
    @serialized_data = [
      {
        name: 'restaurant[name]',
        value: 'Panjab'
      },
      {
        name: 'restaurant[rating]',
        value: '5'
      },
      {
        name: 'restaurant[postcode]',
        value: '123456'
      }
    ]
    spyOn(@restaurant_form.$el, 'serializeArray').andReturn @serialized_data

  afterEach ->
    @server.restore()

  it "should parse form data", ->
    expect(@restaurant_form.parseFormData(@serialized_data)).toEqual validAttrs

  it "should add a restaurant when form data is valid", ->
    spyOn(@restaurant_form, 'parseFormData').andReturn validAttrs
    @restaurant_form.save() # we mock the click by calling the method
    expect(@restaurant_form.collection.length).toEqual 1

  it "should not add a restaurant when form data is invalid", ->
    spyOn(@restaurant_form, 'parseFormData').andReturn invalidAttrs
    @restaurant_form.save()
    expect(@restaurant_form.collection.length).toEqual 0

  it "should send an ajax request to the server", ->
    spyOn(@restaurant_form, 'parseFormData').andReturn validAttrs
    @restaurant_form.save()
    expect(@server.requests.length).toEqual 1
    expect(@server.requests[0].method).toEqual('POST')
    expect(@server.requests[0].requestBody).toEqual JSON.stringify(validAttrs)

  it "should show validation errors when data is invalid", ->
    spyOn(@restaurant_form, 'parseFormData').andReturn invalidAttrs
    @restaurant_form.save()
    expect($('.error', $(@invisible_form)).length).toEqual 1

The pattern is exactly the same as the one we used in the previous spec: we instantiate a sinon server and check the requests array for a POST request with the valid attributes.

To implement this, we need to modify a line in views/restaurant_form.coffee:

save: ->
  data = @parseFormData(@$el.serializeArray())
  new_restaurant = new Gourmet.Models.Restaurant data
  errors =  new_restaurant.validate(new_restaurant.attributes)
  if errors then @handleErrors(errors) else @collection.create new_restaurant

Instead of simply adding the restaurant to the collection, we call the create method to trigger the server save.


Conclusion

If you have never worked with Backbone and Jasmine before, this is lot to digest, however the real benefit is the possibility to work effectively on testable pieces of functionality that follow predictable patterns. Here are some suggestions on how to improve from here:

  • Would it be possible to add a message to the validation errors?
  • How could we reset the form after adding a restaurant?
  • How could we edit a restaurant?
  • What if we need to paginate the table?

Try it out and let me know in the comments!


April 09 2012

19:54

Better CoffeeScript Testing With Mocha

Recently, I’ve been doing a considerable amount of CoffeeScript work. One problem I ran into early-on was testing: I didn’t want to have to manually convert my CoffeeScript to JavaScript before I could test it. Instead, I wanted to test from CoffeeScript directly. How’d I end up doing it? Read on to find out!


You’ll need to have Node.js and Node Package Manager installed.

Before we continue on, I’ll point out that you need to have a decent knowledge of CoffeeScript for this tutorial; I won’t be explaining the bits and pieces here. If you’re interested in CoffeeScript, you should check out the CoffeeScript tuts available here on Nettuts+, or the CoffeeScript documentation.

Additionally, you’ll need to have Node.js and the Node Package Manager (npm) installed for this tutorial. If you don’t have ‘em installed, no worries: head over to nodejs.org and download the installer for your platform; then, well, install it!


Meeting Mocha and Chai

We’ll be building the beginnings of a todo list application (cliché, I know). These will be CoffeeScript classes. Then, we’ll write some tests with Mocha and Chai to test that functionality.

Why both Mocha and Chai? Well, Mocha is a testing framework, but it doesn’t include the actual assertions component. That might sound strange: after all, there isn’t much more to a testing library, is there? Well, there is, in Mocha’s case. The features that brought me to the library are two-fold: the ability to run tests from the command line (instead of having an HTML page to run them in the browser), and the ability to run test in CoffeeScripts, without having to convert that code to JavaScript (as least manually: Mocha does it behind the scenes). There are other features, too, that I won’t be talking about here, including:

  • You can easily test asynchronous code.
  • You can watch for especially slow tests.
  • You can output the results in a number of different formats.

And on, and on. See more at the Mocha home page. To install Mocha simply run npm install -g mocha, and you’re set.

As for Chai: it’s a great assertion library that offers interfaces for doing both BDD and TDD; you can use it both in the browser or on the command line via node, which is how we’ll use it today. Install it for Node, via npm install -g chai.

Now that we have our libraries installed, let’s start writing some code.


Setting Up Our Project

Let’s begin by setting up a mini project. Create a project folder. Then, create two more folders in that one: src, and test. Our CoffeeScript code will go in the src folder, and our tests will go in, you guessed it, the tests folder. Mocha looks for a test folder by default, so by doing this, we’ll save ourselves some typing later.

Mocha looks for a test folder by default.

We’re going to create two CoffeeScript classes: Task, which will be a todo item, and TaskList, which will be a list of todo items (yes, it’s more than an array). We’ll put them both in the src/task.coffee file. Then, the tests for this will be in test/taskTest.coffee. Of course, we could split ‘em into their own files, but we’re just not going to do that today.

We have to start by importing the Chai library and enabling the BDD syntax. Here’s how:

chai = require 'chai'
chai.should()

By calling the chai.should method, we’re actually adding a should property to Object.prototype. This allows us to write tests that read like this:

task.name.should.equal "some string"

If you prefer the TDD syntax, you can do this:

expect = chai.expect

… which allows you to write tests like this:

expect(task.name).to.equal "some string"

We’ll actually have to use both of these, as you’ll see; however, we’ll use the BDD syntax as much as possible.

Now we’ll need to import our Task and TaskList classes:

{TaskList, List} = require '../src/task'

If you aren’t familiar with this syntax, that’s CoffeeScript’s destructured assignment at work, as well as some of its object literal sugar. Basically, our require call returns an object with two properties, which are our classes. This line pulls them out of that object and gives us two variables named Task and TaskList, each of which points to the respective class.


Writing Our First Tests

Great! Now, how about a test? The beauty of the Mocha syntax is that its blocks (describe and it) are identical to Jasmine’s (both being very similar to RSpec). Here’s our first test:

describe 'Task instance', ->
	task1 = task2 = null
	it 'should have a name', ->
		task1 = new Task 'feed the cat'
		task1.name.should.equal 'feed the cat'

We start with a describe call: all these tests are for a Test instance. By setting test1 = test2 = null outside our individual tests, we can use those values for multiple tests.

Then, in our first test, we’re simply creating a task and checking to see that its name property has the correct value. Before writing the code for this, let’s add two more tests:

it 'should be initially incomplete', ->
	task1.status.should.equal 'incomplete'
it 'should be able to be completed', ->
	task1.complete().should.be.true
	task1.status.should.equal 'complete'

Ok, let’s run these tests to make sure they’re failing. To do this, let’s open a command prompt and cd to your project folder. Then, run this command:

mocha --compilers coffee:coffee-script

Mocha doesn’t check for CoffeeScript by default, so we have to use the --compilers flag to tell Mocha what compiler to use if it finds a file with the coffee file extension. You should get errors that look like this:

If, instead of seeing that, you get the error Cannot find module '../src/task', it’s because your src/task.coffee file doesn’t exist yet. Make said file, and you should get said error.


Coding Our First Features

Well, now that we have failing tests, it’s time to write the code, correct? Open that src/task.coffee file and let’s get cracking.

class Task
	constructor: (@name) ->

Just this is enough to get our first test passing. If you aren’t familiar with that parameter syntax, that just sets whatever value was passed to new Task to the @name (or this.name) property. However, let’s add another line to that constructor:

@status = 'incomplete'

That’s good. Now, head back to the terminal and re-run our tests. You’ll find that—wait a second, nothing’s changed! Why aren’t our first two tests passing?

A simple problem, actually. Because the CoffeeScript compiler wraps the code in each file in a IIFE (or, a self-invoking anonymous function), we need to “export” anything we want to be accessible from other files. In the browser, you’d do something like window.Whatever = Whatever. For Node, you can use either global or exports. We’ll be using exports, since 1) that’s considered best practice, and 2) that’s what we prepared for when setting up our tests (remember our require call?). Therefore, at the end of our task.coffee file, add this:

root = exports ? window
root.Task = Task

With that in place, you should find that two of our three tests are now passing:

To get the last test to pass, we’ll have to add a complete method. Try this:

complete: ->
	@status = 'complete'
	true

Now, all tests pass:

Now’s a good time to mention that Mocha has a number of different reports: these are just different ways to output the test results. You can run mocha --reporters to see your options:

By default, Mocha uses the dot reporter. However, I prefer the spec reporter, so I tack -R spec on the end of command (-R is the reporter-setting flag).


Adding a Feature

Let’s add a feature to our Task class: we’ll let tasks be dependent on other tasks. If the “parent” task isn’t completed, the “child” task can’t be done. We’ll keep this feature simple and allow tasks to have only one sub-task. We also won’t check for recursiveness, so while it will be possible to set two tasks to be the parent and child of each other, it will render both tasks incomplete-able.

Tests first!

it 'should be able to be dependent on another task', ->
	task1 = new Task 'wash dishes'
	task2 = new Task 'dry dishes'

	task2.dependsOn task1

	task2.status.should.equal 'dependent'
	task2.parent.should.equal task1
	task1.child.should.equal task2

it 'should refuse completion it is dependent on an uncompleted task', ->
	(-> task2.complete()).should.throw "Dependent task 'wash dishes' is not completed."

Task instances are going to have a dependsOn method, which tasks the task that will become their parent. Tasks that have a parent task should have a status of “dependent.” Also, both tasks get either a parent or child property that points to the appropriate task instance.

In the second test there, we say that a task with an incomplete parent task should throw an error when its complete method is called. Notice how test syntax works: we need to call should off of a function, and not the result of the function: therefore, we wrap the function in parentheses. This way, the test library can call the function itself and check for the error.

Run those tests and you’ll see that both fail. Coding time!

dependsOn: (@parent) ->
	@parent.child = @
	@status = 'dependent'

Again, very simple: we just set the task parameter to the parent task, and give it a child property which points to this task instance. Then, we set the status of this task to be “dependent.”

If you run this now, you’ll see that one of our tests is passing, but the second isn’t: that’s because our complete method doesn’t check for an uncompleted parent task. Let’s change that.

complete: ->
	if @parent? and @parent.status isnt 'completed'
		throw "Dependent task '#{@parent.name}' is not completed."
	@status = 'complete'
	true

Here’s the completed complete method: if there’s a parent task, and it isn’t completed, we throw an error. Otherwise, we complete the task. Now, all tests should pass.


Building the TaskList

Next, we’ll build the TaskList class. Again, we’ll start with a test:

describe 'TaskList', ->
    taskList = null
    it 'should start with no tasks', ->
        taskList = new TaskList
        taskList.tasks.length.should.equal 0
        taskList.length.should.equal 0

This is old-hat to you by now: we’re creating a TaskList object and checking its tasks and length properties to makes sure their both at zero. As you might guess, tasks is an array that holds the tasks, while length is just a handy property that we’ll update when adding or removing tasks; it just saves us from having to write list.tasks.length.

To make this test pass, we’ll make this constructor:

class TaskList
	constructor: () ->
		@tasks = []
		@length = 0

Good start, and that gets our test passing.

We’ll want to be able to add tasks to a task list, right? We’ll have an add method that can take either a Task instance, or a string which it will convert to a Task instance.

Our tests:

it 'should accept new tasks as tasks', ->
    task = new Task 'buy milk'
    taskList.add task
    taskList.tasks[0].name.should.equal 'buy milk'
    taskList.length.should.equal 1
it 'should accept new tasks as string', ->
    taskList.add 'take out garbage'
    taskList.tasks[1].name.should.equal 'take out garbage'
    taskList.length.should.equal 2

First, we add an actual Task object, and check the taskList.tasks array to verify that it’s been added. Then, we add a string, and make sure that a Task object with the right name was added to the tasks array. In both cases, we check the length of taskList as well, to make sure that it’s being property updated.

And the function:

add: (task) ->
    if typeof task is 'string'
        @tasks.push new Task task
    else
        @tasks.push task
    @length = @tasks.length

Pretty self-explanatory, I think. And now our tests pass:

Of course, we might want to remove tasks from our list, right?

it 'should remove tasks', ->
	i = taskList.length - 1
	taskList.remove taskList.tasks[i]
	expect(taskList.tasks[i]).to.not.be.ok

First, we call the remove method (yet to be written, of course), passing it the last task currently in the list. Sure, we could just hardcode the index 1, but I’ve done it this way because that makes this test flexible: if we changed our previous tests or added more tests above this one, that might have to change. Of course, we have to remove the last one because otherwise, the task after it will take its place and there’ll be something at that index when we’re expecting there to be nothing.

And speaking of expecting, notice that we’re using the expect function and syntax here instead of our usual should. This is because taskList.tasks[i] will be undefined, which doesn’t inherit from Object.prototype, and therefore we can’t use should.

Oh, yeah, we still need to write that remove function:

remove: (task) ->
    i = @tasks.indexOf task
    @tasks = @tasks[0...i].concat @tasks[i+1..] if i > -1
    @length = @tasks.length

Some fancy array footwork combined with CoffeeScript’s ranges and array splicing shorthand closes this deal for us. We’re simply splitting off all the items before the one to remove and all the items after it; the we concat those two arrays together. Of course, we’ll update @length accordingly. Can you say “passing tests”?

Let’s do one more thing. We want to print our a (relatively) nice-looking list of the current tasks. This will be our most complex (or at least, our longest) test yet:

    it 'should print out the list', ->
        taskList = new TaskList
        task0 = new Task 'buy milk'
        task1 = new Task 'go to store'
        task2 = new Task 'another task'
        task3 = new Task 'sub-task'
        task4 = new Task 'sub-sub-task'

        taskList.add task0
        taskList.add task1
        taskList.add task2
        taskList.add task3
        taskList.add task4

        task0.dependsOn task1
        task4.dependsOn task3
        task3.dependsOn task2

        task1.complete()

        desiredOutput = """Tasks

- buy milk (depends on 'go to store')
- go to store (completed)
- another task
- sub-task (depends on 'another task')
- sub-sub-task (depends on 'sub-task')

"""
		taskList.print().should.equal desiredOutput

What’s going on here? First, we’re creating a new TaskList object so that we start from scratch. Then, we create five tasks and add them to taskList. Next, we set up a few dependencies. Finally we complete one of our tasks.

We’re using CoffeeScript’s heredoc syntax to create a multi-line string. As you can see, we’re keeping it pretty simple. If a task has a parent task, it’s mentioned in parentheses after the task name. If a task is completed, we put that, too.

Ready to write the function?

print: ->
    str = "Tasks

"
    for task in @tasks
        str += "- #{task.name}"
        str += " (depends on '#{task.parent.name}')" if task.parent?
        str += ' (complete)' if task.status is 'complete'
        str += "
"
    str

It’s actually pretty straightforward: we just look over the @tasks array and add ‘em to a string. If they have a parent, we add that, and if they’re complete, we add that too. Notice that we’re using the modifier form of the if statement, to tighten up our code. Then, we return the string.

Now, all our tests should pass:


Wrapping Up

Try adding a few features to get the hang of it all.

That’s the extent of our little project today. You can download the code from the top of this page; in fact, why don’t you try adding a few features to get the hang of it all? Here are a few ideas:

  • Prevent Task instances from being able to depend on each other (recursive dependencies).
  • Make the TaskList::add method throw an error if it receives something other than a string or a Task object.

These days, I’m finding CoffeeScript more and more attractive, but the biggest downside to it is that it must be compiled to JavaScript before it’s useful. I’m grateful for anything that negates some of that workflow breaker, and Mocha definitely does that. Of course, it’s not perfect (since it’s compiling to JS before running the code, line numbers in errors don’t match up with your CoffeeScript line numbers), but it’s a step in the right direction for me!

How about you? If you’re using CoffeeScript, how have you been doing testing? Let me know in the comments.


December 14 2011

20:43

Should You Learn CoffeeScript?

I’d imagine that I represent a large portion of the web development community. I’m very intrigued by CoffeeScript; I’ve even learned the syntax and used it in a few demos. However, I haven’t yet taken the plunge and used it in a real project. It comes down to this one question for me: is CoffeeScript something that is truly worth investing time and effort into learning?

I wasn’t sure, so I compiled a list of frequently asked questions (along with a few of my own), and asked some masters in the industry – on both sides of the fence – for their advice.

The Panel

  • Brendan Eich – The creator of JavaScript, and co-founder of Mozilla.
  • John-David Dalton – “I’m an opinionated JavaScript tinkerer, bug fixer & benchmark runner. I have a bachelor’s degree in Multimedia Instructional Design, an awesome wife & a puppy.”
  • Dave Ward – “I’m a software developer focusing on ASP.NET, jQuery, and web application usability.”
  • Marco Chomut – “I’m a Computer Scientist Extraordinaire living in the Washington, DC area. I specialize in web and mobile development, and love working with Django and Android.”
  • Trever Burnham – “Web developer and author.”
  • James Padolsey -” I am, by profession, a JS Developer with extensive experience in front-end application development adopting new and cool JS/HTML5/CSS3 techniques while employing a variety of frameworks.”
  • Nathan Smith – “I work as a user experience developer at Pure Charity.”
  • Ryan Florence – “I’m a front-end web developer from Salt Lake City, Utah and have been creating websites since the early 90′s.”
  • Oscar Godson – I am a Software Engineer at Yammer.
  • Alex MacCaw – I work at Twitter. Ruby/JavaScript developer, O’Reilly author and entrepreneur.

  • 1 – Perhaps the most common question: if I’m a reasonably solid JavaScript developer, is there any real incentive for me to learn CoffeeScript?

    Jeremy Ashkenas

    Yes. CoffeeScript is not an entirely new and strange language. It exists to allow “reasonably solid” JavaScript developers to write the same code they were going to write in the first place, in a more readable and fluent way. The basic idea is to write what you mean, instead of writing within the limits of historical accident. For example, if I want to loop over every item in a list, in CoffeeScript, I can write what I mean:

        for item in list
          process item
    

    Whereas in JavaScript, I partially obscure my intention, by writing:

        for (var i = 0, l = list.length; i < l; i++) {
          var item = list[i];
          process(item);
        }
    

    CoffeeScript allows “reasonably solid” JavaScript developers to accomplish the latter by simply writing the former.

    Other Incentives Include
    • The ability to write code that works in old versions of Internet Explorer without having to compromise or shim
    • Not having to worry about JavaScript pitfalls like trailing commas and automatic semicolon insertion
    • Cleaned up semantics where every language construct can be used as part of a larger expression
    • and a boatload of additional features listed on CoffeeScript.org

    James Padolsey

    If you’re comfortable in JavaScript, and are able to create expressive APIs that suit you well, then I don’t feel there is a sufficient incentive for learning CoffeeScript. Widening horizons and learning new programming paradigms and patterns is always good, but if you’re learning CoffeeScript so it can eventually replace your need for JavaScript then there are other things to consider.

    John-David Dalton

    If you’re great with JS, I don’t think there is any real incentive to learn CoffeeScript. Things like accidental leaked globals, switch statement fall-throughs, and other potential JS gotchas can be handled by JS linters/text-editors and don’t require a compile step / Node.js. Class sugar is so basic any JS developer can, if needed, simulate it in a handful of lines. I happen to like double equals ==, and switch statement fall-throughs, and know how best to write my JS.

    Having to conform to someone else’s rules of what they feel is appropriate doesn’t mesh well with me.

    Also, don’t forget CoffeeScript isn’t without its own warts.

    Dave Ward

    Continually exposing yourself to new perspectives and technologies is a critical part of keeping yourself relevant in our field.

    Absolutely. Continually exposing yourself to new perspectives and technologies is a critical part of keeping yourself relevant in our field, and CoffeeScript is certainly a great candidate for that in the JavaScript space. Even if you ultimately decide that CoffeeScript doesn’t appeal to you, being able to write a bit of CoffeeScript should be a prerequisite to making an informed decision either way.

    Nathan Smith

    I have been using CoffeeScript for a few months now, as part of my job as a front-end dev on a Rails team. I don’t know if I would say there’s “incentive” to learning CoffeeScript if you already know JavaScript. I’m not sure there would be an incredible speed boost to be gained, because really there is no “best” tool for a job, only one you’re most familiar with to accomplish a given task.

    Though I enjoy the comfy feel of JavaScript (like a well broken-in pair of shoes), there is also a lot to like in CoffeeScript — the “unless” syntax, for example. I would liken using CoffeeScript to having a conversation with a friend who majored in English, correcting your grammar all the while. It’s great if you want that guidance, but sometimes I just want to “keep it casual” and speak slang, without worrying about what that’s going to translate into.

    Note: I suspended judgment until after reading Trevor Burnham’s book on CoffeeScript. Now that I know more about it, I’m fine using CS when I am on a team that already uses it, but I still tend to prefer JS for my own projects.

    Ryan Florence

    Absolutely. CoffeeScript is influencing TC-39′s decisions (like paren-free, class syntax, arrow syntax, etc.). The future versions of JavaScript will likely look a lot like CoffeeScript. I decided to learn it after listening to Brendan mentioning its influence during his talk at TXJS.

    If there is anything to learn about CoffeeScript is that it’s _Just JavaScript™_. I consider it a part of our community and have really enjoyed learning it and using it. It doesn’t feel like a different language when you use it.

    Brendan Eich

    (Limiting my response to responding to Ryan Florence’s comments about TC39, except in my final paragraph.)

    The influence of CoffeeScript on TC39 in practice is mostly me writing and proposing strawmen. None has yet stuck. I’m going to retool paren-free to be more like CoffeeScript in that newlines will be more significant in statement heads (this solves some nasty hard cases Waldemar Horwat identified, see es-discuss). But no indentation-based block structure.

    Arrow function syntax was worth doing but it’s not going to make it. Block lambdas are in better shape but not yet “in”. As Jeremy said, “For the record, I too favor [block lambdas] if arrows in JS will need curlies to delimit blocks. Curlies or arrows, not both.”

    That JS and CoffeeScript are formally co-expressive — have the same semantics — is huge. Yes, this means you could have just written JS. But productivity and beauty (in the eyes of some beholders) matter; syntax matters.

    Oscar Godson

    In short, no. The incentives to CoffeeScript are incentives, in my opinion, that are for developers who don’t fully understand the language. For example, for…in loops and leaking globals and not understanding “this” fully. If you understand those things you don’t make those mistakes in the first place, and if you do, you know what the problem is right away and know how to fix them. Having an entire transpiled language to fix common mistakes seems like overkill.

    Marco Chomut

    Out of professional curiosity, you should always be exploring new languages, technologies, libraries, and frameworks.

    There are a few different approaches to answering this question. First and foremost, out of professional curiosity, you should always be exploring new languages, technologies, libraries, and frameworks. The worst thing that can happen to you as a developer is to become stuck in a rut. If the first language you learned was COBOL, ColdFusion, or PHP, and that’s still the breadth of your knowledge five years later, you’re just asking to become obsolete. Then again, it’s equally worse to jump ship onto the new flavor-of-the-month every time something mildly interesting appears in your news reader or Twitter feed. Have a healthy curiosity while maintaining reasonable skepticism.

    Arriving back on topic, if you and your co-workers are already well-versed in restricting yourselves to the “good parts” of JavaScript, and are painfully aware of its idiosyncrasies, than CoffeeScript probably won’t offer you much. It’s a more Ruby or Python-like approach to syntax for the language that does everything it can to prevent you or your team from shooting themselves in the foot. But it’s not for everyone.

    Trevor Burnham

    Obviously I have a financial stake in this question (my book was released by PragProg in May), so you can take my words with a grain of salt. But yes, I think that learning CoffeeScript is worth the time. It doesn’t take much effort to learn; CoffeeScript is basically the sum of a few dozen syntactic sugars on top of JavaScript. And the reward is that you get to write more beautiful code, when you want it. For instance, some JavaScripters use CoffeeScript just for their unit tests.

    Some folks complain about having to use a compiler on top of JavaScript, but some of JavaScript’s flaws—like automatic global creation when the var keyword is omitted (see here)—more or less necessitate the use of other tools, or strict mode. CoffeeScript is one such tool, and is easily among the most popular.

    Alex MacCaw

    My CoffeeScript programs end up as being about half the length of the equivalent source written in JavaScript.

    Absolutely; in fact I’d say there was even more of an incentive to learn CoffeeScript if you’re a solid JavaScript developer. CoffeeScript certainly requires some JavaScript profiency, there’s no getting away from it. JavaScript knowledge is a pre-requisite, especially when it comes to debugging.

    However, for good JavaScript developers, CoffeeScript offers a lot of advantages, such as fixing common bugs concerning global variables, semicolons and equality comparisons. Frankly, even the best JavaScript developers make these sort of simple mistakes from time to time.

    The other major advantage CoffeeScript offers me over JavaScript is syntactical sugar such as shorter function declarations, comprehensions and a simple class abstraction. My CoffeeScript programs end up as being about half the length of the equivalent source written in JavaScript, with twice the clarity.


    2 – Is CoffeeScript targeted at JavaScript developers? Or, is it for devs who prefer other languages, like Ruby, and haven’t yet learned the ins and outs of JS?

    Jeremy Ashkenas

    The core idea with CoffeeScript is to express JavaScript semantics in as readable and minimal a syntax as we can find.

    CoffeeScript is targeted at JavaScript developers. It certainly borrows ideas from other dynamic languages, including Python, Ruby and Perl. But ultimately, the core idea with CoffeeScript is to express JavaScript semantics in as readable and minimal a syntax as we can find.

    John-David Dalton

    It seems to me developers who prefer languages like Ruby gravitate more towards CoffeeScript than those that don’t. Although, it’s common to find developers having love / hate opinions about it in any group.

    Nathan Smith

    I think CoffeeScript is targeted at people that understand JavaScript, but for whom it isn’t their language of choice. Otherwise, (obviously) they would prefer to just be writing JS. Whether one knows the ins and outs of JS when starting with CS, it is essential if one is to get the most out of using CS.

    Oscar Godson

    I work at Yammer with a lot of senior JavaScript engineers; none use it. I noticed that the friends who do use it and are extremely happy about it are Rails people. For example, at Posterous, they use it but don’t have any real JavaScript engineers. We have Rails people here, but they only do Rails – not JavaScript.

    Ryan Florence

    I’d have to defer to Jeremy for that one, but I do think it appeals mostly to Rubyists who are finding they spend most of their day in JavaScript. CoffeeScript knowledge is not a substitute for JavaScript knowledge. Scope is kind of different; other than that, it’s just a cleaner syntax.

    Marco Chomut

    I’d definitely say that it’s targeting both existing JavaScript developers and those coming from other dynamic languages who are somewhat new to the front-end web world. I personally discovered it after already having a decent amount of “raw” JS experience, and it was refreshing to work with what I imagine a modern-day client-side language would look like. While it’s just my personal approach to learning things, I don’t think I would have dove straight into CoffeeScript without any prior knowledge of the language it was built upon.

    It’s important to always have at least a rudimentary understanding of whatever “black boxes” of abstraction exist in your toolkit.

    Trevor Burnham

    If you’re someone who likes JavaScript but wants to write more expressive code, CoffeeScript is going to be the obvious choice.

    CoffeeScript’s goal is to stay as close as possible to the underlying JavaScript while improving on the language’s syntax. That makes it very different from, say, Dart, or GWT, or something that reorders code like TameJS. So I think that if you’re someone who likes JavaScript but wants to write more expressive code, CoffeeScript is going to be the obvious choice.

    Obviously it’s disproportionately popular in the Ruby world, since it’s borrowed many Ruby-isms like postfix if/unless and has an extremely prominent evangelist in dhh, but it’s also quite popular in the Node.js world, which says a lot.

    Alex MacCaw

    I’ve used JavaScript for years, and wrote the O’Reilly book on JavaScript web applications. I think you could say I’ve learnt the ‘ins and outs’ of the language. That said, I personally plan to never write plain JavaScript again, not because I don’t like the language, but because I love writing CoffeeScript so much.

    CoffeeScript is for people who deeply understand and respect JavaScript.


    3 – When Dart was announced, it was met with immediate slander by much of the JS community. Though not an entirely different language, the same is partially true for CoffeeScript. Are some developers simply afraid of learning yet another new thing, or are their criticisms justified?

    Jeremy Ashkenas

    With the release of Dart, the web development community was faced with the peril of Google forcing a new, nonstandard language into a shipping web browser.

    Dart is a different story. With the release of Dart, the web development community was faced with the peril of Google forcing a new, nonstandard language into a shipping web browser. As we know well from the web — once you ship something in a browser, it tends to be there forever. In addition, Dart retreats from the dynamism of JavaScript, and instead exists as a somewhat static language, where types can be checked at compile time, but are erased at runtime. The JavaScript community perceived this as a cynical gesture to make Java developers feel more at home in Dart, being able to write types that appear similar to Java types, even though they’re treated as comments when the program runs. It’s not just JavaScript developers being wary of the Dart push, browser implementors are wary as well.

    Now, let’s take the CoffeeScript case. CoffeeScript has felt threatening to a surprising number of JavaScript developers, in a way that other languages have not. You don’t hear JS programmers worrying about other new languages like Clojure or Scala, or even compile-to-JS languages like GWT or Objective-J in anything approaching the same volume.

    Note that I’m not talking about people who simply choose to continue to use JavaScript — I continue to use JavaScript for many projects as well. I’m talking about the fearful rhetoric of “I won’t use your library because you wrote it in CoffeeScript”, or “CoffeeScript makes you forget how to write JavaScript.”

    CoffeeScript feels threatening to JavaScript developers precisely because it’s so close to JavaScript.

    Because the semantics are the same, every CoffeeScript program is fully interoperable with JavaScript, and vice-versa. You may already be using a library written in CoffeeScript without even knowing it (like Zombie.js, Riak-JS, or xml2js). In addition, CoffeeScript is actually being used — it’s currently the 13th most popular language on GitHub.

    As as JavaScript developer, confronting this situation — where there’s a fully compatible alternative to JavaScript, with the same performance profile — forces you to answer the question: “why haven’t you tried CoffeeScript yet?” Many of the posts that we’re seeing are developers justifying their answer to that question for themselves. If I hadn’t tried CoffeeScript yet, I’d probably be writing the same kind of posts.

    James Padolsey

    The real battle is creating clean, intuitive and maintainable APIs.

    Dart’s slightly different. One, it’s from Google! i.e. that massive monopoly that we’re supposed to be wary of. Beyond the various political issues, Dart doesn’t seem to bring anything to the table other than a more Java-esque syntax, which many developers aren’t too fond of, myself included. I prefer to stick to the most expressive API/languages I have at my disposal. When it comes to CoffeeScript, though, I am cautious because really, it’s just JavaScript, but with a completely different syntax. JavaScript’s malleable enough for me to create the APIs and functionality that I need. I don’t much care for convenience sugar unless it really enhances my ability to write good code. Some of CoffeeScript’s features, like destructuring assignment and the existential operator, are really quite awesome, but to be honest, they’re just minor sweetness, and similar functionality can be gained in JavaScript (see JS 1.7 for destructuring assignment too!), although with a little more verbosity. The real battle is creating clean, intuitive and maintainable APIs. CoffeeScript isn’t going to help you a great deal there. Like I said, it’s sugar.

    John-David Dalton

    I don’t think it’s being afraid of something new. For me at least, it’s more about not wanting to over-engineer and having more control over my JS.

    Dave Ward

    It’s difficult to speak for others, but I don’t get the impression that many JavaScript developers are avoiding CoffeeScript because they avoid new things. If anything, I think most developers who are aware of CoffeeScript at all are probably on the early adopter’s end of the curve.

    In particular, I believe that reluctance toward adding CoffeeScript’s compilation step into client-side development is objectively justified, not related to any previous investment in learning JavaScript.

    Nathan Smith

    With any potentially disruptive new technology, those who have staked their claim on the current way of doing things tend to go through the five “stages of grief.

    This was my experience, anyway…

    1. Denial — “I’ll never use CoffeeScript.” (or Dart)
    2. Anger — “I wish people would shut up about it already!”
    3. Bargaining — “Okay, I guess it has *some* good parts.”
    4. Depression — “I can’t believe I have to learn this.”
    5. Acceptance — *Shrug* ~ “Use the best tool for the job.”

    That said, there are some justifications to the criticisms of CoffeeScript (and Dart). However, whereas CoffeeScript attempts to adhere to the “spirit” of JavaScript (terse code, etc), the end-game for Dart is to get developers writing an entirely different language altogether (preferably interpreted in a browser’s VM, instead of being precompiled to JS). Dart is more akin to Java than JavaScript.

    The most valid criticism against any language that would attempt to supplant JavaScript is that JS has the world’s largest install base of any language runtime (on desktop browsers, server, and mobile devices). It might not be perfect, but as far as distribution goes, it “just works.”

    Brendan Eich has already expressed his interest in seeing aspects of CS folded back into future versions of ECMAScript. By contrast, Dart has been met with harsher criticism from not only JS developers, but from the WebKit community.

    Oscar Godson

    Yes and no. I tend to be more critical of things before I’ve tried them, but I did try CoffeeScript to see what all the hype was about. It was nice, but it’s not worth it. Why have a compiled language to *just* help you with common JS warts and to make JS more “pretty”? That’s what puts me off about it. JavaScript engineers do tend to be elitist though, I agree with that, but in this case I believe it’s for a good reason. The reason being, don’t write a totally different language to fix some warts about it.

    Ryan Florence

    [...] We’re just so tired of fragmentation.

    CoffeeScript and Dart aren’t even comparable. Dart aims to replace JavaScript, CoffeeScript is nothing more than a nice coat of paint. You can use CoffeeScript and still “always bet on JS”. I think front-end devs are happy to learn new things (our environment is always broken, you’d have to like learning stuff to survive), we’re just so tired of fragmentation. It’s completely justified to freak out if you see “ActiveX 2.0″ coming. CoffeeScript is not a threat to JavaScript.

    Marco Chomut

    I believe both reactions were equally justified (although when Google is involved, people always tend to exaggerate their opinions one way or the other for whatever reason). CoffeeScript was a re-imagining of JavaScript from the Ruby and Python communities. Dart was a re-imagining from a subset of the Java community. Language biases aside, I honestly don’t believe that Java-fying an already dynamic and (arguably) verbose language is the correct approach.

    It probably didn’t help that the JavaScript community was already allergic to the idea of Dart before it was even announced, due to the set of “leaked” correspondance surrounding it.

    Trevor Burnham

    Of course some of the criticisms of CoffeeScript are justified. I mean, “significant whitespace is evil” is a lame one, but “it divides the community” is legit. There’s something to be said for JS being a lingua franca. But you look at very common JS mistakes like forgetting a comma in a multi-line object literal (or adding an extra one at the end of the last line), and it causes your whole app to crash… for a certain kind of programmer (myself included), not having to deal with that is a big breath of fresh air.

    I think CoffeeScript and JS are going to peacefully coexist for the foreseeable future, and there are gonna be haters, and that’s fine. That’s how you know it’s a real programming language.

    Alex MacCaw

    CoffeeScript doesn’t intend to replace JavaScript, or abstract it away, but rather to enhance it.

    As others have mentioned, Dart is a completely different beast to CoffeeScript, and many of the criticisms directed at Dart were regarding implementation details and Google’s approach, rather than just the existence of another language. Frankly, CoffeeScript is an entirely different language to Dart.

    Google took rather a walled garden approach to Dart, and I get the impression they didn’t really look outside the confines of their company for inspiration. Whether this was because of some sort of Not Invented Here syndrome, or the fact that they needed a language that would appeal to their Java developers, I’m not sure. However, Dart strikes me as something that is very specific to Google’s needs, rather than something that’s applicable at large.

    CoffeeScript doesn’t intend to replace JavaScript, or abstract it away, but rather to enhance it. So, not only are the languages completely different, but the motives behind them are very different. Thus it’s difficult to compare criticism between the two.


    4 – Is it a fair to assume that, if you’re against the idea of CoffeeScript, then you’re likely also against CSS preprocessors, like Sass and Less? Or, do you see a specific distinction between the two (as I do)?

    James Padolsey

    I’ve never used Sass or Less so I can’t really comment. I will say that the general idea is the same in that they’re all slightly heightening the level of abstraction, allowing you to quickly get at functionality without having to type the verbose alternative. I will say that the thing keeping me from picking up CoffeeScript is very different to what would keep me from picking up a CSS preprocessor.

    John-David Dalton

    I don’t work heavily with CSS and haven’t used a CSS preprocessor but I can understand the need to manage the cluster of vendor prefixes. I’m also not as comfortable with CSS as I am with JS.

    Nathan Smith

    I don’t think that is an entirely accurate assumption. While there might be some who are against all preprocessing of client-side code, with Sass (and Compass) you get a layer atop CSS that’s very “close to the metal” in terms of syntax. One of the benefits of Compass is the ability to write one line that is transformed into multiple lines of vendor prefixed code. One needn’t memorize different variations on the same styling that will ultimately be deprecated when a standard is agreed upon. Sass (with Compass) example:

    #foobar
      +background(linear-gradient(#fff, #ccc))
    

    That reads cleanly, and is somewhat similar to what the standard might become in CSS.

    CoffeeScript, on the other hand, adds a new syntactic layer that seeks to be a departure from JavaScript, incorporating idioms from other languages that are not native to JS.

    Sass adds variables, color math, and a slew of things that cannot be done in CSS alone. Whereas, CoffeeScript provides an alternative approach to what JavaScript is already perfectly capable of doing. I believe that’s why we’re having this discussion — Some see value in that. Others don’t.

    Oscar Godson

    I personally have nothing against CSS preprocessors because they add functionality. I don’t use them because I’m a purist you could say, but they do save time with less typing – particularly for people who do lots of CSS coding. They also don’t aim to fix “broken” things – just extend it. I don’t use it and don’t see myself ever using it for personal stuff but I’m not opposed to using it.

    Ryan Florence

    There is a distinction. SASS, Less, Stylus etc. all bring something to CSS that it doesn’t already have.

    There is a distinction. SASS, Less, Stylus etc. all bring something to CSS that it doesn’t already have: logic–it turns your CSS into an application. CoffeeScript doesn’t bring anything “new” to JavaScript in the same way, which is why it’s so debatable. Not using a CSS preprocessor isn’t really even debatable for anything non-trivial.

    Marco Chomut

    CoffeeScript provides cleaner syntax…

    I’m going to have to agree with the other answers here that the CSS “equivalents” of CoffeeScript, such as SASS or Less, are often judged quite differently. For me, SASS is always a default on any new project that I work on, while CoffeeScript continues to be debatable. CoffeeScript provides cleaner syntax, does its best to keep a developer shielded from the bad parts of JavaScript, and allows you to avoid prototype-based inheritance with its built-in class structure. SASS on the other hand offers a slew of (very-necessary) features to CSS that you would otherwise not be able to have. Variables, functions, mixins, the list goes on and on. CoffeeScript doesn’t really offer any of these meta-features to JavaScript, and really just boils down to syntactic sugar.

    Trevor Burnham

    I’m honestly amazed that people are still using Sass/SCSS.

    Sass is an interesting example because it went through a big split itself: Originally, it was a fully whitespace-significant alternative to CSS, and of course some people loved that and others hated it. Now it comes in two flavors: The whitespace-significant “Sass Classic” syntax, and the CSS superset SCSS. They’re both annoyingly strict; the “Sass Classic” compiler will yell at you if you use so much as a semicolon. Then TJ Holowaychuk came along and created Stylus, which lets you use whitespace-significant syntax and curly-brace syntax… in the same file! It’s a much more elegant solution, and I’m honestly amazed that people are still using Sass/SCSS.

    Which isn’t to say that CoffeeScript should start accepting curly braces (there would be some ambiguous cases). My point is just that CSS preprocessors aren’t really about cleaner/terser syntax the way CoffeeScript is. (The SCSS syntax is more popular than Sass Classic, probably because designers can keep using the CSS snippets they’re used to without running them through a converter.) They’re about doing things in a totally different way. CSS isn’t really a language; CSS preprocessors (with their variables and functions) are.

    Rebuttle from Nathan Smith:

    CSS *is* a language. Just not a “programming” language. I see his point though, preprocessors allow for declarative, functional programming.

    Alex MacCaw

    Well, I don’t think that’s necessarily the case. I personally enjoy Less and Stylus, as much as I enjoy CoffeeScript. However, I’m not a fan of HTML abstractions such as HAML and Jade. I evaluate each technology independently. I’m not for or against preprocessors in general.


    5 – A frequent criticism of CoffeeScript is that, if everyone uses it, we may get to a point when nobody remembers (or ever learned) how to write actual JavaScript. Is this a valid concern?

    Jeremy Ashkenas

    Nope — CoffeeScript exposes a subset of JavaScript semantics. If you learn how to write CoffeeScript, almost by definition you’ll know how to write JavaScript. Learning isn’t a zero-sum game. Learning one language or dialect doesn’t prevent you from knowing others.

    In fact, just as people who are comfortable speaking several languages find it easy to pick up more; programmers who know more than one dialect of JavaScript may be better able to learn new concepts and idioms.

    John-David Dalton

    No. As it is CoffeeScript compiles to JS so developers still have to deal with JS when debugging, for the time being, and can still use JS through the supported embedding syntax.

    - http://jashkenas.github.com/coffee-script/#embedded
    - https://bugs.webkit.org/show_bug.cgi?id=30933
    - https://bugzilla.mozilla.org/show_bug.cgi?id=618650

    Dave Ward

    Various tools and frameworks have been “compiling” to HTML for nearly as long as HTML has existed

    No, I don’t think that’s likely.

    Various tools and frameworks have been “compiling” to HTML for nearly as long as HTML has existed, yet knowledge of (and appreciation for) the generated HTML markup has only increased during that time. With most abstractions, you inevitably find yourself dealing with edge cases that force you to learn more deeply about the underlying technology. If anything, a simple abstraction over something more daunting often provides an appealing onramp for new developers, eventually leading them to learn more about the abstracted topic than they would otherwise have been comfortable with.

    Nathan Smith

    If CoffeeScript goes “mainstream” then more people will take an interest in the JavaScript language itself.

    I actually think (hope) maybe the opposite will be true. I think that if CoffeeScript goes “mainstream” then more people will take an interest in the JavaScript language itself. I have met quite a few designers who didn’t care about JavaScript at all, but learned how to cut and paste jQuery snippets. Before long, they’re saying “Man, I really need to learn JavaScript.”

    Just as jQuery ignited interest in JS amongst designers with its “reads like CSS” selectors, I think that perhaps CoffeeScript will be that “gateway drug” to greater JS understanding, except for Rubyists. Either way, those who already know JS have a leg-up.

    Oscar Godson

    Have you been to StackOverflow recently? Try asking a question about JavaScript. I once asked about doing some date parsing (to get the next Wed.) and someone sent me an entire jQuery plugin. It ended up being a one liner and the jQuery plugin got the most votes compared to the right one line answer. This has happened with jQuery where people just pick up jQuery and never bother to learn JavaScript. On Twitter I overheard someone asking about cookie sessions and someone suggested they use jQuery and include a $.cookie plugin. Im worried that CoffeeScript is going to end up like this where people will be including this for simple apps or when they just dont really want to understand JS.

    Ryan Florence

    You can’t write CoffeeScript without knowing JavaScript. You are debugging the JavaScript. You’re using third-party libs that are JavaScript. You can’t get away from it (the great flaw in using CoffeeScript for real world applications). So no, its not a valid argument for being against CoffeeScript.

    The fact that this argument is flawed is a solid argument to not use CoffeeScript. If you can’t break from JavaScript, what’s the point?

    Marco Chomut

    Similar arguments were made around the time that jQuery was becoming quite popular. I don’t believe that it was a valid concern then, and I don’t think it is now. Learning CoffeeScript will also require you to at some point buckle-down and learn the underlying JavaScript. This isn’t really something that you can avoid, until the day comes (if ever) that browsers parse and execute it natively. You’re going to run into the odd error or interaction that will force you to understand what it’s translating into.

    Trevor Burnham

    You shouldn’t use CoffeeScript without knowing JavaScript.

    What Ryan said.

    You shouldn’t use CoffeeScript without knowing JavaScript, although you can learn both at the same time. I mean, there must be a million people out there who are using JavaScript without really knowing JavaScript. A lot of them have other primary languages, and they’ll never really like JavaScript as much as they like Ruby, or PHP, or Java, so they only learn as much as they need to get by. That’s the sort of crowd my book is mainly aimed at. It’s like “Hey, let’s learn this hip new language, and along the way we’ll fill in the gaps in our JavaScript knowledge.”

    Alex MacCaw

    On the contrary, it’s quite the opposite. I don’t think this is a valid concern. As the others have stated, JavaScript knowledge is a requirement for writing CoffeeScript. Thus by writing CoffeeScript I think your JavaScript knowledge should, if anything, improve.

    The JavaScript generated by the CoffeeScript compiler is top notch, and by browsing through it you certainly learn a few tricks.

    However, I completely disagree that the fact you can’t break from JavaScript is an argument not to use CoffeeScript. CoffeeScript is a lightweight curated subset of the language, improving it’s syntax and only presenting the ‘good parts’. In other words, I think it’s an improvement.


    6 – One argument in favor of CoffeeScript that I rarely see put forth is that it can make you a better JavaScript developer – particularly if you’re somewhat new to the language. Similar to Rails, a huge array of best practices are baked into the compiler. Do you see benefit in that aspect? Use CoffeeScript to become a better JavaScript developer?

    Jeremy Ashkenas

    A large number of users have reported learning new tricks and patterns from reading their compiled JavaScript.

    Yes. A large number of users have reported learning new tricks and patterns from reading their compiled JavaScript.

    But having best practices built in to the compiler doesn’t mainly benefit beginners — the benefit is to long-term programmers who can take full advantage of having a concise, readable way to express their JavaScript intentions in code — without having to constantly keep best practice patterns in mind. A best practice that can be enforced and generated by a compiler is better than a best practice that has to be remembered and manually typed out every time.

    James Padolsey

    The only problem I see with taking this approach is that you’re not really learning JavaScript, and there’s so much magic going on that you won’t necessarily be appreciating the lengths that you might have to go to in order to get similar things done in JavaScript. CoffeeScript is easier for these tasks.

    It will teach you to become a better programmer, I think, but if you want to learn JavaScript, then learn it, purely.

    John-David Dalton

    I think you can take the “it makes you a better JS developer” and apply that to existing JS libs/frameworks. I learned a lot from digging into and fixing issues in libs like Dojo, jQuery, MooTools, and Prototype. The code produced by CoffeeScript is extraneously verbose and promotes micro-optimizations (which isn’t necessarily helpful and not a “best practice”).

    I would not look to CoffeeScript or its compiled JS to improve my JS skills and would rather look to mature battle hardened JS libs.

    Dave Ward

    If someone wants to become a better JavaScript developer, there are less circuitous routes. I think the main things that make JavaScript difficult for beginners are more conceptual than syntactical. CoffeeScript doesn’t change the fact that you need to understand concepts like closures, asynchronous programming, and continuation passing to write non-trivial JavaScript code.

    Nathan Smith

    I think there is some truth to this. If you are consistently checking what JavaScript is output by the CoffeeScript compiler, I think there are some insights to be gleaned. For instance, declaring all variables at the beginning of a function, to prevent variable hoisting.

    Additionally, the concept of closures is introduced automatically. This might seem frustrating at first, if just trying to create a global variable, directly inline within (emitting something from the server-side in HTML). Due to this, CoffeeScript enforces good habits, such as explicitly attaching variables to the global object, if that is indeed what you mean to do…

    // Global variable in CoffeeScript
    window.foobar = 'something'
    
    //=====//
    
    (function() {
      // CoffeeScript output.
      window.foobar = 'something';
    }).call(this);
    
    // Versus:
    
    (function() {
      // Manual typo.
      foobar = 'something';
    })();
    

    That’s not to say such lessons cannot be learned apart from using a transpiler, but if someone new to JavaScript sought to use CoffeeScript as a way to learn about JS concepts, it might be an interesting place to start. Though, for JS beginners, reading canonical books like “JavaScript: The Good Parts” would probably be more helpful.

    Oscar Godson

    How do you learn or become better at something you’ve been shielded from? If you never have to worry about global vars leaking how do you know later when working with vanilla JS? It’s like giving someone a camera with auto-focus who’s never used a camera before and then expecting them to know how to use a film camera and adjust the focus, ISO, etc by manual means.

    Ryan Florence

    My hand-written JavaScript is pretty different from what CoffeeScript spits out.

    I think developers who aren’t very experienced in JavaScript have something to learn from the compiler’s output. Take the ?= and ||= operators, CoffeeScript shows them how to solve that problem in JavaScript.

    But they are also going to have a hard time debugging code they don’t understand. I don’t think these people can effectively use CoffeeScript.

    My hand-written JavaScript is pretty different from what CoffeeScript spits out; it’s also better looking. I think there’s more to learn by reading the source code of some of our community leaders and established JS libraries than from the compiler.

    Marco Chomut

    If, as a developer, you weren’t already exposed to the finer portions of JavaScript (either through Douglas Crockford’s JSLint or Anton Kovalyov’s JSHint), then CoffeeScript will definitely be a decent crash-course in the subject. But only if you take the chance to really understand why CS made certain decisions in the language. If you rush through it and merely try to push out a working prototype as fast as possible, you’re only harming yourself in the long run. I mentioned it before in a previous answer, but being unaware of some of the inner workings of your black boxes is very dangerous and counter-productive.

    Trevor Burnham

    Sounds like you’ve been attending my talks; I put this argument forward all the time.

    It’s interesting that you mention Rails. A lot of people learn Ruby by learning Rails. A lot of people learn JavaScript by learning jQuery. But if you learn that way, you’re not going to see the whole language. By contrast, you work through something on CoffeeScript, you’re going to see the edges. You’re going to learn all about this and prototype inheritance and typeof/instanceof and iterating through object keys and array values, and a hundred other things that JS noobs ask about on Stack Overflow every day.

    So yeah. I see learning CoffeeScript as one path to becoming a knowledgeable JavaScripter. Certainly not the only one, but one that’s fun and rewarding.


    7 – Clearly, if you’re a Ruby developer, CoffeeScript will be infinitely more appealing to you, as the syntax is fairly similar. For real world projects, where developers have deadlines, is CoffeeScript not simply a way to get the job done more quickly, with less language shuffling? What’s wrong with that, if anything?

    Jeremy Ashkenas

    Some Rubyists say that CoffeeScript looks like Ruby, Pythonistas say that CoffeeScript looks like Python, and I’ve heard Haskellers say that CoffeeScript looks like Haskell.

    I’m afraid that this is a silly question. Some Rubyists say that CoffeeScript looks like Ruby, Pythonistas say that CoffeeScript looks like Python, and I’ve heard Haskellers say that CoffeeScript looks like Haskell. The truth of the matter is that CoffeeScript semantics are just JavaScript semantics — there’s definitely no less “language shuffling” involved.

    James Padolsey

    I fear it will become acceptable to forgo the vital learning curve of JavaScript and simply rest falsely assured that the code you write in CoffeeScript works just like it would in that-other-language-you-know. For a team with a deadline I can definitely see the appeal of having a more unified development environment. Ruby and CoffeeScript are a cute match — much more so than JavaScript and Ruby. I think an understanding of JavaScript is vital, especially at this early stage (debugging can still be a nuisance).

    John-David Dalton

    Depends on their setup. CoffeeScript, like JS libs, has bugs from release to release (even some which affect cross-browser use) which can cause existing CoffeeScript code to break.

    Also, debugging still requires digging through raw JS and may not necessarily be an easy task as CoffeeScript applications become more complex.

    Unlike JS libs which can live on CDNs, the sugar around CoffeeScript has to be compiled for every JS file (unless compiled together). This can make CoffeeScript generated JS less ideal for separate third-party scripts. CoffeeScript adds yet another “something” the team will have to familiarize themselves with and become proficient in, which costs time/money and could be avoided by simply using JS (JS lib + linter).

    Dave Ward

    As someone who has spent quite a bit of time in the .NET world, I’ve seen that argument used to support drag ‘n drop development and some particularly leaky abstractions over HTML, CSS, and JavaScript. That experience has left me extremely skeptical about the long-term value of focusing on up-front productivity at the expense of understanding your development stack.

    Nathan Smith

    I wouldn’t say it’s a way to avoid “language shuffling.” Though CoffeeScript and Ruby might share some syntactic sugar, each has its own ways of dealing with things. While CS will no doubt look familiar to Ruby developers, there is still a learning curve.

    If you are under the gun on a deadline, deciding to use CoffeeScript is probably not going to help you get that work done any sooner. As with any new language, you need to set aside some time to get familiar with it, make beginner mistakes, and finally end up at a place where it becomes second nature.

    I think the danger to Ruby developers is hoping that CoffeeScript will gloss over some perceived mysterious aspects inherent to JavaScript.

    While you might end up typing less overall characters in a *.coffee file, you still need to care about what ends up in the *.js file. That comes with experience, not (only) with new syntax.

    Ryan Florence

    You write in one language, but debug in another…

    As for “less language shuffling” I assume you mean it’s like Ruby everywhere in your app–that is totally false. You write in one language, but debug in another language and neither is Ruby, so it’s actually more shuffling.

    If JavaScript’s syntax is slowing you down, then you need to learn how to use your text editor or learn how to type. There is nothing faster about CoffeeScript. Introducing CoffeeScript into your workflow actually increases “shuffling”:

    A lot of people gloss over the debugging issue but 20% of the day we write bugs, the other 80% we fix them (don’t deny it). Debugging is a big issue.

    You are debugging code you didn’t write. You have to figure out what the compiler is doing, and then figure out why the code is not doing what you wanted. Then you have to go to your CoffeeScript and figure out how to fix it in a different syntax. Usually it’s not that bad, but when using some of the fancier features of CoffeeScript it can get really “machine code” looking. One line in CoffeeScript can turn into several lines of crazy looking stuff (see here), that, again, you didn’t write, so you have to figure out why it looks that way, and then why it’s broken.

    This back-and-forth “shuffling” is a weird step that slows you down because it’s not _your_ code you’re looking at. I find I’m back to doing a lot of console.log in my code instead of using break points and watch expressions, etc., which is a total shame, and slower. But it’s the fastest way for me to “shuffle” between the JavaScript I’m debugging and the CoffeeScript I’m writing.

    Trevor Burnham

    Will CoffeeScript get the job done more quickly? Certainly some prominent JavaScript/Ruby pros have reached that conclusion for themselves.

    Rubyists are certainly easier to sell on CoffeeScript than, say, Java programmers. But the most common questions I get from Rubyists are along the lines of “Wait, why do we need a separate language? Why can’t we just compile Ruby to JS?” And I try to explain to them that, well, compiling “a = b” from Ruby into JS would require you to check whether b is a function, and if it is then run it and return its value… and compiling “x = y + 1” would require you to fire up a BigDecimal library, because all Ruby numbers are infinite-precision… and so on. Those folks have to learn that, look, when you’re in the browser, you’re on JavaScript’s turf and you’ve got to make peace with it. It could be worse. It could be statically typed.

    Will CoffeeScript get the job done more quickly? Certainly some prominent JavaScript/Ruby pros (like 37signals’ Sam Stephenson, creator of Prototype.js) have reached that conclusion for themselves. Obviously it depends on a lot of factors… sometimes what you need is a fresh perspective, and a new language can give you that.

    Alex MacCaw

    CoffeeScript isn’t inherently Rubyish.

    That’s a pretty leading question, and I don’t think that assumption is necessarily valid. CoffeeScript isn’t inherently Rubyish, just as it’s not inherently Pythonist. It borrows features from both languages but ultimately its schematics are inspired by JavaScript. The aim of CoffeeScript is not to abstract away JavaScript for developers who don’t want to learn it, such as the now defunct RJS. As such, it doesn’t help with language shuffling.


    8 – Many might argue that CoffeeScript allows for more beautiful and maintainable code. For example, creating a class in CS is considerably more intuitive and readable than what we might write with plain JavaScript.

    It’s not surprising that many will prefer the cleaner and shorter:

    class MyClass
      constructor: ->
        alert 'constructor'
    
      doSomething: ->
        alert 'doing something'
    
    c = new MyClass()
    c.doSomething()
    

    Over…

    var MyClass = (function() {
      function MyClass() {
        alert('constructor');
      }
    
      MyClass.prototype.doSomething = function() {
        alert('doing something');
      };
    
      return MyClass;
    })();
    
    c = new MyClass();
    c.doSomething();
    

    My question is: does CoffeeScript’s readability alone warrant its usage?

    Jeremy Ashkenas

    You can write undreadable code in any language.

    You can write undreadable code in any language … but yes — one of the main focuses of CoffeeScript is readability: expressing JavaScript concepts and patterns in as minimal and readable a way as we can find.

    Your “class” example is a good one. If you want to make many objects that share common methods in JavaScript — it’s not easy to accomplish. There are many ways to break the “prototype” object while you try to set up the prototype chain. You’re left either writing unreadable boilerplate every time you wish to chain two prototypes together, or using a helper library that hides basic object orientation from you. CoffeeScript’s classes are a simple way to define your constructor functions along with their prototypal properties and prototype chain. The side effect is the readability of simply writing what you mean:

        class Square extends Shape
        

    … instead of a half dozen lines of prototype manipulation code in JavaScript:

        function Square() {
          ...
        };
        var tempConstructor = function(){
          this.constructor = Square;
        };
        tempConstructor.prototype = Shape.prototype;
        Square.prototype = new tempConstructor;
    

    James Padolsey

    Naturally, because I’ve worked more with JavaScript, it’s more readable to me than CoffeeScript.

    That’s not the JavaScript I would write, but I see your point. CoffeeScript can have great readability and most of the CS code I’ve seen is both terse and expressive, but I don’t think this necessarily translates to “more intuitive”. Naturally, because I’ve worked more with JavaScript, it’s more readable to me than CoffeeScript. Again, this seems to be about taste, and is very much influenced by prior language exposure. A Ruby person would probably understand the CoffeeScript code sooner than the JavaScript, but it would be the opposite for, say, a PHP or Java developer, where keywords play a central role in class and function definition. In CoffeeScript you have very minimal and expressive operators which aren’t always as clear.

    John-David Dalton

    No. Developers have different opinions on what they consider readable. CoffeeScript is similar to JS libs in that they all add syntactic sugar and each developer/team has their own preference (MooTools, jQuery, Dojo, CoffeeScript, CoffeeScript+libs, and on and on).

    Dave Ward

    If you want syntactic sugar around structuring your code, there are JavaScript libraries to help with that without requiring the obtrusive compilation step.

    If you want syntactic sugar around structuring your code, there are JavaScript libraries to help with that without requiring the obtrusive compilation step.

    Considering this question in the overall context of the others, the developer who doesn’t yet understand JavaScript needs more than a somewhat similar analog to their server-side language’s implementation of classical inheritance. I believe putting the “class” pseudo-keyword in front of a developer coming from a typical object oriented language may even be harmful in the long run.

    Nathan Smith

    “Readability” is subjective. I think you’ve touched on something with the “class” example. For developers coming from a classical programming background (C#, Ruby, etc), CoffeeScript probably feels like a breath of fresh air. To me, having learned JavaScript as my first “real” programming language, thinking in terms of classes feels foreign.

    In my opinion, the perfect blend of CS and JS would be var added automagically, and not needing to write unnecessary parenthesis or curly braces. However, I could do without the automatic return at the end of each function.

    I am also not a fan of how CS hijacks the for in to become an i++ loop — requiring instead that you write for of to be able to iterate through objects (when *.length isn’t present).

    Oscar Godson

    This might be because JavaScript isn’t a class based language. It’s prototypal, and that scares people who aren’t used to it. PHP or Rails developers come to JS, and don’t know how to use it properly. So they come up with hacks to make it work and even look like other languages. This isn’t the answer. If you do need to use classes, you can write a mini-lib and make it clean like:

    var Ninja = Person.extend({
      init: function(){
        this._super( false );
      },
      dance: function(){
        // Call the inherited version of dance()
        return this._super();
      },
      swingSword: function(){
        return true;
      }});
    
    // via http://ejohn.org/blog/simple-javascript-inheritance/
      

    The only real difference is no parenthesis. I actually like Brendan Eich’s idea of paran-free JS, but I like the idea of it being baked in and not completely changing the language.

    Ryan Florence

    I review code on gerrit from my team every day. Some JavaScript, some CoffeeScript. I have as hard a time following what they’re trying to do in one syntax vs. the other. It’s perhaps more verbally readable at times, but that has yet to make it more understandable for me. Take this line for example:

    scores = (student["assignment_#{@assignment.id}"].score for own idx, student of @gradebook.students when student["assignment_#{@assignment.id}"]?.score?)
    

    That’s 160 columns of verbally readable code straight out of our app but I have no idea what it’s doing. The fun part is that you end up debugging things like this.

    There are some aspects to CoffeeScript that are less readable.

    The fat arrow => binds the context to the function, which sounds great, but it encourages deep nesting, an anti-pattern.

    Couple that with significant whitespace over several lines of code and you’ve got a mess. Unstructured code with callbacks and lots of if else going on is extremely hard to follow: there’s no closing bracket for me to place my cursor over and see where I’m at with my text editor. Some say, “Don’t write code like that”. I don’t write all the code I work with.

    Also, not all APIs have functions as the last argument to their signature, so you end up with some commas floating around at the beginning of lines, which looks really weird next to the rest of CoffeeScript’s generally appealing look.

    On the flip side, I’ve noticed that the class syntax hits a logical chord in people who aren’t JavaScript experts but experts in some other language(s). Suddenly they grasp that they can write modular front-end code instead of chaining jQuery down to oblivion. I personally don’t use class, or write JavaScript the way you did in the example, but I think its a useful syntax for good programmers less familiar with JavaScript.

    Trevor Burnham

    As far as readability is concerned, there’s no substitute for good documentation. I look at the annotated source for Backbone.js, and I think, “Wow.” It’d be maybe 30% fewer lines if it were written in CoffeeScript, but it’d only be marginally easier to understand.

    I think the bigger win is in writability. It’s not just fewer keystrokes (typing is rarely a bottleneck for coding); it’s less to think about. A common Node.js idiom is writing:

      if (typeof err != null) throw err;
      > that's not correct JS as `typeof err` will result in a string value
    

    …at the top of callbacks. I could save that as a snippet, I guess, but I’d much rather just punch in the CoffeeScript equivalent:

      throw err if err?
      > if (err) throw err;
      

    It just takes fewer brain cycles. That way, I can focus more on the core of the callback.

    Alex MacCaw

    Sure, that’s a good reason to learn CoffeeScript, or indeed any high level language. Readability is a crucial part to developing, maintaining and extending code in any language. CoffeeScript takes this a step further by using whitespace, meaning that badly formatted code will simply fail to compile.

    Of course it’s possible to write ugly code in any language, but I definitely think CoffeeScript has an inherit aesthetic beauty to it, in both the language and the community; much more so than traditional JavaScript.


    Closing Arguments

    Jeremy Ashkenas

    I’d like to file my general objection to the way in which these questions are framed. They create false drama where none needs to exist. CoffeeScript is a fun little language that attempts to push JavaScript in a certain direction: How minimal and readable a syntax can we find to express the famous good parts of JavaScript. If you enjoy it, that’s great; if you don’t, that’s great as well — JavaScript is a wonderful language. Because CoffeeScript and JavaScript share semantics, they’ll always get along just fine. Personally, I write a good deal of both.

    Interviewer’s Notes: Absolutely. It was never my intention to create a flame war, when, ultimately, we’re dealing with helpful tools. That can never be a bad thing! That said, the questions I’ve provided are the ones that I found to be most frequently asked on Twitter, blogs, and social networks. Even if they’re unfounded, it’s important to acknowledge that they are being asked, and discuss them. :)

    Ryan Florence

    I think CoffeeScript is an excellent choice for hobbyist and one-man operations. On a team, I would advise against it if you aren’t already down the path.

    Trevor Burnham

    What Ryan said. Learn JavaScript. It’s an awesome language. But it’s not my favorite language, because there’s CoffeeScript.

    John-David Dalton

    +1 to Ryan Florence’s side note.

    Nathan Smith

    I don’t think anyone can deny that Jeremy Ashkenas has created something remarkable. The fact we’re all talking about it testament to that. I would encourage anyone who has dug-in their heels against using CoffeeScript to at least give it a shot. Having done so myself, I still prefer JavaScript, but at least now I can appreciate why it’s appealing to others.


    Further CoffeeScript Resources

  • JSConf 2011 Presentation
  • A Cup of CoffeeScript
  • Rocking Out with CoffeeScript
  • A Case Against CoffeeScript

  • A Question for the Readers

    Now that some of the best in the business have offered there own opinions, I’d like to hear from you in the comments. While most of these questions came courtesy of social networks and blog posts, this last question is one that I was personally most interested in learning the answer to.

    One of my only concerns with using CoffeeScript is that debugging the generated JavaScript could potentially be a huge concern. Have you found this to be the case?

    Let me know below!


    December 20 2010

    16:10

    Rocking Out With CoffeeScript


    Even though CoffeeScript is a new language, you’ll learn it very quickly. You should, since it’s only JavaScript flaunting with some flashy clothes, after all. It reads like Ruby or Python, but compiles down to pure, non-fluffy JavaScript. Today, we’re going to take a look at why everyone is talking about CoffeeScript.


    A Word From the Author

    With the advent of powerful JavaScript engines, like V8, JavaScript has shed its stigma of a gimped tool for juvenile interactions and morphed into quite a powerhouse. It has even jumped from client side applications to server side, node.js for instance. The fact that it adheres to a pretty nifty, prototype based ideology doesn’t hurt it either. There is no doubt that JavaScript is indeed a critical language now and for the foreseeable future.

    But I’ve always felt the syntax itself to be a bit kludgy. After working with a mix of Ruby and Python over the past couple of years, I’ve been finding JavaScript’s semi-colon infused, parentheses dependent, verbose syntax to be tedious. And from what I can gather, I’m not alone in feeling this way. This is where CoffeeScript comes to the rescue!


    What is CoffeeScript?

    CoffeeScript compiles down to raw JS.

    CoffeeScript is essentially just a syntactic rewrite of JavaScript. The core language itself stays the same, with small semantic enhancements. The syntax is modified, modeled after Python and Ruby.

    Remember that the CoffeeScript compiler outputs clean JavaScript that not only follows best practices and is eminently readable but also passes JSLint. This means that you don’t have to worry about compatibility down the line. In the worst case scenario of this project dying, you can just pick up the pristine JS that CoffeeScript generates and move on with your code. You aren’t locked into this environment.

    This may seem like an alien concept but under the web development umbrella, we’ve already seen our fair share of this ideology. HAML is but a new way of writing HTML while SASS does the same for CSS. All of them clean up the structure and syntax of their languages making them more easier to work with and thus boosting our productivity.


    Some Quick Code

    You’re probably wondering how the code itself looks so here is a quick peek:

    index = (list, target) ->
      [low, high] = [0, list.length]
      while low < high
        mid = (low + high) >> 1
        val = list[mid]
        return mid if val is target
        if val < target then low = mid + 1 else high = mid
      return -1
    

    This is a quick implementation of a binary search. Don’t try to parse the code itself right now. Just try to familiarize yourselves with the syntax.

    Below is the JavaScript code that CoffeeScript generates:

    var index;
    index = function(list, target) {
      var high, low, mid, val, _ref;
      _ref = [0, list.length], low = _ref[0], high = _ref[1];
      while (low < high) {
        mid = (low + high) >> 1;
        val = list[mid];
        if (val === target) {
          return mid;
        }
        if (val < target) {
          low = mid + 1;
        } else {
          high = mid;
        }
      }
      return -1;
    };
    

    Pros and Cons

    Here are some quick advantages and disadvantages of using CoffeeScript. This isn’t comprehensive by any means but I think this is sufficient to get a quick overview of the system.

    Yays

    • Python style whitespacing
    • Ruby styled lightweight syntax
    • Concise function declarations
    • JSLint approved
    • Class based inheritance

    There are, of course, numerous other points including semantic and syntactic enhancements.

    Nays

    • Slight learning curve involved
    • Deployment, depending on your route, may be a chore
    • You’ll need a basic knowledge of JS for debugging purposes. You can’t directly start here, naturally.

    Getting Started

    The official methods to get started include a command line utility that runs under node.js and simply downloading the source and installing it. Nothing much to guide here. Get the node.js utility and use npm install coffee-script [or for the source, bin/cake install] to install and get started.

    The situation with Windows is slightly more complicated. There is no straight forward way to get node.js or the source installed on Windows [outside of Cygwin]. Never fret though. A number of enterprising people have written compilers that work natively on Windows. I’ve included a few below:

    Note that the compiler, in compiled JavaScript form, is also bundled with the source, if you’re interested. It’s present under the extra directory with an obvious name.

    With that out of the way, we’re now going to take a look at a handful of things that show you how CoffeeScript makes JavaScript easier to consume!


    Use of Whitespace

    The first thing you’ll need to know is how CoffeeScript uses whitespace effectively to simplify the syntax. People with a Python background will find this trivial but for the others, here is a quick explanation.

    First up, you need not end every line with a semi-colon. Ending a line is automatically interpreted to be the end of that statement. For example, this..

    numbers = [0, 1, 2, 3]
    name = "NetTuts+"
    

    .. compiles down to this:

    var name, numbers;
    numbers = [0, 1, 2, 3];
    name = "NetTuts+";
    

    Next, you’ll be happy to know that you can do away with curly braces. Those numerous braces for opening and closing a block? Everything’s out. In CoffeeScript, you use Python-esque indentation to signify the beginning and ending of a block.

    CoffeeScript doesn’t require unnecessary parentheses or curly braces.

    Here is a quick example. Disregard everything but the indentation for now. We’ll get to the rest a little later below:

    if chasedByCylons
     runForYourLife()
    

    .. compiles down to

    if (chasedByCylons) {
      runForYourLife();
    }
    

    If you’re still a little confused, don’t worry. The syntax will start making more sense once we get to know the language better.


    Nifty, Semantic Aliases

    CoffeeScript provides a number of aliases for operators and keywords to make the code more readable and intuitive. Let’s take a look at some of them now.

    First, the comparison operators:

    • is maps to ===
    • isnt compiles to !==
    • == and != compile to === and !== respectively [As a best practice]

    Let’s see them in action quickly.

    if pant is onFire
     lookForWater()
    
    if game isnt good
     badMouth();
    

    ..which compiles to..

    if (pant === onFire) {
      lookForWater();
    }
    if (game !== good) {
      badMouth();
    }
    

    Pretty easy to read, no? Now, on to how logical operators are mapped.

    • and maps to &&
    • or is an alias for ||
    • not compiles down to !

    Building on our previous code:

    if pant is onFire and not aDream
     lookForWater()
    
    if game isnt good or haughtyDevs
     badMouth();
    

    ..which compiles to..

    if (pant === onFire && !aDream) {
      lookForWater();
    }
    if (game !== good || haughtyDevs) {
      badMouth();
    }
    

    Conditionals

    As you’ve already seen above, the basic if/else construct behaves the same as in normal JavaScript, sans the parentheses and curly braces. We’ll look at some variations below.

    if tired and bored
     sleep()
    else
     jog()
    
    // Raw JS below
    
    if (tired && bored) {
      sleep();
    } else {
      jog();
    }
    

    And here’s how the ternary operator is handled:

    activity = if sunday then isChilling else isWorking
    
    // Raw JS below
    
    activity = sunday ? isChilling : isWorking;
    

    An additional semantic enhancement is with the unless keyword. This functions as the exact opposite of if.

    keepRunning() unless tired
    
    keepWorking unless focus is extremelyLow
    

    And the compiled JavaScript…

    if (!tired) {
      keepRunning();
    }
    if (focus !== extremelyLow) {
      keepWorking;
    }
    

    Switch-Case

    Switch statements can be a little obtuse in JavaScript. CoffeeScript provides an intuitive wrapper around this construct.

    It begins with the switch keyword, as expected, followed by the variable whose value we’re checking. Each case or possible value is preceded by the when keyword followed by the statements to execute if it’s a match.

    There’s no need to add a break statement at the end of every case statement: CoffeeScript does this automatically for you.

    switch time
     when 6.00
      wakeUp()
      jotDownList()
     when 9.00 then startWorking()
     when 13.00 then eat()
     when 23.00
      finishUpWork()
      sleep()
     else doNothing()
    

    The syntax should be fairly self explanatory if you already know the equivalent in JavaScript. The only point to note here is the use of the then keyword. It’s used to separate the condition from the expression without starting a new line. You can use then for the other conditional statements as well as loops too.

    Here’s the JS that CoffeeScript generates for you:

    switch (time) {
      case 6.00:
        wakeUp();
        jotDownList();
        break;
      case 9.00:
        startWorking();
        break;
      case 13.00:
        eat();
        break;
      case 23.00:
        finishUpWork();
        sleep();
        break;
      default:
        doNothing();
    }
    

    Basic Loops

    Looping is another essential construct for your typical JavaScript code. Be it looping through numbers in an array or nodes in the DOM, you’re always in need of looping through collections.

    CoffeeScript provides a very flexible while loop that can be modified to function as a generic for or do-while loop.

    while work > time then freakOut()
    
    while time > work
      relax()
      mozyAround()
    
    // Raw JS
    
    while (work > time) {
      freakOut();
    }
    while (time > work) {
      relax();
      mozyAround();
    }
    

    until is another semantic enhancement and is equivalent to while not. A quick example below:

    workOut() until energy < exhaustion 
    
    // Raw JS
    
    while (!(energy < exhaustion)) {
      workOut();
    }
    

    Looping Through Collections

    Looping over arrays is pretty easy. You’ll need to use the for..in construct to step through the array. Let me show you how:

    sites = ['CodeCanyon','ThemeForest','ActiveDen']
    for site in sites
     alert site
    

    If you prefer the statements to be in the same line:

    sites = ['CodeCanyon','ThemeForest','ActiveDen']
    alert site for site in sites
    

    CoffeeScripts compiles these to basic for loops like so. Note that in line with best practices, the length of the array is cached beforehand.

    var site, sites, _i, _len;
    sites = ['CodeCanyon', 'ThemeForest', 'ActiveDen'];
    for (_i = 0, _len = sites.length; _i < _len; _i++) {
      site = sites[_i];
      alert(site);
    }
    

    Iterating over associate arrays [or hashes or dictionaries or key-value pairs] is just as easy with the of keyword.

    managers = 'CodeCanyon': 'Jeffrey Way', 'ThemeForest': 'Mark Brodhuber', 'ActiveDen': 'Lance Snider'
    
    for site, manager of managers
      alert manager + " manages " + site
    

    As expected, the above compiles down to a basic for loop as shown below:

    var manager, managers, site;
    managers = {
      'CodeCanyon': 'Jeffrey Way',
      'ThemeForest': 'Mark Brodhuber',
      'ActiveDen': 'Lance Snider'
    };
    for (site in managers) {
      manager = managers[site];
      alert(manager + " manages " + site);
    }
    

    Functions

    Creating and using functions is extremely easy under CoffeeScript. To define a function, you list the parameters it takes and then go on with the function's body. Here, let me show you how:

    playing = (console, game = "Mass Effect") ->
      alert "Playing #{game} on my #{console}."
    
    playing 'Xbox 360', 'New Vegas'
    

    This is the basic syntax behind creating and using functions. The default value for parameters can be defined inline. CoffeeScript generates the code to check whether a value has been passed in or not.

    Invoking a function is just as easy. There's no need for parentheses: pass in the parameters one after the other.

    As always, here's the generated code for your reference:

    var playing;
    playing = function(console, game) {
      if (game == null) {
        game = "Mass Effect";
      }
      return alert("Playing " + game + " on my " + console + ".");
    };
    playing('Xbox 360', 'New Vegas');
    

    Embedding Raw JavaScript

    Sometimes, you may have no other choice but to use raw JavaScript inside your CoffeeScript code. Hopefully, these instances should be far and few between but this has been taken into account as well.

    You can inject raw JS into your code by wrapping it with grave accents, also known as a backquote or backtick. Anything passed in thus will be completely untouched by the CoffeeScript compiler.

    rawJS = `function() {
      return someSuperComplexThingie;
    }`
    
    // which nets you
    
    var rawJS;
    rawJS = function() {
      return someSuperComplexThingie;
    };
    

    What Happens to My Libraries?

    Nothing happens to them, they can stay exactly where they are. CoffeeScript works seamlessly with any third party library, big or small, because it simply compiles to raw JavaScript. You'll just have to reformat and/or refactor your code very slightly but other than that, incompatibilities shouldn't be a point of concern.

    So instead of writing this:

    $(document).ready(function() {
     elemCollection = $('.collection');
      for (i=0; i<=elemCollection.length;i++)
      {
        item = elemCollection[i];
       // check for some random property here. I am skipping the check here
       colortoAdd = item.hasProperty()? yesColor : noColor;
       // I'm quite aware there are better ways to do this
       $(item).css ('background-color', colortoAdd);
      }
    });
    

    ... you'd write..

    $(document).ready ->
        elemCollection = $('.collection')
        for item in elemCollection
          colortoAdd = if item.hasProperty() then yesColor else noColor
          $(item).css 'background-color', colortoAdd
    

    That's All Folks

    And we've come to an end. I haven't covered a number of higher levels topics, classes for example, because they're well beyond the scope of an introductory article. Look for some advanced CoffeeScript tutorials down the road!

    I think CoffeeScript has changed the way I write JavaScript and, after reading this, I hope it has changed yours too. Questions? Nice things to say? Criticisms? Hit the comments section and leave me a comment. Happy coding and thank you so much for reading!

    Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
    Could not load more posts
    Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
    Just a second, loading more posts...
    You've reached the end.
    (PRO)
    No Soup for you

    Don't be the product, buy the product!

    close
    YES, I want to SOUP ●UP for ...