Updated: 2025-12-28 Sun 19:48

# clean-code

planted: 2025-07-27 last tended to: 2025-12-28

## Chapter 1: Clean Code

Referenced Items:

- Implementation Patterns, Kent Beck, Addison-Wesley, 2007.
- Literate Programming, Donald E. Knuth, Center for the Study of Language and Information, Leland Stanford Junior University, 1992.

Principles mentioned: Single Responsibility Principle (SRP), the Open Closed Principle (OCP), and the Dependency Inversion Principle (DIP)

## Chapter 2: Meaningful Names

### Use intention revealing names:

Names should reveal intent, there is no revelation in naming an integer `d`, intending it stands for days. Instead, you should use the following names:

    int elapsedTimeInDays;
    int daysSinceCreation;
    int daysSinceModification;
    int fileAgeInDays;

### Avoid disinformation

Don’t postfix the word ’list’ to the name ’accounts’ unless it’s actually a list. This is because the reader will assume the data type of accountsList is indeed a list, instead choose a name like `accountsGroup`.

### Make Meaningful Distinctions

While it is possible to name by being disinformative, it is also possible to name being non informative. Consider:

    public static void copyChars(char a1[], char a2[]) {
        for (int i = 0; i < a1.length; i++) {
            a2[i] = a1[i];
        }
    }

What on earth does `a[1]` and `a[2]` even stand for? We are better off using names like source and destination (due to the function’s intent of copying the array).

Furthermore, noise words are redundant. We should never use the word `variable` when naming a variable, or `table` when naming a table.

### Use Pronouncable Names

This is quite straightforward. Do not use a name like `genymdhms` to refer to generation date, year, month, day, hour, minute, and second. Instead use `generationTimeStamp`.

### Use Searchable Names

In modern IDE’s, it is still quite difficult to search for single-lettered variables. The writer states a personal preference of using single-letter names only as local variables and inside short methods. The following principle is given:

The length of a name should correspond to the size of its scope

### Avoid Encodings

Don’t prefix variables with letters like m_ as was done in the past. Do not type encode as well, an example of this is: `PhoneNumber phoneString;` we can see the reader being misled into thinking the phone number is a String.

### Avoid Mental Mappings

Clarity is king, don’t use a name for a variable that only you know what it stands for. For example: using the letter r as the lower-cased version of the url with the host and scheme removed. That’s being smart, not professional.

### Class Names

> Classes and objects should have noun or noun phrase names like Customer, WikiPage, Account, and AddressParser. Avoid words like Manager, Processor, Data, or Info in the name of a class. A class name should not be a verb.

> Classes and objects should have noun or noun phrase names like Customer, WikiPage, Account, and AddressParser. Avoid words like Manager, Processor, Data, or Info in the name of a class. A class name should not be a verb

### Method Names

Methods should have verb or verb phrase names.

### Don’t be cute/Don’t use puns

Do not use names that are only understandable to people whom you share jokes etc with. Furthermore, do not use colloquialism and slang in names.

- Example: `HandGrenade` instead of `DeleteItems`
- Example: `whack()` instead of `kill()`

### Pick one word per concept

If you have multiple choices for naming a concept, use one and stick with it. For instance if your options are fetch, get and retrieve, use one and stick with it throughout.

### Solution Domain Names and Problem Domain Names

Where possible use solution domain names, as the people that are going to be reading the code are programmers. Therefore, do not shy away from using CS terms, algorithm names, math names and so forth.

