Easy to read does not equal quicker comprehension

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com, or follow me on Twitter.

In theory, this is a rant against Coffeescript, but at the theoretical level, it is a rant against easy to read languages that are actually tough to comprehend.

CoffeeScript encourages writing code in sentences instead of logical statements.

eat food for food in foods

That looks great on the demo page, but eventually you end up with something more like this:

wash plate, brush, sink for key, plate of dishes when plate.dirty if meal.status is ‘done’

That is verbally readable code, but it’s not very comprehensible:

What is plate? The left side of the line (the side you scan while reviewing and debugging code) depends on stuff in the middle. You have to see plate then find it later in the line to know what it is, then come back to see what you’re doing with it.
Why is the plate still dirty in the app?! There are three things that could screw up that single line of code

dishes is empty, 8 words in you know you’re dealing with dishes.
The plate isn’t dirty, 10 words in.
The meal.status isn’t done, at the very end of the line
So all the things that determine whether or not the plate gets washed are deep inside the line. Though easy to read out loud, very hard to comprehend while scanning. Verbally readable code states the logic backwards. To comprehend it, you have to understand it from right to left, which takes more time. I’d probably write the wash plate line like this, assuming its inside of a function:

if meal.status isnt ‘done’
return

for key, plate of dishes
if plate.dirty
wash plate, brush, sink

Totally clear when a block of code will run, and much easier to scan. Also, not substantially different than some fast-and-loose JavaScript:

if (meal.status !== ‘done’)
return

for (var plate in dishes)
if (dishes[plate].dirty)
wash(dishes[plate], brush, sink);

Though, I’d write it like this:

if (meal.status !== ‘done’) {
return;
}
for (var plate in dishes) {
plate = dishes[plate];
if (plate.dirty) {
wash(plate, brush, sink);
}
}

The one-liners are very tempting as the author: you’re head is already wrapped around the problem so it’s easier to stay in context, giving you the false idea that it’ll make more sense to everybody else. Don’t believe me? Check out this one-liner I pulled out of the first .coffee file I randomly opened from our application:

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

That’s 160 columns of “readable code” that turns into this for debugging ಠ_ಠ:

var idx, scores, student;
var __hasProp = Object.prototype.hasOwnProperty;

scores = (function() {
var _ref, _ref2, _results;
_ref = this.gradebook.students;
_results = [];
for (idx in _ref) {
if (!__hasProp.call(_ref, idx)) continue;
student = _ref[idx];
if (((_ref2 = student[“assignment_” + this.assignment.id]) != null ? _ref2.score : void 0) != null) {
_results.push(student[“assignment_” + this.assignment.id].score);
}
}
return _results;
}).call(this);

Post external references

  1. 1
    http://ryanflorence.com/2011/2012/case-against-coffeescript/
Source