Pure JavaScript vs. lodash, and the importance of decision-making in programming

Xkcd on the truths behind efficiency.

Don’t get me wrong — I love lodash. It has many useful helper functions, and I use it nigh on daily. But in many cases, it simply isn’t needed.

I recently opened a pull request in which i referenced to the first index of an array using the vanilla [0] notation. I didn’t think much it, to be honest. In the subsequent code review, I received the following comment (paraphrased):

“Why don’t you use the more readable _.first instead?”

The suggestion soon received support from a second reviewer. I must admit that, at first, I considered the comment to be nothing more than nitpicking. I wanted to know why using _.first would be a better option.

“Using _.first makes the code more readable.”

I disagree. C-style syntax is the most popular form of syntax used in programming languages today; a programmer who doesn’t immediately recognise what arr[0] does is, well, doing it wrong. For people unfamiliar with lodash/Underscore, however, _. may not be obvious [1] .

So, to my eye, arr[0] is, at the very least, just as readable as _.first(arr). It’s also shorter, which is always a plus. But we’re missing a key issue: what about performance? Readable code is great, but efficient code is even better.

Here’s a small snippet of pure JS that refers to the first index of an array arr in a for loop that is executed 1,000,000 times:


function calculateSpeed() {
  var arr = [1,2,3,4,5];
  var start = new Date().getTime();
  for(var i = 0; i < 1000000; ++i) {
    arr[0];
  }
  var end = new Date().getTime();
  console.log(end - start);
}

I ran the code in Safari using the highly scientific “do it twice” method, getting a result of three milliseconds for both runs. Executing the code with _.first(arr); instead of arr[0]; gave a result of 24 milliseconds (both runs). That’s almost one order of magnitude worse. It may not matter much for typical use cases, but small inefficiencies pile up. Shit’s important.

So there we have it. My recommendation in this case is to prefer [0] over _.first. But, despite the lengthy exposition, this isn’t why I wrote this post. The review got me thinking about programmers’ reasoning and decision-making processes in general. Programmers make countless small decisions every day, and collectively, they determine the quality of the result. There are scores of complex decision-making models, but I find that using a mental checklist is usually good enough.

Checklists should be context-specific, but I find that a general checklist that focuses on readability, conciseness, performance and reusability serves as a good starting point. Given two competing solutions A and B, I ask myself these questions:

  • Is the code for A at least as readable as that of B?
  • Is the code for A at least as concise as that of B?
  • Is the code for A at least as efficient as that of B?
  • Is the code for A at least as reusable as that of B?

What are the questions you ask yourself? What does your mental checklist looks like? If you don’t have one, I highly recommend giving it some thought.

For my checklist, if the answer to all questions is yes, then I know what to do: Fire up a browser, open the pull request, and tell those pesky code reviewers that they are wrong.

  1. Okay, I admit that lodash and Underscore aren’t exactly obscure libraries, but you get the point. []