{"id":609404,"date":"2023-02-18T07:49:00","date_gmt":"2023-02-18T13:49:00","guid":{"rendered":"https:\/\/news.sellorbuyhomefast.com\/index.php\/2023\/02\/18\/its-probably-time-to-stop-recommending-clean-code-2020\/"},"modified":"2023-02-18T07:49:00","modified_gmt":"2023-02-18T13:49:00","slug":"its-probably-time-to-stop-recommending-clean-code-2020","status":"publish","type":"post","link":"https:\/\/newsycanuse.com\/index.php\/2023\/02\/18\/its-probably-time-to-stop-recommending-clean-code-2020\/","title":{"rendered":"It&#x27;s probably time to stop recommending Clean Code (2020)"},"content":{"rendered":"<div>\n<p>It may not be possible for us to ever reach empirical definitions of &#8220;good code&#8221; or &#8220;clean code&#8221;, which means that any one person&#8217;s opinions about another person&#8217;s opinions about &#8220;clean code&#8221; are necessarily highly subjective. I cannot review Robert C. Martin&#8217;s 2008 book <a href=\"https:\/\/learning.oreilly.com\/library\/view\/clean-code\/9780136083238\/\"><i>Clean Code<\/i><\/a> from your perspective, only mine.<\/p>\n<p>That said, the major problem I have with <i>Clean Code<\/i> is that a lot of the example code in the book is <em>just dreadful<\/em>.<\/p>\n<h4>*<\/h4>\n<p>In chapter 3, &#8220;Functions&#8221;, Martin gives a variety of advice for writing functions well. Probably the strongest single piece of advice in this chapter is that <strong>functions should not mix levels of abstraction<\/strong>; they should not perform both high-level and low-level tasks, because this is confusing and muddles the function&#8217;s responsibility. There&#8217;s other valid stuff in this chapter: Martin says that function names should be descriptive, and consistent, and should be verb phrases, and should be chosen carefully. He says that functions should do exactly one thing, and do it well, which I agree with&#8230; provided that we aren&#8217;t too dogmatic about how we define &#8220;one thing&#8221;, and we understand that in plenty of cases this can be highly impractical. He says that functions should not have side effects (and he provides a really great example), and that output arguments are to be avoided in favour of return values. He says that functions should generally either be commands, which <em>do<\/em> something, or queries, which <em>answer<\/em> something, but not both. This is all reasonable entry-level advice.<\/p>\n<p>But mixed into the chapter there are more questionable assertions. Martin says that Boolean flag arguments are bad practice, which I agree with, because an unadorned <code>true<\/code> or <code>false<\/code> in source code is opaque and unclear <i>versus<\/i> an explicit <code>IS_SUITE<\/code> or <code>IS_NOT_SUITE<\/code>&#8230; but Martin&#8217;s reasoning is rather that a Boolean argument means that a function does more than one thing, which it shouldn&#8217;t.<\/p>\n<p>Martin says that it should be possible to read a single source file from top to bottom as narrative, with the level of abstraction in each function descending as we read on, each function calling out to others further down. This is far from universally relevant. Many source files, I would even say most source files, cannot be neatly hierarchised in this way. And even for the ones which can, an IDE lets us trivially jump from function call to function implementation and back, the same way that we browse websites.<\/p>\n<p>He says code duplication &#8220;may be the root of all evil in software&#8221; and fiercely advocates <a href=\"https:\/\/en.wikipedia.org\/wiki\/Don%27t_repeat_yourself\">DRY<\/a>. At the time, this was quite standard advice. In more recent times, however, we generally understand that <a href=\"https:\/\/overreacted.io\/goodbye-clean-code\/\">a little duplication isn&#8217;t the worst thing in the world<\/a>; it can be clearer, and it can be <a href=\"https:\/\/sandimetz.com\/blog\/2016\/1\/20\/the-wrong-abstraction\">cheaper than the wrong abstraction<\/a>.<\/p>\n<p>And then it gets weird. Martin says that functions should not be large enough to hold <em>nested<\/em> control structures (conditionals and loops); equivalently, they should not be indented to more than two levels. He says blocks should be one line long, consisting probably of a single function call. He says that an ideal function has <em>zero arguments<\/em> (but still no side effects?), and that a function with just three arguments is confusing and difficult to test. Most bizarrely, Martin asserts that an ideal function is <em>two to four lines of code long<\/em>. This piece of advice is actually placed at the start of the chapter. It&#8217;s the first and most important rule:<\/p>\n<blockquote>\n<p>The first rule of functions is that they should be small. The second rule of functions is that <em>they should be smaller than that<\/em>. This is not an assertion that I can justify. I can\u2019t provide any references to research that shows that very small functions are better. What I can tell you is that for nearly four decades I have written functions of all different sizes. I\u2019ve written several nasty 3,000-line abominations. I\u2019ve written scads of functions in the 100 to 300 line range. And I\u2019ve written functions that were 20 to 30 lines long. What this experience has taught me, through long trial and error, is that functions should be very small.<\/p>\n<p>[&#8230;]<\/p>\n<p>When Kent [Beck] showed me the code, I was struck by how small all the functions were. I was used to functions in Swing programs that took up miles of vertical space. Every function in <em>this<\/em> program was just two, or three, or four lines long. Each was transparently obvious. Each told a story. And each led you to the next in a compelling order. <em>That\u2019s<\/em> how short your functions should be!<\/p>\n<\/blockquote>\n<p>All of this sounds like hyperbole. A case for short functions instead of long ones can certainly be made, but we assume that Martin doesn&#8217;t <em>literally<\/em> mean that every function in our entire application <em>must<\/em> be four lines long or less.<\/p>\n<p>But the book is being absolutely serious about this. All of this advice culminates in the following source code listing at the end of chapter 3. This example code is <strong>Martin&#8217;s preferred refactoring<\/strong> of <a href=\"https:\/\/github.com\/unclebob\/fitnesse\/blob\/3bec390e6f8e9e341149b7d060551a92b93d3154\/src\/fitnesse\/html\/HtmlUtil.java#L279-L331\">a pair of Java methods<\/a> originating in an open-source testing tool, <a href=\"http:\/\/www.fitnesse.org\/\">FitNesse<\/a>.<\/p>\n<pre>\npackage fitnesse.html;\n\nimport fitnesse.responders.run.SuiteResponder;\nimport fitnesse.wiki.*;\n\npublic class SetupTeardownIncluder {\n  private PageData pageData;\n  private boolean isSuite;\n  private WikiPage testPage;\n  private StringBuffer newPageContent;\n  private PageCrawler pageCrawler;\n\n\n  public static String render(PageData pageData) throws Exception {\n    return render(pageData, false);\n  }\n\n  public static String render(PageData pageData, boolean isSuite)\n    throws Exception {\n    return new SetupTeardownIncluder(pageData).render(isSuite);\n  }\n\n  private SetupTeardownIncluder(PageData pageData) {\n    this.pageData = pageData;\n    testPage = pageData.getWikiPage();\n    pageCrawler = testPage.getPageCrawler();\n    newPageContent = new StringBuffer();\n  }\n\n  private String render(boolean isSuite) throws Exception {\n     this.isSuite = isSuite;\n    if (isTestPage())\n      includeSetupAndTeardownPages();\n    return pageData.getHtml();\n  }\n\n  private boolean isTestPage() throws Exception {\n    return pageData.hasAttribute(\"Test\");\n  }\n\n  private void includeSetupAndTeardownPages() throws Exception {\n    includeSetupPages();\n    includePageContent();\n    includeTeardownPages();\n    updatePageContent();\n  }\n\n\n  private void includeSetupPages() throws Exception {\n    if (isSuite)\n      includeSuiteSetupPage();\n    includeSetupPage();\n  }\n\n  private void includeSuiteSetupPage() throws Exception {\n    include(SuiteResponder.SUITE_SETUP_NAME, \"-setup\");\n  }\n\n  private void includeSetupPage() throws Exception {\n    include(\"SetUp\", \"-setup\");\n  }\n\n  private void includePageContent() throws Exception {\n    newPageContent.append(pageData.getContent());\n  }\n\n  private void includeTeardownPages() throws Exception {\n    includeTeardownPage();\n    if (isSuite)\n      includeSuiteTeardownPage();\n  }\n\n  private void includeTeardownPage() throws Exception {\n    include(\"TearDown\", \"-teardown\");\n  }\n\n  private void includeSuiteTeardownPage() throws Exception {\n    include(SuiteResponder.SUITE_TEARDOWN_NAME, \"-teardown\");\n  }\n\n  private void updatePageContent() throws Exception {\n    pageData.setContent(newPageContent.toString());\n  }\n\n  private void include(String pageName, String arg) throws Exception {\n    WikiPage inheritedPage = findInheritedPage(pageName);\n    if (inheritedPage != null) {\n      String pagePathName = getPathNameForPage(inheritedPage);\n      buildIncludeDirective(pagePathName, arg);\n    }\n  }\n\n  private WikiPage findInheritedPage(String pageName) throws Exception {\n    return PageCrawlerImpl.getInheritedPage(pageName, testPage);\n  }\n\n  private String getPathNameForPage(WikiPage page) throws Exception {\n    WikiPagePath pagePath = pageCrawler.getFullPath(page);\n    return PathParser.render(pagePath);\n  }\n\n  private void buildIncludeDirective(String pagePathName, String arg) {\n    newPageContent\n      .append(\"n!include \")\n      .append(arg)\n      .append(\" .\")\n      .append(pagePathName)\n      .append(\"n\");\n  }\n}\n<\/pre>\n<p>I&#8217;ll say again: this is Martin&#8217;s own code, written to his personal standards. This is the ideal, presented to us as a learning example.<\/p>\n<p>I will confess at this stage that my Java skills are dated and rusty, almost as dated and rusty as this book, which is from 2008. But surely, even in 2008, this code was illegible trash?<\/p>\n<p>Let&#8217;s ignore the wildcard <code>import<\/code>.<\/p>\n<p>First, the class name, <code>SetupTeardownIncluder<\/code>, is dreadful. It <em>is<\/em>, at least, a noun phrase, as all class names should be. But it&#8217;s a nouned verb phrase, the strangled kind of class name you invariably get when you&#8217;re working in strictly object-oriented code, where everything has to be a class, but sometimes the thing you really need is just one simple gosh-danged <em>function<\/em>.<\/p>\n<p>Inside the class, we have:<\/p>\n<ul>\n<li>two public, static methods, as before, plus<\/li>\n<li>one new private constructor and<\/li>\n<li><strong>fifteen<\/strong> new private methods.<\/li>\n<\/ul>\n<p>Of the fifteen private methods, fully thirteen of them either have side effects (they modify variables which were not passed into them as arguments, such as <code>buildIncludeDirective<\/code>, which has side effects on <code>newPageContent<\/code>) or call out to other methods which have side effects (such as <code>include<\/code>, which calls <code>buildIncludeDirective<\/code>). Only <code>isTestPage<\/code> and <code>findInheritedPage<\/code> look to be side-effect-free. They still make use of variables which aren&#8217;t passed into them (<code>pageData<\/code> and <code>testPage<\/code> respectively) but they <em>appear<\/em> to do so in side-effect-free ways.<\/p>\n<p>At this point you might reason that maybe Martin&#8217;s definition of &#8220;side effect&#8221; doesn&#8217;t include member variables of the object whose method we just called. If we take this definition, then the five member variables, <code>pageData<\/code>, <code>isSuite<\/code>, <code>testPage<\/code>, <code>newPageContent<\/code> and <code>pageCrawler<\/code>, are implicitly passed to <em>every<\/em> private method call, and they are considered fair game; any private method is free to do anything it likes to any of these variables.<\/p>\n<p>But Martin&#8217;s own definition contradicts this. This is from earlier in this exact chapter, with emphasis added:<\/p>\n<blockquote>\n<p>Side effects are lies. Your function promises to do one thing, but it also does other hidden things. <strong>Sometimes it will make unexpected changes to the variables of its own class.<\/strong> Sometimes it will make them to the parameters passed into the function or to system globals. In either case they are devious and damaging mistruths that often result in strange temporal couplings and order dependencies.<\/p>\n<\/blockquote>\n<p>I like this definition. I agree with this definition. It&#8217;s a useful definition, because it enables us to reason about what a function does, with some degree of confidence, by referring only to its inputs and output. I agree that it&#8217;s bad for a function to make <em>unexpected<\/em> changes to the variables of its own class.<\/p>\n<p>So why does Martin&#8217;s own code, &#8220;clean&#8221; code, do <em>nothing but this<\/em>? Rather than have a method pass arguments to another method, Martin makes a distressing habit of having the first method set a member variable which the second method, or some other method, then reads back. This makes it incredibly hard to figure out what any of this code does, because all of these incredibly tiny methods do almost nothing and work exclusively through side effects.<\/p>\n<p>Let&#8217;s just look at one private method.<\/p>\n<pre>\nprivate String render(boolean isSuite) throws Exception {\n   this.isSuite = isSuite;\n  if (isTestPage())\n    includeSetupAndTeardownPages();\n  return pageData.getHtml();\n}\n<\/pre>\n<p>So&#8230; imagine that someone enters a kitchen, because they want to show you how to make a cup of coffee. As you watch carefully, they flick a switch on the wall. The switch looks like a light switch, but none of the lights in the kitchen turn on or off. Next, they open a cabinet and take down a mug, set it on the worktop, and then tap it twice with a teaspoon. They wait for thirty seconds, and finally they reach behind the refrigerator, where you can&#8217;t see, and pull out a <em>different<\/em> mug, this one full of fresh coffee.\n<\/p>\n<p>&#8230;What just happened? What was flicking the switch for? Was tapping the empty mug part of the procedure? Where did the coffee come from?<\/p>\n<p>That&#8217;s what this code is like. Why does <code>render<\/code> have a side effect of setting the value of <code>this.isSuite<\/code>? When is <code>this.isSuite<\/code> read back, in <code>isTestPage<\/code>, in <code>includeSetupAndTeardownPages<\/code>, in both, in neither? If it does get read back, why not just pass <code>isSuite<\/code> in as a Boolean? Or perhaps the caller reads it back?<\/p>\n<p>Why do we return <code>pageData.getHtml()<\/code> when we never touched <code>pageData<\/code>? How did the HTML get there? Was it already there? We might make an educated guess that <code>includeSetupAndTeardownPages<\/code> has side effects on <code>pageData<\/code>, but then, what? We can&#8217;t know either way until we look. And what other side effects does that have on other member variables? The uncertainty becomes so great that we suddenly have to wonder if calling <code>isTestPage()<\/code> could have side effects too.<\/p>\n<p>How would you unit-test this method? Well, you can&#8217;t. It&#8217;s not a unit. It can&#8217;t be separated from the side-effects it has on other parts of the code. (And what&#8217;s up with the indentation? And where are the danged braces?)<\/p>\n<p>Martin states, in this very chapter, that it makes sense to break a function down into smaller functions &#8220;if you can extract another function from it with a name that is not merely a restatement of its implementation&#8221;. But then he gives us:<\/p>\n<pre>\nprivate boolean isTestPage() throws Exception {\n  return pageData.hasAttribute(\"Test\");\n}\n<\/pre>\n<p>and:<\/p>\n<pre>\nprivate WikiPage findInheritedPage(String pageName) throws Exception {\n  return PageCrawlerImpl.getInheritedPage(pageName, testPage);\n}\n<\/pre>\n<p>and half a dozen others, none of which are even called from more than one location.<\/p>\n<p>There is at least one questionable aspect of this code which isn&#8217;t Martin&#8217;s fault: the fact that <code>pageData<\/code>&#8216;s content gets destroyed. Unlike the member variables (<code>isSuite<\/code>, <code>testPage<\/code>, <code>newPageContent<\/code> and <code>pageCrawler<\/code>), <code>pageData<\/code> is not actually ours to modify. It is originally passed in to the top-level public <code>render<\/code> methods by an external caller. The <code>render<\/code> method does a lot of work and ultimately returns a <code>String<\/code> of HTML. However, during this work, as a side effect, <code>pageData<\/code> is destructively modified (see <code>updatePageContent<\/code>). Surely it would be preferable to create a brand new <code>PageData<\/code> object with our desired modifications, and leave the original untouched? If the caller tries to use <code>pageData<\/code> for something else afterwards, they might be very surprised about what&#8217;s happened to its content. But this is <a href=\"https:\/\/github.com\/unclebob\/fitnesse\/blob\/3bec390e6f8e9e341149b7d060551a92b93d3154\/src\/fitnesse\/html\/HtmlUtil.java#L329\">how the original code behaved<\/a> prior to the refactoring, and the behaviour could be intentional. Martin has preserved the behaviour, though he has buried it very effectively.<\/p>\n<p>Some other mild puzzles: why do we use <code>pageData.hasAttribute(\"Test\")<\/code> to figure out whether this is a test page, but we have to consult a separate Boolean to figure out whether or not this is a test <em>suite<\/em> page? And what exactly is the separation of concerns between <code>PageCrawler<\/code> and <code>PageCrawlerImpl<\/code>, both of which are in use here?<\/p>\n<h4>*<\/h4>\n<p>Is the whole book like this?<\/p>\n<p>Pretty much, yeah. <i>Clean Code<\/i> mixes together a disarming combination of strong, timeless advice and advice which is highly questionable or dated or both.<\/p>\n<p>Much of the book is no longer of much use. There are multiple chapters of what are basically filler, focusing on laborious worked examples of refactoring Java code; there is a whole chapter examining the internals of JUnit. This book is from 2008, so you can imagine how relevant that is now. There&#8217;s a whole chapter on formatting, which these days reduces to a single sentence: &#8220;Pick a sensible standard formatting, configure automated tools to enforce it, and then never think about this topic again.&#8221;<\/p>\n<p>The content focuses almost exclusively on object-oriented code, to the exclusion of other programming paradigms. Object-oriented programming was very fashionable at the time of publication. Martin is a huge proponent of OO, having invented three of the five principles which make up <a href=\"https:\/\/en.wikipedia.org\/wiki\/SOLID\">SOLID<\/a>, and having popularised the term. But the total absence of functional programming techniques or even simple procedural code was regrettable even then, and has only grown more obvious in the years since.<\/p>\n<p>The book focuses on Java code, to the exclusion of other programming languages, even other object-oriented programming languages. Java was popular at the time, and if you&#8217;re writing a book like this, it makes sense to pick a single well-known language and stick with it, and Java is still very popular and may still be a strong choice for this purpose. But the book&#8217;s overall use of Java is very dated.<\/p>\n<p>This kind of thing is unavoidable \u2014 programming books date legendarily poorly. That&#8217;s part of the reason why <i>Clean Code<\/i> was a recommended read at one time, and I now think that the pendulum is swinging back in the opposite direction.<\/p>\n<p>But even for the time, even for 2008-era Java, much of the provided code is <em>bad<\/em>.<\/p>\n<p>There&#8217;s a chapter on unit testing. There&#8217;s a lot of good, basic, stuff in this chapter, about how unit tests should be fast, independent and repeatable, about how unit tests enable more confident refactoring of source code, about how unit tests should be about as voluminous as the code under test, but strictly simpler to read and comprehend. But then he shows us a unit test with what he says is too much detail:<\/p>\n<pre>\n@Test\n  public void turnOnLoTempAlarmAtThreashold() throws Exception {\n    hw.setTemp(WAY_TOO_COLD);\n    controller.tic();\n    assertTrue(hw.heaterState());\n    assertTrue(hw.blowerState());\n    assertFalse(hw.coolerState());\n    assertFalse(hw.hiTempAlarm());\n    assertTrue(hw.loTempAlarm());\n  }\n<\/pre>\n<p>and he proudly refactors it to:<\/p>\n<pre>\n@Test\n  public void turnOnLoTempAlarmAtThreshold() throws Exception {\n    wayTooCold();\n    assertEquals(\u201cHBchL\u201d, hw.getState());\n  }\n<\/pre>\n<p>This is done as part of an overall lesson in the virtue of <em>inventing a new domain-specific testing language for your tests<\/em>. I was left so confused by this suggestion. I would use exactly the same code to demonstrate exactly the opposite lesson. Don&#8217;t do this!<\/p>\n<p>Which is to say nothing of the method named <code>wayTooCold<\/code>. This is an adjective phrase. It&#8217;s entirely unclear what this method does. Does it <em>set<\/em> the world&#8217;s state to be way too cold? Does it <em>react<\/em> to the world&#8217;s state <em>becoming<\/em> way too cold? Or is it an <em>assertion<\/em> that the world&#8217;s state currently must <em>be<\/em> way too cold?<\/p>\n<p>Methods should have verb or verb phrase names like <code>postPayment<\/code>, <code>deletePage<\/code>, or <code>save<\/code>. That&#8217;s not me saying that. That&#8217;s a direct quote from this book. Chapter 2, &#8220;Meaningful Names&#8221;:<\/p>\n<blockquote>\n<p>Methods should have verb or verb phrase names like <code>postPayment<\/code>, <code>deletePage<\/code>, or <code>save<\/code>.<\/p>\n<\/blockquote>\n<p>This is perfectly sound advice. And <code>hw.setTemp(WAY_TOO_COLD);<\/code> was a perfectly unambiguous line of code. What gives?<\/p>\n<p>And even if you guess correctly that calling <code>wayTooCold()<\/code> <em>sets<\/em> the temperature to be way too cold&#8230; there&#8217;s no way that you could guess that it also calls <code>controller.tic()<\/code> internally. Earlier, we were advised to avoid code having side effects. This, also, was sound advice. And it is, again, being ignored in the actual written code example.<\/p>\n<p>(And since we&#8217;re here, this, the original unrefactored code, is a fine demonstration of the drawbacks of unadorned Booleans. What does it mean when, say, <code>coolerState<\/code> returns <code>true<\/code>? Does it mean that the cooler&#8217;s current state is good, <i>i.e.<\/i> cold enough, <i>i.e.<\/i> switched off? Or does it mean that it is powered on, and actively cooling? An <code>enum<\/code> with a few values, <code>ON<\/code> and <code>OFF<\/code>, could be less ambiguous.)<\/p>\n<h4>*<\/h4>\n<p>The book presents us with the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Test-driven_development\">TDD<\/a> loop:<\/p>\n<blockquote>\n<p><b>First Law<\/b> You may not write production code until you have written a failing unit test.<\/p>\n<p><b>Second Law<\/b> You may not write more of a unit test than is sufficient to fail, and not compiling is failing.<\/p>\n<p><b>Third Law<\/b> You may not write more production code than is sufficient to pass the currently failing test.<\/p>\n<p>These three laws lock you into a cycle that is perhaps thirty seconds long. The tests and the production code are written together, with the tests just a few seconds ahead of the production code.<\/p>\n<\/blockquote>\n<p>But the book doesn&#8217;t acknowledge the missing zeroth step in the process: figuring out how to break down the programming task in front of you, so that you can take a minuscule thirty-second bite out of it. <em>That<\/em>, in many cases, is exceedingly time-consuming, and frequently obviously useless, and frequently impossible.<\/p>\n<h4>*<\/h4>\n<p>There&#8217;s a whole chapter on &#8220;Objects and Data Structures&#8221;. In it, we&#8217;re provided with this example of a data structure:<\/p>\n<pre>\npublic class Point {\n  public double x;\n  public double y;\n}\n<\/pre>\n<p>and this example of an object (well, the interface for one):<\/p>\n<pre>\npublic interface Point {\n  double getX();\n  double getY();\n  void setCartesian(double x, double y);\n  double getR();\n  double getTheta();\n  void setPolar(double r, double theta);\n}\n<\/pre>\n<p>Martin writes:<\/p>\n<blockquote>\n<p>These two examples show the difference between objects and data structures. Objects hide their data behind abstractions and expose functions that operate on that data. Data structure expose their data and have no meaningful functions. Go back and read that again. Notice the complimentary nature of the two definitions. They are virtual opposites. This difference may seem trivial, but it has far-reaching implications.<\/p>\n<\/blockquote>\n<p>And&#8230; that&#8217;s it?<\/p>\n<p>Yes, you&#8217;re understanding this correctly. Martin&#8217;s definition of &#8220;data structure&#8221; disagrees with the definition everybody else uses. This is a very strange choice of definition, though Martin does at least define his term clearly. Drawing a clear distinction between objects as dumb data and objects as sophisticated abstractions with methods is legitimate, and useful. But it&#8217;s quite glaring that there is no content in the book <em>at all<\/em> about clean coding using <a href=\"https:\/\/en.wikipedia.org\/wiki\/List_of_data_structures\">what most of us consider to be real data structures<\/a>: arrays, linked lists, hash maps, binary trees, graphs, stacks, queues and so on. This chapter is <em>much<\/em> shorter than I expected, and contains very little information of value.<\/p>\n<h4>*<\/h4>\n<p>I&#8217;m not going to rehash all the rest of my notes. I took a lot of them, and calling out everything I perceive to be wrong with this book would be counterproductive. I&#8217;ll stop with one more egregious piece of example code. This is from chapter 8, a prime number generator:<\/p>\n<pre>\npackage literatePrimes;\n\nimport java.util.ArrayList;\n\npublic class PrimeGenerator {\n  private static int[] primes;\n  private static ArrayList<Integer> multiplesOfPrimeFactors;\n\n  protected static int[] generate(int n) {\n    primes = new int[n];\n    multiplesOfPrimeFactors = new ArrayList<Integer>();\n    set2AsFirstPrime();\n    checkOddNumbersForSubsequentPrimes();\n    return primes;\n  }\n\n  private static void set2AsFirstPrime() {\n    primes[0] = 2;\n    multiplesOfPrimeFactors.add(2);\n  }\n\n  private static void checkOddNumbersForSubsequentPrimes() {\n    int primeIndex = 1;\n    for (int candidate = 3;\n         primeIndex < primes.length;\n         candidate += 2) {\n      if (isPrime(candidate))\n        primes[primeIndex++] = candidate;\n    }\n  }\n\n  private static boolean isPrime(int candidate) {\n    if (isLeastRelevantMultipleOfNextLargerPrimeFactor(candidate)) {\n      multiplesOfPrimeFactors.add(candidate);\n      return false;\n    }\n    return isNotMultipleOfAnyPreviousPrimeFactor(candidate);\n  }\n\n  private static boolean\n  isLeastRelevantMultipleOfNextLargerPrimeFactor(int candidate) {\n    int nextLargerPrimeFactor = primes[multiplesOfPrimeFactors.size()];\n    int leastRelevantMultiple = nextLargerPrimeFactor * nextLargerPrimeFactor;\n    return candidate == leastRelevantMultiple;\n  }\n\n  private static boolean\n  isNotMultipleOfAnyPreviousPrimeFactor(int candidate) {\n    for (int n = 1; n < multiplesOfPrimeFactors.size(); n++) {\n      if (isMultipleOfNthPrimeFactor(candidate, n))\n        return false;\n    }\n    return true;\n  }\n\n  private static boolean\n  isMultipleOfNthPrimeFactor(int candidate, int n) {\n   return\n     candidate == smallestOddNthMultipleNotLessThanCandidate(candidate, n);\n  }\n\n  private static int\n  smallestOddNthMultipleNotLessThanCandidate(int candidate, int n) {\n    int multiple = multiplesOfPrimeFactors.get(n);\n    while (multiple < candidate)\n      multiple += 2 * primes[n];\n    multiplesOfPrimeFactors.set(n, multiple);\n    return multiple;\n  }\n}\n<\/pre>\n<p>What the heck is this code? What is this algorithm? What are these <em>method names<\/em>? <code>set2AsFirstPrime<\/code>? <code>smallestOddNthMultipleNotLessThanCandidate<\/code>? Why does the code break with an out-of-bounds exception if we replace the <code>int[]<\/code> with a second <code>ArrayList<Integer><\/code>? Earlier, we were advised that a method should be a command, which <em>does<\/em> something, or a query, which <em>answers<\/em> something, but not both. This was good advice, so why do nearly all of these methods ignore it? And what of thread safety?<\/p>\n<p>Is this meant to be clean code? Is this meant to be a legible, intelligent way to search for prime numbers? Are we supposed to write code like this? And if not, why is this example in the book? And where is the \"real\" answer?<\/p>\n<p>If this is the quality of code which this programmer produces \u2014 at his own leisure, under ideal circumstances, with none of the pressures of real production software development, <em>as a teaching example<\/em> \u2014 then why should you pay any attention at all to the rest of his book? Or to his other books?<\/p>\n<h4>*<\/h4>\n<p>I wrote this essay because I keep seeing people recommend <i>Clean Code<\/i>. I felt the need to offer an anti-recommendation.<\/p>\n<p>I originally read <i>Clean Code<\/i> as part of a reading group which had been organised at work. We read about a chapter a week for thirteen weeks. (The book has seventeen chapters, we skipped some for reasons already mentioned.)<\/p>\n<p>Now, you don't want a reading group to get to the end of each session with nothing but unanimous agreement. You want the book to draw out some kind of reaction from the readers, something additional to say in response. And I guess, to a certain extent, that means that the book has to either say something you disagree with, or not say everything you think it should say. On that basis, <i>Clean Code<\/i> was <em>okay<\/em>. We had good discussions. We were able to use the individual chapters as launching points for deeper discussions of <em>actual<\/em> modern practices. We talked about a great deal which was not covered in the book. We disagreed with a lot in the book.<\/p>\n<p>Would I recommend this book? <strong>No.<\/strong> Would I recommend it as a beginner's text, with all the caveats above? No. Would I recommend it as a historical artifact, an educational snapshot of what programming best practices used to look like, way back in 2008? No, I would not.<\/p>\n<h4>*<\/h4>\n<p>So the killer question is, what book(s) would I recommend instead? I don't know. Suggestions in the comments, unless I've closed them.<\/p>\n<h3 id=\"sec0\">Update, 2020-12-19<\/h3>\n<p>After suggestions from comments below, I read <i>A Philosophy of Software Design<\/i> (2018) by John Ousterhout and found it to be a much more positive experience. I would be happy to recommend it over <i>Clean Code<\/i>.<\/p>\n<p><i>A Philosophy of Software Design<\/i> is not a drop-in replacement for <i>Clean Code<\/i>. As the title suggests, it focuses more on the practice of software design at a higher level than it does on the writing or critiquing of actual individual lines of code. (As such, it contains relatively few code examples.) Because it's aimed at this higher level, I think it's possibly not a suitable read for absolute beginner programmers. A lot of this high-level theory is difficult to comprehend or put into practice until you have some real experience to compare it with. I think there actually is something of a gap in the market for an entry-level introductory programming text right now.<\/p>\n<p>Having said that, I found <i>A Philosophy of Software Design<\/i> to be informative, cogent, concise and <em>much<\/em> more up-to-date. I found that I agreed with nearly all of Ousterhout's assertions and suggestions for good software design, many of which are diametrically opposed to those found in <i>Clean Code<\/i>. By virtue of providing relatively high-level advice, I feel that the book is likely to age rather better too.<\/p>\n<p>Of course, software development is still moving forwards as I write this. Who knows what a good programming book will look like in ten more years?<\/p>\n<h3 id=\"sec1\">Afterword, 2022-03-21<\/h3>\n<p>Probably the most common defence of <i>Clean Code<\/i> that I've seen coming from readers of this essay is that the book <em>is<\/em> still worth recommending, despite the objections above, because the advice in the book shouldn't be taken entirely literally, or applied dogmatically. The burden is on the reader to think critically, draw their own conclusions, and selectively ignore the book's advice when that advice is bad. Even the book itself says:<\/p>\n<blockquote>\n<p>[M]any of the recommendations in this book are controversial. You will probably not agree with all of them. You might violently disagree with some of them. That's fine. We can't claim final authority.<\/p>\n<\/blockquote>\n<p>I don't think this is a particularly convincing defence of the book containing bad advice and bad example code in the first place.<\/p>\n<p>It's true that we should always engage critically with material instead of passively letting it wash over us. This is universally understood; this is what reading <em>is<\/em>; this is what the essay above is. This doesn't need to be stated, and it's redundant for the book itself to mention the point at all. This isn't something which can be used to shield a book from criticism.<\/p>\n<p>What's more important is what the book actually says. And, especially in an instructional text like this, <em>how carefully<\/em> the book has to be read in order to get a positive experience out of it, and what happens if the book isn't read sufficiently critically.<\/p>\n<p>Experienced programmers will get almost nothing out of reading <i>Clean Code<\/i>. They'll be able to weigh the advice given against their own experiences and make an informed decision \u2014 and the book will tell them almost nothing that they didn't learn years ago.<\/p>\n<p>Inexperienced programmers, meanwhile \u2014 and <i>Clean Code<\/i> is an entry-level programming text, so this is the target audience, whose experiences are most important \u2014 won't be able to distinguish the good advice from the bad, and won't be able to see that the example code is bad and shouldn't be imitated. Inexperienced programmers will take those lessons at face value, and it might be years before they figure out how badly they were misled.<\/p>\n<\/p><\/div>\n<p><a href=\"https:\/\/qntm.org\/clean\" class=\"button purchase\" rel=\"nofollow noopener\" target=\"_blank\">Read More<\/a><br \/>\n Elroy Coby<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It may not be possible for us to ever reach empirical definitions of &#8220;good code&#8221; or &#8220;clean code&#8221;, which means that any one person&#8217;s opinions about another person&#8217;s opinions about &#8220;clean code&#8221; are necessarily highly subjective. I cannot review Robert C. Martin&#8217;s 2008 book Clean Code from your perspective, only mine. That said, the major<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4188,30126,46],"tags":[],"class_list":{"0":"post-609404","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-probably","7":"category-recommending","8":"category-technology"},"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/posts\/609404","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/comments?post=609404"}],"version-history":[{"count":0,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/posts\/609404\/revisions"}],"wp:attachment":[{"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/media?parent=609404"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/categories?post=609404"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/newsycanuse.com\/index.php\/wp-json\/wp\/v2\/tags?post=609404"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}