However when it is not possible to use solution domain names (in other words, when there is no “programmer-eese” then use the name from the problem domain. The other programmers can ask the domain expert for clarification. If the code is more to do with the problem domain concepts, then the names should be drawn from them.

### Add Meaningful Context

Enclose names with well-named classes, functions, or namespaces. When all else fails, then prefix with something that provides more context.

### Don’t add gratuitous context

Shorter names are better than longer ones, generally. This is so long as the context and intent is clear. Don’t add redundant or irrelevant additions to the name in the for the sake of ’context’.

## Chapter 3: Functions

### Functions should be small

Functions should be extremely short—ideally just a few lines, so they remain easy to understand and maintain.

Avoid deeply nested blocks; keep indentation shallow (1–2 levels), often replacing blocks with descriptive function calls.

A small function tells a concise, self-contained story, making it easier for readers to follow the program’s intent.

The smaller the function, the more descriptive and accurate its name can be, improving self-documentation.

Large functions hide complexity and mix abstraction levels, making errors and duplication more likely.

### Do One Thing & One Level of Abstraction

A function should do exactly one conceptual task, and all its statements should exist at the same abstraction level.

Mixing details (like string concatenation) with high-level actions (like rendering a page) causes confusion.

The Stepdown Rule: organise functions so they read like a top down narrative, each calling the next abstraction level.

If you can extract a subfunction with a name that isn’t a restatement, the original function is doing too much.

Functions that “do one thing” cannot be logically split into sections such as “initialize,” “process,” “finalize.”

### Switch Statements

Switch statements naturally violate “do one thing” by handling multiple cases; they also grow in size over time.

They break the Single Responsibility Principle (multiple reasons to change) and Open-Closed Principle (must change for new cases).

Preferred approach: hide switch statements inside a factory and dispatch behavior polymorphically through an interface.

Allow only one visible switch in your system, used solely for object creation, then encapsulate it.

This removes duplication and keeps high-level code unaware of concrete type distinctions.

Example:

    public abstract class Employee {
        public abstract boolean isPayday();
        public abstract Money calculatePay();
        public abstract void deliverPay(Money pay);
    }
    -----------------
        public interface EmployeeFactory {
            public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
        }
    -----------------
        public class EmployeeFactoryImpl implements EmployeeFactory {
            public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {
                switch (r.type) {
                case COMMISSIONED:
                    return new CommissionedEmployee(r) ;
                case HOURLY:
                    return new HourlyEmployee(r);
                case SALARIED:
                    return new SalariedEmploye(r);
                default:
                    throw new InvalidEmployeeType(r.type);
                }
            }
        }

### Use Descriptive Names

A function’s name should clearly state its purpose. Long, descriptive names beat short, cryptic ones.

Consistent naming patterns (shared verbs/nouns) help code read like a coherent story and aid predictability.

Descriptive names reduce the need for comments and improve comprehension without external documentation.

Renaming functions can reveal design improvements, so try multiple options until the best emerges.

IDE refactoring tools make renaming safe, encouraging experimentation.

### Function Arguments

> The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification—and then shouldn’t be used anyway.

Fewer arguments = better; aim for 0–2, avoid more than 3 unless absolutely necessary.

Flag arguments (booleans) are a red flag—they imply the function does multiple things.

Group related parameters into objects (e.g., `Point` for `x` and `y`) to reduce argument count and improve clarity.

Output arguments are confusing—prefer returning values or mutating the owning object’s state.

Match function/argument names in verb–noun or keyword style (e.g., `writeField(name)`, `assertExpectedEqualsActual`).

### Have No Side Effects

A function should do only what its name promises. Hidden state changes are misleading and dangerous.

Side effects create temporal coupling, meaning the function must be called in a certain sequence to be safe.

If unavoidable, make side effects explicit in the name (e.g., `checkPasswordAndInitializeSession`).

Clear separation of command and query functions avoids ambiguity in meaning and intent.

Functions that modify state and return information often cause confusion and should be split.

### Error Handling

Error handling is a single responsibility—separate it from normal logic to keep both paths clear.

Prefer exceptions over error codes to avoid cluttering the happy path and to reduce dependency magnets.

Extract try/catch bodies into their own functions for cleaner structure.

See below:

    public void delete(Page page) {
          try {
            deletePageAndAllReferences(page);
          }
          catch (Exception e) {
            logError(e);
          }
      }

    private void deletePageAndAllReferences(Page page) throws Exception {
        deletePage(page);
        registry.deleteReference(page.name);
        configKeys.deleteKey(page.name.makeKey());
    }
    private void logError(Exception e) {
        logger.log(e.getMessage());
    }

Keep functions small enough that occasional multiple return or break statements are acceptable.

Avoid duplication in error handling, and follow the DRY principle to ensure changes occur in one place.

## Chapter 4: Comments

Comments are a necessary evil—they exist because code fails to express intent clearly.

Outdated comments are dangerous; they can mislead more than help.

Strive to write code that explains itself; comments should be minimized.

Truth is always in the code, not in the comments.

### Comments Do Not Make Up for Bad Code

Don’t use comments to excuse messy, unclear code—clean the code instead.

Clear, expressive code with few comments > cluttered code with many comments.

    // Check to see if the employee is eligible for full benefits
    if ((employee.flags & HOURLY_FLAG) && (employee.age > 65))

    // Better:
    if (employee.isEligibleForFullBenefits())

### Good Comments

Only write them when unavoidable.

### Legal Comments

Sometimes required for copyright/licensing.

Keep them short; refer to standard licenses rather than embedding full legal text.

### Informative Comments

Explain return values, formats, or patterns.

Prefer naming/structuring code to make such comments unnecessary.

    // format matched kk:mm:ss EEE, MMM dd, yyyy
    Pattern timeMatcher = Pattern.compile("\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*");

### Explanation of Intent

Describe why a certain approach was chosen.

Helps future maintainers understand reasoning behind code.

return 1; // we are greater because we are the right type.

### Clarification

Translate obscure values into readable terms.

Useful when working with unchangeable APIs/libraries, but risky if incorrect.

### Warning of Consequences

Alert others about performance, thread-safety, or side effects.

// SimpleDateFormat is not thread safe, so create each instance independently.

### \TODO\ Comments

Mark incomplete work or planned improvements.

Should be reviewed regularly; not an excuse for bad code.

### Amplification

Highlight the importance of seemingly small details.

// the trim is real important. It removes starting spaces…

### Javadocs in Public APIs

Public APIs should have clear documentation.

Javadocs can also mislead—keep them accurate and up-to-date.

### Don’t Use a Comment When You Can Use a Function or Variable

Replace explanatory comments with expressive variable or function names.

Refactor code to remove comment redundancy.

### Position Markers

Avoid decorative banners like // Actions ///////////////////////—they add clutter.

Use sparingly and only for meaningful grouping.

Overuse makes them blend into background noise.

### Closing Brace Comments

Comments on closing braces (} // while) are unnecessary for small, well-structured functions.

Prefer short, clear functions over brace markers.

### Attributions and Bylines

Don’t add personal tags like /* Added by Rick */—use version control for authorship history.

Such comments become outdated and irrelevant over time.

### Commented-Out Code

Never keep old code commented out; delete it and rely on version control history.

Commented-out code adds clutter and confuses future maintainers.

    // Old cruft that should be deleted:
    //hdrPos = bytePos;
    //dataPos = bytePos;

### HTML Comments

Avoid HTML markup inside code comments—it makes them harder to read in the editor.

Let documentation tools (like Javadoc) handle formatting.

### Nonlocal Information

Comments should describe nearby code only, not unrelated parts of the system.

Avoid embedding global/system details that the function can’t control.

### Too Much Information

Avoid long, unnecessary historical or technical explanations.

Keep only relevant context (e.g., “RFC 2045” reference is fine, not the full spec).

### Inobvious Connection

Ensure the relationship between comment and code is clear.

Don’t make readers guess what part of the code the comment refers to.

    // plus filter bytes ... but which part is “filter”?
    this.pngBytes = new byte[((this.width + 1) * this.height * 3) + 200];

### Function Headers

Short, single-purpose functions with good names don’t need header comments.

Let the function name explain the purpose.

### Javadocs in Nonpublic Code

Javadocs are useful for public APIs, but excessive formality in internal code is just noise.

Internal methods should be self-explanatory without full doc comments.

### Example: Refactored Prime Generator

Original code: Over-commented, with redundant explanations and irrelevant history.

Refactored version: Only two comments remain—both explain why, not what.

One eases the reader into the algorithm.

One explains rationale for using the square root as a loop limit.

## Chapter 5: Formatting

### Vertical Formatting (Clean Code, Ch.5)

#### Vertical Formatting

- Vertical openness (blank lines) separates concepts and improves readability.
- Too much density makes code look like a muddle and harder to scan.

#### Vertical Density

- Tightly related lines should appear vertically dense.
- Avoid useless comments that interrupt association.
- Example (bad):

    public class ReporterConfig {
    /**
    * The class name of the reporter listener
    */
    private String m_className;

- Example (better):

    public class ReporterConfig {
    private String m_className;
    private List<Property> m_properties = new ArrayList<>();

#### Vertical Distance

- Related concepts should be kept close together to reduce scrolling and searching.
- Local variables → as close to use as possible, usually at top of function.
- Control variables → declared inside loop headers.
- Instance variables → declared at the top of class (common Java convention).

    for (Test each : tests) {
        count += each.countTestCases();
    }

- Dependent functions: caller above callee for natural top-down reading.

    public Response makeResponse(...) {
        String pageName = getPageNameOrDefault(request, "FrontPage");
        loadPage(pageName, context);
        return makePageResponse(context);
    }

    private String getPageNameOrDefault(Request request, String defaultPageName) { ... }

#### Conceptual Affinity

- Group functions with similar naming or shared purpose.
- Example (JUnit assert methods):

    static public void assertTrue(String message, boolean condition) { ... }
    static public void assertTrue(boolean condition) { ... }
    static public void assertFalse(String message, boolean condition) { ... }
    static public void assertFalse(boolean condition) { ... }

#### Vertical Ordering

- Organise code top down:
  - High-level concepts first (main logic).
  - Lower-level details later.
- Readers can skim like a newspaper: important first, details last.
- Contrast: C/C++ require declarations before use, Java does not.

#### Summary - vertical

- Use vertical openness to separate concepts.
- Use vertical density to group related ones.
- Keep related variables, methods, and concepts close together.
- Order code top down for natural readability.

### Horizontal Formatting

Keep lines short — most professional code naturally stays within ~45 characters, with ~80 as an upper bound. Lines beyond 100–120 characters are generally careless.

Avoid shrinking font or overly wide monitors to fit more code — readability > fitting more characters.

Example limit guideline:

    // Good (short)
    int sum = a + b + c;

    // Bad (too long)
    int sum = a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q;

### Horizontal Openness and Density

Use spaces to separate low-precedence operators (e.g., +, -, =) and improve readability.

Do not put spaces between function names and parentheses — they are closely related.

Example (Quadratic formula formatting):

    return (-b + Math.sqrt(determinant)) / (2*a);

Separate arguments with spaces after commas to show distinct parameters.

### Horizontal Alignment

Avoid aligning variable declarations or assignments in columns — it draws the eye to the wrong place.

Long aligned lists usually mean the class is too large and should be split.

Example (preferred unaligned):

      // Prefer this:
      private Socket socket;
      private InputStream input;
      private OutputStream output;

    //instead of:
    private Socket      socket;
    private InputStream input;
    private OutputStream output;

### Indentation

Indent according to scope hierarchy:

Classes → no indent

Methods → 1 level

Method bodies → 2 levels

Inner blocks → +1 for each nesting

Indentation makes scopes visually obvious; without it, code is hard to scan.

Avoid collapsing scopes onto one line — always use braces and proper indenting.

### Dummy Scopes

Avoid dummy bodies in loops (e.g., empty while or for loops).

If unavoidable, place semicolon on its own indented line to make it visible.

    while (dis.read(buf, 0, size) != -1)
        ;

### Team Rules

Teams must agree on a single formatting style for consistency.

Use IDE formatters to enforce these rules across all files.

Consistent formatting builds trust and reduces mental load for readers.

### Uncle Bob’s Formatting Rules (Example in CodeAnalyzer.java)

Short, clear methods with consistent spacing and indentation.

Use spaces around assignment and low-precedence operators, no space for high-precedence operators.

Avoid deeply nested structures — prefer clear, flat logic.

Example snippet:

    private void measureLine(String line) {
      lineCount++;
      int lineSize = line.length();
      totalChars += lineSize;
      lineWidthHistogram.addLine(lineSize, lineCount);
      recordWidestLine(lineSize);
    }

## Chapter 6: Objects and Data Structures

## Chapter 7: Error Handling

## Chapter 8: Boundaries

## Chapter 9: Unit Tests

## Chapter 10: Classes

## Chapter 11: Systems

## Chapter 12: Emergence

## Chapter 13: Concurrency

## Chapter 14: Successive Refinement

## Chapter 15: JUnit Internals

## Chapter 16: Refactoring SerialDate

## Chapter 17: Smells and Heuristics

## Apendix A: Concurrency II

Backlinks

- booknotes