Uncle Bob’s Clean Code: Irrelevant in the Age of Full-Stack JavaScript?

I recently picked up Clean Code by Robert C. Martin (a.k.a. Uncle Bob). I’ve found it to be particularly helpful in the practice of day-to-day software development. It contains some wisdom that has since become so engrained in the culture of the software development community that it almost sounds trite when you read it for the first time. But how relevant is it to the concerns of web development eight years after it was published?

Clean Code Book Cover

Some Context

If there’s one place where the book struggles, it’s in the fact that it was written one year prior to the birth of Node.js and the full-stack JavaScript application. The code examples–all written in Java–have aged reasonably well, except for the fact that they’re written in Java.

If this book were to be written today, the code examples ought to be written in JavaScript. Not only is JavaScript the most appropriate language for this book because of its widespread use and promising future, but JavaScript is also a much more difficult language in which to write clean code.

Let me be clear: You can write terrible code in any language, but if you were to try to write terrible code that works, JavaScript would be your language of choice. And that’s why I’m evaluating Clean Code in this 21st year of JavaScript (JavaScript can drink now!).

Clean Code is Functional

The most important of Martin’s claims is that clean code is functional. Mind you, this was written when Java 6 was the latest and greatest and Java had not fully embraced the functional style with the introduction of lambda expressions and java.util.function.

Probably my favorite bit of wisdom in Martin’s chapter on functions is that functions should not mix levels of abstraction. On some level, I knew this, but I did not quite have the vocabulary to express it. From Martin:

Mixing levels of abstraction within a function is always confusing. Readers may not be able to tell whether a particular expression is an essential concept or a detail. Worse, like broken windows, once details are mixed with essential concepts, more and more details tend to accrete within the function.

This is especially relevant to JavaScript developers because unless your tests break, it’s very easy to screw up code that you’re working in without knowing that you broke it. Abiding by this principle is also perhaps the best way to discern the boundaries of a function’s responsibility (and keeping your functions short, another of Martin’s values). Keeping your JavaScript code functional is probably the only path to sanity in a large JavaScript codebase. Martin’s chapter on functional code is maybe the most valuable 22 pages you could read on the subject of staying sane.

Clean Code is Clean

I found the foreword written by James O. Coplien to be really insightful. He discusses the Japanese workplace organization methodology called 5S, and one of the principles of this methodology is Seiso (Shine).

Clean your workplace on daily basis completely or set cleaning frequency.
Use cleaning as inspection.
Prevent machinery and equipment deterioration.
Keep workplace safe and easy to work.
Keep workplace clean and pleasing to work in.

As I was reading this, I realized that there were formatting inconsistencies in my codebase that had been really irritating me. I immediately took a few minutes to do a find and replace (and run tests) on stuff like spaces between closing parens and opening curly braces in anonymous function expressions. I was really quite surprised to find how much better I felt after doing this.

I also can’t express how important this is for catching typos in a language that fails as silently as JavaScript does. Anything you can do to make your codebase more regular and easy to scan for correctness must be done. Unit tests are the answer to many problems, but there are certainly edge cases that will frustrate you when you fat finger a variable name.

‘The Only Truly Good Comment is the Comment You Found a Way Not To Write’

Comments are the subject of the next most enjoyable chapter. I’m not a big code commenter, but boy, did I love reading Martin’s takedown of code comments:

Why am I so down on comments? Because they lie. Not always, and not intentionally, but too often. The older a comment is, and the farther away it is from the code it describes, the more likely it is to be just plain wrong. The reason is simple. Programmers can’t realistically maintain them.

The distilled wisdom from this chapter is relevant to people like me who already avoid writing comments: If you feel an urge to comment or explain yourself, encapsulate the code you would comment in a function that is basically the comment you would write.

I encountered this problem recently when writing a function that programmatically creates the name of the image file it needs based on a combination of variables that describe some state of the app.


keyboardLayoutImage: function () {
    let keyboardLayout = this.get('keyboardLayout');
    let itemDisplay = this.get('itemDisplayMode');
    return 'assets/images/' + _.kebab([keyboardLayout, itemDisplay]) + '.png';
}

My solution for constructing filenames using constants describing the various states of the app was simple, easy to read, easy to test, and very short. There was only one problem: Since we used the same image file for several different states, we could reduce load time by using the same image file for several of the states. If you were just reading the code, my addition to support this functionality looked bizarre:


