Skip to content
Sibo Yang
LinkedinGithub

Clean Code Reading Notes

Reading4 min read

Meaningful Names

  • Use Intention-Revealing Names
    • It should tell you why it exists, what it does, and how it is used. If a name requires a comment, then the name does not reveal its intent.
  • Avoid Disinformation:
    • Do not refer to a grouping of accounts as an accountList unless it's actually a List. accountGroup or bunchOfAccounts or just plain accounts would be better.
    • Truly awful example of disinformative names would be the use of lowercase L or uppercase O as variable names.
  • Make Meaningful Distinctions:
    • Number-series naming (a1, a2, .. , an) is the opposite of intentional naming. They are noninformative.
    • Noise words are another meaningless distinction. ProdcutData and ProdcuctInfo have different names but doesn't mean differently.
  • Use Pronounceable Name:
    • If you can't pronounce it, you can't discuss it without sounding like an idiot.
  • User Searchable Names:
    • Single letter names can ONLY be used as local variables inside short methods.
    • The length of a name should correspond to the size of its scope.
  • Class Names:
    • Class and objects should have noun or noun phrase names, a class name should not be a verb.
  • Method Names:
    • Methods should have verb or verb phrase names.
  • Pick One Word per Concept:
    • It is confusing to have fetch, retrieve and get as equivalent methods of different classes.
    • Likewise, it is confusing to have a controller and a manager and a driver in the same code base.
    • A consistent lexicon is a great boon to the programmer who must use your code.
  • Don't Pun:
    • Avoid using the same word for two purposes.
    • One may decide to use the word for "consistency" when he or she is not in fact adding in the same sense.
  • Add Meaningful Context:
    • We need to place names in context for our reader by enclosing them in well-named classes, functions or namespaces. When all else fails, then prefixing the name may be necessary as a last, resort.
    • state as a variable name is self is confusing, but we can put it in an Address class, or even add context by using prefixes like addrState

Functions

  • Do One Thing:

    • Functions should be very small.
    • If a function does only those steps that are one level below the stated name of the function, then the function is doing one thing.
    • A way to know that a function is doing more than "one thing" is if you can extract another function from it with a name that is not merely a restatement of its implementation.
  • One Level of Abstraction per Function

    • Functions cannot be at a high level of abstraction, such as getHTML() and low level of abstraction like .append('\n') at the same time.
    • 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.
  • Switch Statements:

    • It's hard to make a small switch statement. It's also hard to make a switch statement that does one thing. By their nature, switch statements always do N things.
    • Unfortunately we can't always avoid switch statements, but we can make sure that each switch statement is buried in a low-level class and is never repeated. We do this with polymorphism.
  • Function Arugments:

    • The number of function arguments should be as small as possible. It shouldn't be more than three.
    • Flag arguments are ugly. It not only immediately complicates the signature of the method, but also loudly proclaims that this function does more than one thing.
    • Reducing the number of arguments by creating objects out of them may seem like cheating, but it's not. When groups of variables are passed together, they are likely part of a concept that deserves a name of its own.
  • Have No Side Effects:

    • Functions promise to do one thing, they should not do hidden things.
    • Sometimes it will make unexpected changes to the variables of its own class, sometimes it will make them to the parameters passed into the function or to the system globals.
  • Command Query Separation:

    • Functions should either do something or answer something, but not both.
  • Error handling:

    • Returning error codes from command functions is a subtle violation of command query separation. It promotes commands being used as expressions in the predicates of if statements, such as if(delete(item)) == E_OK)
    • It is better to extract the bodies of the try and catch blocks out into functions of their own because they confuse the structure of the code and mix error processing with normal processing. It makes the function do more than one thing.