Tuesday, March 26, 2019

Tech Book Face Off: Coffeescript Vs. Simplifying Javascript

I really like this setup for a Tech Book Face Off because it's implicitly asking the question of what can be done to improve the quagmire that is the JavaScript language. Should we try to simplify things and pare down what we use in the language to make it more manageable, or should we ditch it and switch to a language with better syntax that transpiles into JavaScript? For the latter option, I picked one of the few books on the CoffeeScript language, aptly named CoffeeScript: Accelerated JavaScript Development by Trevor Burnham. Then, for sticking with JavaScript, I went with a recently published book by Joe Morgan titled Simplifying JavaScript: Writing Modern JavaScript with ES5, ES6, and Beyond. It should be interesting to see what can be done to make JavaScript more palatable.

CoffeeScript front coverVS.Simplifying JavaScript front cover

CoffeeScript


This book was written a few years ago now, in early 2015, but CoffeeScript is still alive and kicking, especially for Ruby on Rails developers as the default front-end language of choice. CoffeeScript is integrated into Rails' asset pipeline, so it gets automatically transpiled to JavaScript and minified as part of the production release process. If you're already comfortable with JavaScript, and even more so if you know Ruby, then CoffeeScript is a breeze to learn.

The ease with which this language can be picked up is exemplified by the book, since it's one of the shortest books I've ever read on a programming language. Over half of the book has more to do with examples, applications, and other stuff tangential to CoffeeScript, rather than the language proper. The book itself is just short of 100 pages while the content on syntax and usage of the language is condensed into the first half of the book.

As all books like this do, the first chapter starts out with how to install the language and configure the environment. It's pretty straightforward stuff. Then, we get into all of the syntax changes that CoffeeScript brings to JavaScript, which essentially defines the language since all of the features are the same as JavaScript's. Chapter 2 shows how function and variable declarations are different, and much shorter. Chapter 3 demonstrates some nice syntactical sugar for arrays in the form of ranges, and iteration can be done more flexibly with for comprehensions. Chapter 4 gets into the syntax features for defining classes and doing inheritance concisely.

Most of the syntax will look quite familiar to Rubyists, including class instance variables denoted with an '@' prefix, the string interpolation notation, unless conditionals, and array ranges. Here's an example from the book showing a number of the syntax features:

class Tribble
constructor: -> # class constructor definition
@isAlive = true # instance variable definition
Tribble.count += 1 # class variable access

breed: -> new Tribble if @isAlive
die: ->
return unless @isAlive
Tribble.count -= 1
@isAlive = false

@count: 0 # class variable (property)
@makeTrouble: -> console.log ('Trouble!' for i in [1..@count]).join(' ')
This code would be about twice as many lines in JavaScript, so the compression is pretty great and the code is much cleaner and easier to understand. Burnham proclaims these virtues of CoffeeScript early on in the book:
Shorter code is easier to read, easier to write, and, perhaps most critically, easier to change. Gigantic heaps of code tend to lumber along, as any significant modifications require a Herculean effort. But bite-sized pieces of code can be revamped in a few swift keystrokes, encouraging a more agile, iterative development style.
Maybe that's stated a bit more strongly than is warranted, but it's still hard to argue with the improved simplicity and cleanliness of CoffeeScript making developers' lives more pleasant.

The last three chapters of the book delve into different frameworks and packages in the JavaScript universe that can be used with CoffeeScript, and the vehicle for exploring these things is a (heavily) stripped  down version of the Trello app. Chapter 5 goes through how to create the front-end portion of the app with jQuery and Backbone.js. Chapter 6 adds a backend server for the app with Node and Express. Chapter 7 explores how to test the app with Intern. All of the code for the front-end, backend, and tests is written in CoffeeScript, and the transpiling is setup to be managed with Grunt. It's nice to see multiple different examples of how to use CoffeeScript anywhere that JavaScript would normally be used, just to get an idea of how to transition to CoffeeScript in multiple ways.

Throughout the book, Burnham presents everything in a straightforward, no-frills manner. Everything is clear and logical, and his concise descriptions are part of the reason the book is so short. He assumes you already know JavaScript—which is much appreciated—and he doesn't go into extended explanations of JavaScripts features. It's just the facts on how CoffeeScript is different and what the syntax is for the features it compresses. It's awfully hard for me not to recommend this book simply because it's so short and to the point. It only took a few hours to read through, and now I know a better way to code JavaScript. There's not much more I can ask of a programming language book.

Simplifying JavaScript


