Web Dev

An Introductory Analysis of CoffeeScript

For the last six months, I have been working a project that exclusively uses CoffeeScript for both the front end and back end. That being said, I have had a lot of CoffeeScript on my mind lately! This blog post will examine some of the pros and cons related to features of CoffeeScript and, hopefully, provide insight into whether CoffeeScript might be the right language for your next project.

If you are completely new to CoffeeScript, I encourage you to head over to its site (http://coffeescript.org/) and look through some of the documentation.

The first stable version of CoffeeScript was released to the public in December 2010 by Jeremy Ashkenas (creator of Backbone.js, and Underscore.js). The compiler, which was originally written in Ruby, was replaced by an actual CoffeeScript version which can be run in a JS environment.

The purpose of this new language was to allow the user to escape many of the disadvantages and “bad parts” of JavaScript. On first inspection, you might notice a syntax reminiscent of Ruby or C. This was by design! Coders who dislike the Ruby syntax might have similar feelings toward CoffeeScript, as well.

The Good

CoffeeScript is more human-readable code. I can’t speak for other people, but when I read code, I subconsciously convert it into a verbally-readable structure. So for example, when I see code like this:

if (!(field && (value || oldValue))) {
    return null;
}

This would translate to English like this: “If not field and either value or old value then return null.”

Now look at the CoffeeScript version of the above code:

return null unless field and (value or oldValue)

It’s almost the exact English translation of the above JavaScript snippet. By removing a lot of the code syntax and making it more human readable, CoffeeScript eliminates the time it takes to translate it in our minds.

CoffeeScript also allows you to write more code in less time. A general rule of thumb is that writing CoffeeScript lets you reduce the number of lines of code by about ⅓. This, of course, is subjective to the person writing the code, but it seems to be about the average in my experience.

As an example, take a look at the following code snippet:

var contact, item, _i, _len, _ref;
_ref = this.lead.contacts;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  item = _ref[_i];
  if (item.emails.some((function(_this) {
    return function(e) {
      return e.email === _this.account.username;
    };
  })(this))) {
    contact = item
  }
}

This is fairly straightforward code. I am looping through a collection and testing if the collection item (which is an array) contains an item that is equal to the account username. If it is, then we assign it to the variable contact.

Now, how does CoffeeScript make this easier for us?

contact = item for item in @lead.contacts when item.emails.some (e) => e.email is @account.username

That’s a lot fewer lines of code and much more readable!

For an interactive demonstration of how CoffeeScript can dramatically reduce the amount of code, you need to see this link: http://ryanflorence.com/2012/javascript-coffeescript-rewrite/.

CoffeeScript also makes context binding much simpler. Look at the following code snippet:

saveData: function(datum) {
      return $.ajax({
        url: 'exampleURL'
        type: 'POST',
        data: {
          data: data
        },
        dataType: 'json'
      }).done((function(_this) {
        return function(result) {
          _this.doSomething()
          return app.doSomethingElse().then(function() {
            return _this.done()
          });
        };
      })(this)).fail((function(_this) {
        return function(xhr) {
          return showError('Failed!', 'Problem Saving data!”);
        };
      })(this));
    },

In the above example, we are making an AJAX call, then passing around a chain of callbacks, each of which need to be bound to the appropriate scope. This reference can easily be tracked in CoffeeScript by declaring functions using “=>”.

The previous code would become the following in CoffeeScript:

saveData: (datum) ->
    $.ajax
      url: 'exampleURL'
      type: 'POST'
      data: {data: data}
      dataType: 'json'
    .done (result) =>
      @doSomething()
      app.doSomethingElse().then => @done()
    .fail (xhr) =>
      showError “Failed!”, “Problem Saving data!”

Lastly, CoffeeScript provides an abstraction for JavaScript classes.

Javascript is a prototypal and classless language, which allows the use to build their own inheritance class system manually. However, this has traditionally been difficult and confusing to do, especially for new Javascript programmers who aren’t familiar with the Javascript prototype.

Take the following example, which is one way to implement an arbitrary Car class in JavaScript:

(function() {
  var Car;
  Car = (function() {
    function Car(year, make, model) {
      this.year = year;
      this.make = make;
      this.model = model;
    }

    return Car;
  })();
}).call(this);

Using “New Car” will return a new object with the year, make, and model properties. The function Car acts as a constructor that gets called when the new keyword is used.

Say we want to add some class methods, how does this look now?

(function() {
  var Car,
    __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

  Car = (function() {
    function Car(year, make, model) {
      this.drive = __bind(this.drive, this);
      this.honk = __bind(this.honk, this);
      this.logDetails = __bind(this.logDetails, this);
      this.year = year;
      this.make = make;
      this.model = model;
    }

    Car.prototype.logDetails = function() {
      return console.log('1991', 'Honda', 'Accord');
    };

    Car.prototype.honk = function() {};

    Car.prototype.drive = function() {};

    return Car;

  })();

}).call(this);

I’ve added 3 methods, “logDetails”, “Honk”, and “Drive”. To do this, I have to bind the Car scope to the methods in the constructor, and then declare the method prototype. You can see how this will get messy with bigger classes! Fortunately, CoffeeScript recognizes these issues and creates a beautiful abstraction over the class system using the native JavaScript prototype.

Using CoffeeScript, the above code will simply turn into this:

class Car
  constructor: (year, make, model) ->
    @year = year
    @make = make
    @model = model

  logDetails : =>
    console.log '1991', 'Honda', 'Accord'

  honk : =>
    # Implementation details here
  drive : =>
    # Implementation details here

The Not So Good

CoffeeScript also has its fair share of critics, and there are some strong arguments to be made for using native JavaScript over CoffeeScript.

First, CoffeeScript adds a compiling element. Initially, this might annoy a lot of JavaScript developers (it certainly annoyed me at first). The beauty of JavaScript is its simplicity, and when you add an extra complex element like compiling, this aspect is lost.

Debugging is a pain! This article by Ryan Florence, http://ryanflorence.com/2011/case-against-coffeescript/, outlines the difficulties introduced by debugging when you use CoffeeScript. The general idea is this: CoffeeScript typically compiles into a mesh of not very readable JavaScript. So during debugging, you have additional time introduced in order to understand the compiled code, then translate that into CoffeeScript, and then finally, recompile and retest.

CoffeeScript has disadvantages, as well. Although it was written in order to eliminate poorly written JavaScript, things such as tab and white-space sensitivity make it easy to write bugs and other things into CoffeeScript.

Conclusion

In the end, deciding whether to use CoffeeScript is essentially a choice of preference for the developer. While many developers see the advantages, others do not. After reading this, hopefully you will have a clearer view of what CoffeeScript can offer you.

Reference: An Introductory Analysis of CoffeeScript from our WCG partner Keyhole Software at the Keyhole Software blog.

Keyhole Software

Keyhole is a midwest-based consulting firm with a tight-knit technical team. We work primarily with Java, JavaScript and .NET technologies, specializing in application development. We love the challenge that comes in consulting and blog often regarding some of the technical situations and technologies we face.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button