keyboardLayoutImage: function () {
    let keyboardLayout = this.get('keyboardLayout');
    let itemDisplay = this.get('itemDisplayMode');

    if (keyboardLayout === LetterLayouts.custom) {
      keyboardLayout = LetterLayouts.alphabetical;
    }

    return 'assets/images/' + _.kebabCase([keyboardLayout, itemDisplay]) + '.png';
}

I almost felt the need to put a comment there describing the shortcut I was taking to reduce the number of images we used. Instead, I took Martin’s advice, and got the resulting code that is much cleaner (and doesn’t mix levels of abstraction!).


keyboardLayoutImage: function () {
    let keyboardLayout = this.get('keyboardLayout');
    let itemDisplay = this.get('itemDisplayMode');
    keyboardLayout = this.useAlphabeticalImagesForCustomLayout(keyboardLayout);

    return 'assets/images/' + _.kebabCase([keyboardLayout, itemDisplay]) + '.png';
},
useAlphabeticalImagesForCustomLayout: function (keyboardLayout) {
    if (keyboardLayout === LetterLayouts.custom) {
      return LetterLayouts.alphabetical;
    } else {
      return keyboardLayout;
    }
}

Some Quibbles

I will go ahead and address Betteridge’s Law Of Headlines: Clean Code is still relevant–in fact, reading it with the present in mind makes it feel at times prescient with its embrace of functional programming, which is all the rage in front-end development these days.

While it is still relevant, an update certainly wouldn’t hurt it. For instance:

  • The chapter on error handling is still very relevant to Java, but a fundamental premise doesn’t apply to JavaScript error handling: try-catch-finally blocks define their own scope in Java. JavaScript has block scope syntax and functional scope. Although the introduction of let has improved the language in this respect, JavaScript’s weird scope rules requires extra consideration.
  • There’s almost nothing in the book about managing asynchronous code. This is a weird subject to tackle, especially since some JavaScript frameworks are built around solving this problem, but it would still be nice to have it directly addressed by Martin.
  • It sometimes feels like Martin is creating a catalog of interesting code smells, and while there’s value in creating a vocabulary with which to talk about such things, it doesn’t always feel particularly helpful. Time might be better spent on strategies for absolving your code base of such nonsense (or helping team members lose such habits).

Martin’s Clean Code has a lot to say that is applicable to JavaScript development, but if Clean Code: JavaScript Edition came out tomorrow, I’d be first in line to buy it.

