The Elements of Clean Code

2026-08-24

Simplicity is prerequisite for reliability. -- Edsger Dijkstra

Rage Bait

Let's take it as an axiom that most code sucks.1 It's not just that it's buggy, it's messy, obscure and difficult to read. Stuff breaks. Requirements change. It's not enough for the code to run, somebody will have to edit this stuff.

Code that's easier to read, and therefore sucks less, is colloquially known as "clean code". The term shares a name with Robert Martin's book "Clean Code".

Periodically, people bring up the book and argue vehemently. I haven't seen so many nerds delight in expressing such seething hatred since "Batman and Robin" bombed in 1997.

The controversy reminds me of William Strunk's "The Elements of Style".

The Elements of Style

Like "Clean Code", "The Elements of Style" is a prescriptive manual on craftsmanship.2 It has its own proponents and detractors.

There is little or no detectable bullshit in that book. (Of course, it's short; at eighty-five pages it's much shorter than this one.) I'll tell you right now that every aspiring writer should read The Elements of Style. Rule 17 in the chapter titled Principles of Composition is 'Omit needless words.' I will try to do that here. -- Stephen King

There are no rules, just tools. Let's see how these tools are useful.

Mapping

Each book presents endorses directness, clarity and brevity. Many of The Elements of Style"' principles of composition to "Clean Code"'s recommendations.

The Elements of StyleClean Code
Use definite specific concrete languageUse Intention-Revealing Names
Omit Needless WordsWrite small functions, don't repeat yourself
Express coordinate ideas in similar formUse polymorphic objects that share a uniform interface

Examples

Prose

Revising text according to "The Elements of Style" can clear up a muddy passage. Here's an example.3

Macbeth was very ambitious. This led him to wish to become king of Scotland. The witches told him that this wish of his would come true. The king of Scotland at this time was Duncan. Encouraged by his wife, Macbeth murdered Duncan. He was thus enabled to succeed Duncan as king.

The revision delivers the same information.

Encouraged by his wife, Macbeth achieved his ambition and realized the prediction of the witches by murdering Duncan and becoming king of Scotland in his place.

We could call that "clean prose".

Code: The Generate Primes Example

The following GeneratePrimes examples use the Sieve of Eratosthenes to generate prime numbers.

Generate Primes

Here's the 'bad' version from "Clean Code". It's not as messy as code spotted in the wild, but it's still suitably mysterious. If you didn't write this code yourself, or don't remember writing it, you'd have to work to figure it out.

public class GeneratePrimes
   {
     /**
      * @param maxValue is the generation limit.
      */
     public static int[] generatePrimes(int maxValue)
     {
       if (maxValue >= 2) // the only valid case
       {
         // declarations
         int s = maxValue + 1; // size of array
         boolean[] f = new boolean[s];
         int i;
         // initialize array to true.
         for (i = 0; i < s; i++)
           f[i] = true;
         // get rid of known non-primes
         f[0] = f[1] = false;
         // sieve
         int j;
         for (i = 2; i < Math.sqrt(s) + 1; i++)
         {
           if (f[i]) // if i is uncrossed, cross its multiples.
           {
             for (j = 2 * i; j < s; j += i)
               f[j] = false; // multiple is not prime
           }
         }
         // how many primes are there?
         int count = 0;
         for (i = 0; i < s; i++)
                 if (f[i])
             count++; // bump count.
         }
         int[] primes = new int[count];
         // move the primes into the result
         for (i = 0, j = 0; i < s; i++)
         {
           if (f[i])  // if prime
             primes[j++] = i;
         }
           return primes;  // return the primes
       }
       else // maxValue < 2
         return new int[0]; // return null array if bad input.
     }
   }

Without the comments, it's less intelligible.

public class GeneratePrimes
   {
     public static int[] generatePrimes(int maxValue)
     {
       if (maxValue >= 2)
       {
         int s = maxValue + 1;
         boolean[] f = new boolean[s];
         int i;
         for (i = 0; i < s; i++)
           f[i] = true;
         f[0] = f[1] = false;
         int j;
         for (i = 2; i < Math.sqrt(s) + 1; i++)
         {
           if (f[i])
           {
             for (j = 2 * i; j < s; j += i)
               f[j] = false;
           }
         }
         int count = 0;
         for (i = 0; i < s; i++)
                 if (f[i])
             count++;
         }
         int[] primes = new int[count];
         for (i = 0, j = 0; i < s; i++)
         {
           if (f[i])
             primes[j++] = i;
         }
    return primes;
       }
       else
         return new int[0];
     }
   }

Refactored

Here's Robert Martin's refactor.