Every language has those more advanced books that assume you already know the language and instead of covering the basics and syntax, it provides advice on how to write idiomatically in the language. I've read these books for C++, Ruby, and JavaScript and found them to be surprisingly enjoyable to read. That was not the case with this book, but before I get too far into criticisms, I should summarize what this book does well.

Simplifying JavaScript is organized into ten chapters with each chapter broken into a set of tips that total 51 tips in all. These tips each explain one new feature of the JavaScript language from the new ES5, ES6, and ES2017 specifications. Some features, like the spread operator take multiple tips to fully cover. Then, the last chapter covers some features of the JavaScript development environment, like npm, that are not part of the language and have been around a bit longer than these newer specifications.

Most of the new features significantly improve and simplify the language, and they include things like:
  • new variable declaration keywords const and let
  • string template literals, which look much like Ruby's string interpolation
  • the spread operator ... for converting arrays to lists and converting lists of parameters to arrays
  • the Map object
  • the Set object
  • new loop iterators such as map(), filter(), and reduce()
  • default parameters
  • object destructuring
  • unnamed arrow functions
  • partially applied functions and currying
  • classes
  • promises and async/await
The arrow functions, spread operator, loop iterators, and destructuring go a long way in making modern JavaScript much more pleasant to program in. All of these features—and likely more in the newest language specs—make CoffeeScript nearly irrelevant, and likely not worth the effort of going through the step of compiling to JavaScript. The language has really matured in the last few years!

Morgan does a nice job introducing and justifying the new features at times:
We spend so much time thinking and teaching complex concepts, but something as simple as variable declaration will affect your life and the lives of other developers in a much more significant way.
This is so true. The code we're reading and writing every day has hundreds of variable declarations and usages, and being able to indicate intent in those declarations makes code much cleaner and more understandable. Getting better at the fundamentals of the language and having these new declarations available so that the most common code is clear and purposeful will more significantly improve code than all of the complicated, esoteric features that only get used once in a blue moon.

These exciting new features and simple explanations were the good parts, so why did I end up not liking this book much? Mostly, it was because of how long-winded the explanations were. Each tip dragged on for what felt like twice as long as it needed to, and the book could have easily been half as long. CoffeeScript showed how to present language features in a clear, concise way. This book took the opposite approach. Then, to make matters worse, it was written in the second person with the author always referring directly to the reader with you this and you that. Normally I don't mind a few references to you, the reader, every now and then, but this was constant so it became constantly aggravating.

Beyond the writing style, some of the justifications for various features didn't hold much water. For example, when trying to rationalize the new variable declarations, Morgan presented an example of code where the variables are declared at the top, and then there are a hundred lines of code before those variables are used again. Then he says, "Ignore the fact that a block of code shouldn't be 100 lines long; you have a large amount of code where lots of changes are occurring." I don't know about you, but I wouldn't declare a variable and then not use it for a hundred lines. I would declare it right before use. He shouldn't have to contrive a bad example like that to justify the new const and let declarations. The improved ability to relate intent in the code should be reason enough.

In another example for why one must be careful when testing for truthy values in a conditional, he shows some code that would fail because a value of 0 is falsey:
const sections = ['shipping'];

function displayShipping(sections) {
if (sections.indexOf('shipping')) {
return true;
} else {
return false;
}
}
Ignoring the fact that I just cringe at code like this that returns a boolean value that should be computed directly instead of selected through an if statement, (don't worry, he corrects that later) there is much more wrong with this code than just the fact that an index of 0 will incorrectly hit the else branch. In fact, that is the only case that hits the else branch. Whenever 'shipping' is missing from sections, indexOf() will return -1, which is truthy! This code is just totally broken, even for an example that's supposed to show a certain kind of bug, which it does almost by accident.

Other explanations were somewhat lacking in clarity. Late in the book, when things start to get complicated with promises, the explanations seem to get much more brief and gloss over how promises actually work mechanically and how the code executes. After having things explained in excruciating detail and in overly simplistic terms, I was surprised at how little explanation was given for promises. A step-by-step walk through of how the code runs when a promise executes would have been quite helpful in understanding that feature better. I figured it out, but through no fault of the book.

Overall, it was a disappointing read, and didn't at all live up to my expectations built up from similar books. The tone of the book was meant more for a beginner while the content was geared toward an intermediate to expert programmer. While learning about the new features of JavaScript was great, and there are plenty of new features to get excited about, there must be a better way to learn about them. At least it was a quick read, and refreshing my memory will be easy by skimming the titles of the tips. I wouldn't recommend Simplifying JavaScript to anyone looking to come up to speed on modern JavaScript. There are better options out there.

No comments: