It’s been more than 1 year since I started dating CoffeeScript.

Before that, I’ve been developing in native HTML, CSS, JS, PHP languages for long, but later, (propably when I met Ruby on Rails for the 1st time) I instantly learned and loved code syntaxes in which:

  • logic flow is usually controlled by indentation, not braces;
  • braces, parentheses and semicolons may be skipped;
  • in overall, those code syntaxes enable you to write code in still readable way, but much, much faster

Jade/HAML, SASS/LESS/Stylus, CoffeeScript, Ruby syntaxes all fit in that. And well, I fell in love with them!

Just look at those examples:

// Jade
.home-section
  .home-section-inner
    .home-heading Hi, I'm Jack.
    .home-subheading
      | I am a freelance web developer specialized in 
      strong front-end and back-end web development
      | .

vs

<!-- HTML -->
<div class="home-section">
  <div class="home-section-inner">
    <div class="home-heading">
      Hi, I'm Jack.
    </div>

    <div class="home-subheading">
      I am a freelance web developer specialized in
      <strong>front-end and back-end web development</strong>.
    </div>
  </div>
</div>

or

# CoffeeScript
angular.module "myapp"

.factory "UserRegistrationFormFactory", (FormFactory, UsersResource) ->
  class UserRegistrationFormFactory extends FormFactory
    _createSubmitPromise: ->
      UsersResource.create({
        email: @user.email
        password: @user.password
      }).$promise

    onFailure: (response) ->
      alert(response.data.error.message) if response.data?.error?.message

vs:

// JavaScript
var myapp = angular.module("myapp");

myapp.factory("UserRegistrationFormFactory", function(FormFactory, UsersResource) {
  function UserRegistrationFormFactory() {};

  UserRegistrationFormFactory.prototype = Object.create(FormFactory.prototype);

  UserRegistrationFormFactory.prototype._createSubmitPromise = function() {
    return UsersResource.create({
      email: this.user.email,
      password: this.user.password
    }).$promise;
  };

  UserRegistrationFormFactory.prototype.onFailure = function(response) {
    if (typeof response.data === "object" && typeof response.data.error === "object" && response.data.error.message) {
      alert(response.data.error.message);
    }
  };

  return UserRegistrationFormFactory;
});

“There Is More Than One Way To Do It”, but which is the correct one?

However, after first weeks of development in Coffee & Ruby I noticed one thing: the fact that those languages are TIMTOWTDI doesn’t imply you can code in a whatever way you like (or even worse: every time in a different way). You should still obey some rules while coding in your hipster-beatiful language like Ruby or CoffeeScript. Of course, you can already find some of these rules in the internet - upon the name Style Guide:

Basically, every time you learn a new code syntax, the first thing you should do (after learning its’ manual), is to read its’ style guide. Having badly indented code, or having your if/elses formed in 15 different ways throughout your code, is one of the most silliest and childish mistakes you can make while coding.

However, sometimes, (especially in CoffeeScript, because of TIMTOWTDI), keeping to the style guide is just not enough, because you start to wonder:

  • Should I keep or skip those parentheses here?
  • Should these arguments be inline or extracted into a new line?
  • Should this callback function be extracted to a variable?

Everytime you think about it, you lose ~5-60 seconds of your precious “coding-flow”. We don’t want that; we should avoid it to maximise our coding effectivness.

I recommend obeying to one more, general, but very useful rule:

If you are thinking for more than 5 seconds about how to write a specific chunk of code, then

  • propably it sucks and should be refactored
  • if it doesn’t suck, but isn’t verbose and readable enough: write it in a more verbose way (extract temporary calculations to variables; remove shortcuts; and eventually, add comments)

So, instead of complaining ([1], [2]) that it’s impossible to write good, clean and readable code in CoffeeScript, please, use a style guide and e.g. use parentheses/braces whenever you feel the lack of them may confuse another developer in your team.

The fact that you can skip all the parentheses and braces in your .coffee code doesn’t mean you should always do that. It’s up to the programmer’s case, not to the language, to make the code readable. You can easily write unreadable code in C++ or Java also. That’s why you have style guides for them too.

Some more CoffeeScript advices

# Apache Cordova API allowing you to take a picture with phone's camera
# (from http://docs.phonegap.com/en/2.0.0/cordova_media_capture_capture.md.html)
#
# Usage example (JS):
# navigator.device.capture.captureImage( 
#   CaptureCB captureSuccess, CaptureErrorCB captureError, [CaptureImageOptions options]
# );

# Bad .coffee code:
# (unclear, hardly readable)
navigator.device.capture.captureImage (mediaFiles) ->
  savePictures(mediaFiles[0])
, (error) ->
  alert "an error occured!"
, limit: 1

# Better .coffee code:
# 1. Surround callbacks with additional parentheses for better readability
# 2. Surround {options} hash with additional curly braces
navigator.device.capture.captureImage( ((mediaFiles) ->
  savePictures(mediaFiles[0])
), ((error) ->
  alert "an error occured!"
), {limit: 1})

# Much better .coffee code:
# 3. Extract callbacks to variables
captureSuccess = (mediaFiles) ->
  savePictures(mediaFiles[0])
captureError = (error) ->
  alert "an error occured!"

navigator.device.capture.captureImage(captureSuccess, captureError, {limit: 1})

# Note: Now, even if you skip parentheses and braces, it's still readable
navigator.device.capture.captureImage captureSuccess, captureError, limit: 1

Even more CoffeeScript advices

  • don’t use is, isnt, and, or instead of ==, !=, &&, ||. In every code language I know we use the latter syntax, why we should act differently in Coffee? It doesn’t make our development faster/easier at all anyway.
  • generally, wrap function parameters in parentheses, unless it’s a generally used, 1-argument function, like console.log "message" or setTimeout -> (...)
  • generally, wrap objects in curly braces, unless it’s a nested object:

    $http({
      url: url
      method: "PATCH"
      params: 
        page: page
        auth_token: Auth.token
    })
    
  • don’t use fat arrows instead of a normal arrow, unless it’s really necessary

In summary (TL;DR)

  • CoffeeScript may lead you to unreadable code, especially in the beginning.
  • To prevent that, stick to a style guide; and write more verbosily when confused (f.e don’t skip parentheses/braces every possible time).
  • It’s untrue CoffeeScript can’t be used in a long-term, team-developed, open-source projects. Examples? Atom.
  • Check out also Ry Walker’s “Why CoffeeScript” blogpost - I agree with him in 100%.

What about Harmony?

Obviously for me, CoffeeScript is a much better language to write in, than the current version of vanilla JavaScript (ES5).

But what about the new version of JavaScript, “Harmony”, ECMAScript 6? It’s not implemented in the browsers yet, but you can already set automatic compiling of ES6 to ES5 with tools like Traceur, in a similar way as CoffeeScript.

After short research, seems like ES6 would be a better alternative than Coffee for a new JS project, because:

  • ES6 is the future JavaScript, that we’re going to have in a couple of years - so eventually, everyone will need to learn it anyway, which isn’t true with Coffee (Coffee is just a temporary alternative);
  • ES6 has most of the CoffeeScript features, and even some more, like generator functions ([3], [4]).

Looks like Harmony will be a good compromise for both vanilla-JS lovers and CoffeeScript hipsters. One thing still hurts me though: in ES6 I still need to write all the parentheses and semicolons. And I hate writing those }); !

So, at least for now, I’ll stay with CoffeeScript.