Conversation
  • You use the metric “I felt much better after doing this.” Right metric. If you’re really in touch with your feelings, they can send you in the right direction.

    We did some back-of-the-envelope evaluations in Bell Labs and found that fault density was highest in inconsistently or poorly indented code. Alexander was right. First, beauty matters. Second, beauty has to do with geometry (formatting). Third, we gauge it with feeling.

    Too few engineers have the psychological background to explore beyond reductionist measures that are so common. It’s refreshing to hear someone publicly saying “feel better.” And it feels good :-).

    • Andrea Griffini says:

      May be the bad or inconsistently indented code was faulty because written by bad programmers. Running that code into astyle wouldn’t make the faults disappear…

      • AFell says:

        There is truth to this, but at least if it was in a proper style, the programming faults may be easier to spot and fix to a more experienced hand during code review and not allow it to be perpetuated. It also allows the more experienced programmer to show how faults can be spotted and fixed just by logically and visually inspecting the style.

      • Actually, it might led to code understanding that would make faults disappear. That’s the whole point. The research wasn’t quite as naive as you perhaps imagine it might have been and I’m pretty sure there were enough controls to avoid this inconsistency. The pundits were world experts in internal consistency and external validity of experimental design.

    • Steve Hermes says:

      Here Here James,

      I work with some young coders and the concept of beautiful code is not even in there field of view. Maybe with time and maturity they will come to see that a clean codebase has value, especially for those who follow.

      I always try to take the position that the code I write is a reflection of who I am and how I conduct myself. Let’s keep the art in the science.

    • Drew Hoover Drew Hoover says:

      Thanks for commenting, James. And thanks for writing such an enjoyable foreword =)

    • Rick Sline says:

      I’ve been supervising and writing code on the PC platform for over 30 years – starting with dBASE II, moving to FoxPro, Access, SQL Server, .NET, JavaScript & related technologies. Somehow early in my career I found proper code formatting including indenting.

      My code isn’t bug free from the get-go, but generally I can locate a bug in at most a few minutes. I reviewing other’s code – if it’s already formatted well I can see what’s going on very quickly.

      For the bulk of my bug finding expeditions in other’s code, most commonly the code is not formatted. I will frequently take the time to format it, and usually as I do, I find & can fix the bug at hand and occasionally a few others.

      For those who report to me from the start, it’s a “condition of employment”; although frequently I’m called into an organization where there’s a lot of existing code and such clean-up is well worth the time.

    • Cris Bennett says:

      I notice that mechanical engineer friends of mine invariably take some kind of aesthetic pleasure in what they do. Because of the type of bluff folk they are, they represent this as pragmatically necessary order (eg. neatness, everything in its place), but it’s obvious in reality that the motivation has an affective dimension going beyond function.

      The same does seem to be true of programming. This strikes me as a hopeful and good thing. Even programmers are not just brains in vats, and the more dimensions of the self that can be drawn into the activity, the more rewarding it is likely to be.

  • Nirav says:

    Javascript is not a difficult language but a poorly written and poorly standardised language. Last language javascript should be of choice of any programmer. You can not get sillier than that.

  • Kris Lamb says:

    I’ve found the book to be extremely relevant to c++ development too. There are way too many bad ways to write c++

  • David Halonen says:

    A friend of mine works for a domestic automobile manufacturer as a designer. I asked once what would happen if designers were allowed to submit drawings according to any standard – their artistic whims. His response: “You would shut the company down immediately.”

    There is great *communication* value in having the title blocks in the same location on the drawing; all arrows of the same style; dimensions consistently placed;

    For some reason, programmers think of themselves as above this sort of tedium. Style really helps communication, which is the point, yes?

  • David Boyle says:

    In my experience, 20 years ago developers didn’t comment their code. Now they still don’t comment their code. The only thing that has changed is how they feel about it. 20 years ago they felt a nagging sense of shame about not doing something they were told was good practice. Now they feel good about not doing something they are told is bad practice.

    Is it really possible to express every salient point about code through naming? I don’t think so. No amount of thought about how to name a function will tell another developer that you spent two hours trying to implement it in a more intuitive way but there’s a gotcha they should know about that resulted in the code they see now. Similarly for code that might appear to have poor performance but is fine because of some nugget of wisdom about the problem domain that would escape the casual observer. Similarly for code that doesn’t call that particular API because of an odd corner case.

    It seems to me that a perfectly valid point (comments may be used as an inferior substitute for good naming) has been pushed well beyond sense.

    There is an even more pernicious effect: if the logic holds that comments can get out of sync with code, therefore they are worse than useless, then the same holds for absolutely every form of documentation beyond the code itself. Which, as expected, leads some developers to view with suspicion any form of documentation at all. Can you imagine a Boeing engineer saying they’d dumped all the blueprints for the 777 because they could get out of sync with what was actually built? Relax, it’s a self-documenting aircraft!

    If I change what a function does, such that the name becomes misleading, the compiler isn’t going to complain. If I claim to have any concern at all for my fellow developers, a single shred of professionalism, then I’ll update the name of that function. But comments are special? They can’t possibly be expected to be updated?

    • Matt says:

      Yep ! Completely agree. Programmers have an awful habit of starting with something that broadly makes sense, then taking it to its logical (illogical?) conclusion. Doing that here means you end up with an awful lot of 1 line methods and probably more classes than is sane.

    • dysonlu says:

      “The chapter on error handling is still very relevant to Java, but a fundamental premise doesn’t apply to JavaScript error handling: try-catch-finally blocks define their own scope in Java. JavaScript has block scope syntax and functional scope.”

      A variable declared in Javascript catch clause has block-scoped. From MDN:

      “The catch block specifies an identifier (e in the example above) that holds the value specified by the throw statement. The catch block is unique in that JavaScript creates this identifier when the catch block is entered and it adds it to the current scope; the identifier lasts only for the duration of the catch block; after the catch block finishes executing, the identifier is no longer available.”

      (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try…catch)

  • Daniël Terwiel says:

    Clean Code for javascript: https://github.com/ryanmcdermott/clean-code-javascript

    • EricOP says:

      Anyone down this far in the comments must read https://github.com/ryanmcdermott/clean-code-javascript as Daniël has referenced. It’s only been improved and newbs and old-timers alike have contributed and made a sort of style-guide for vanilla JavaScript that is very much what Uncle Bob did with the Java in his book. It’s so powerful to see actual examples of say the Liskov Substitution Principle (from SOLID) with good and bad examples, so you can “sniff out” when you break the principle your self.

      Great post. I love the thoughtful stuff you AO guys and gals blog on. Thought rooted on actual experiences. Good stuff.

  • Comments are closed.