public class PrimeGenerator
   {
       private static boolean[] crossedOut;
       private static int[] result;

       public static int[] generatePrimes(int maxValue)
     {
       if (maxValue < 2)
         return new int[0];
       else
       {
         uncrossIntegersUpTo(maxValue);
         crossOutMultiples();
         putUncrossedIntegersIntoResult();
         return result;
       }
     }

      private static void uncrossIntegersUpTo(int maxValue)
     {
       crossedOut = new boolean[maxValue + 1];
       for (int i = 2; i < crossedOut.length; i++)
         crossedOut[i] = false;
     }

      private static void crossOutMultiples()
     {
       int limit = determineIterationLimit();
       for (int i = 2; i <= limit; i++)
         if (notCrossed(i))
           crossOutMultiplesOf(i);
     }

      private static int determineIterationLimit()
     {
       // Every multiple in the array has a prime factor that
       // is less than or equal to the root of the array size,
       // so we don’t have to cross out multiples of numbers
       // larger than that root.
       double iterationLimit = Math.sqrt(crossedOut.length);
       return (int) iterationLimit;
     }

      private static void crossOutMultiplesOf(int i)
     {
       for (int multiple = 2*i; multiple < crossedOut.length; multiple += i)
         crossedOut[multiple] = true;
     }

    private static boolean notCrossed(int i)
     {
       return crossedOut[i] == false;
     }


     private static void putUncrossedIntegersIntoResult()
     {
       result = new int[numberOfUncrossedIntegers()];
       for (int j = 0, i = 2; i < crossedOut.length; i++)
         if (notCrossed(i))
           result[j++] = i;
     }

    private static int numberOfUncrossedIntegers()
     {
       int count = 0;
       for (int i = 2; i < crossedOut.length; i++)
         if (notCrossed(i))
           count++;
    return count;
     }

    private static int numberOfUncrossedIntegers()
     {
       int count = 0;
       for (int i = 2; i < crossedOut.length; i++)
         if (notCrossed(i))
           count++;
       return count;
     }
   }

This style of refactoring has caused a bit a rift in code reviews; it adds more lines of code than it takes out. On paper, this doesn't "omit needless words".

Programmers won't read code on paper; you're not even reading this on paper. An Integrated Development Environment (IDE) such as VS Code will usually fold blocks of code. The initial view would be something like the following.

public class PrimeGenerator
   {
       private static boolean[] crossedOut;
       private static int[] result;

       public static int[] generatePrimes(int maxValue)
     {
       if (maxValue < 2)
         return new int[0];
       else
       {
         uncrossIntegersUpTo(maxValue);
         crossOutMultiples();
         putUncrossedIntegersIntoResult();
         return result;
       }
     }

   ...

   }

IDEs will also hyperlink function invocations to their declarations, so the "Clean Code" style turns source code into a Wiki.

...
private static void crossOutMultiplesOf(int i)
  {
    for (int multiple = 2*i; multiple < crossedOut.length; multiple += i)
      crossedOut[multiple] = true;
  }
...

Mapping Revisited

When William Strunk urged writers to "make the paragraph the unit of composition", he predated "Uncle Bob's formatting rules" by almost 100 years.4

If the subject on which you are writing is of slight extent, or if you intend to treat it very briefly, there may be no need of subdividing it into topics. Thus a brief description, a brief summary of a literary work, a brief account of a single incident, a narrative merely outlining an action, the setting forth of a single idea, any one of these is best written in a single paragraph. After the paragraph has been written, examine it to see whether subdivision will not improve it.

Ordinarily, however, a subject requires subdivision into topics, each of which should be made the subject of a paragraph. The object of treating each topic in a paragraph by itself is, of course, to aid the reader. The beginning of each paragraph is a signal to him that a new step in the development of the subject has been reached.

Conclusion

"Clean Code" has shortcomings (shoe-horning Test-Driven Development into a syntax formatting guide feels like bringing up politics at Thanksgiving dinner), but publicly banning it or slamming it5 seems unnecessarily theatrical.

It's one way to build software, not the only way.

William Strunk and Robert Martin are similar; everything they say is opinion by default. That's true of all writers.

To the market of hot takes, I submit my recommendation for "Elements of Style" over "Clean Code". It imparts many of the same sentiments in fewer pages. Use it if it works for you.

1

Sadly, this makes it overwhelmingly likely that my code sucks. All men are mortal. Socrates is a man. Therefore...

2

You can read it for free. The first edition is public domain and can be accessed through Project Gutenberg.

3

Omit needless words, the Elements of Style, 1918

4

"Uncle Bob" is a poorly chosen nickname. When a complete stranger asks me to call him "Uncle" anything, I politely refuse. Then I call the cops.

5

Except for that "Uncle" shit.