Library
A Philosophy of Software Design · 7 of 11
A Philosophy of Software Design
AI Software Development HIGH

Naming, Consistency, and Obviousness

naming consistency obviousness cognitive-load conventions

Key Principle

Names must be precise and consistent. Naming difficulty is a diagnostic signal -- if you cannot find a short, precise name, the underlying entity likely conflates multiple concerns and needs redesign. Consistency creates cognitive leverage: once a reader learns a convention, it applies everywhere without re-learning. Obviousness is reader-defined, not writer-defined, and several common patterns (event-driven programming, generic containers) systematically reduce it.

Why This Matters

Imprecise or inconsistent naming causes structural bugs that can take months to surface. Ousterhout recounts a six-month debugging ordeal caused by reusing the variable name block for both file blocks and disk blocks. The shared name created a false assumption of shared semantics, leading to silent data corruption. (Chapter 14)

Conventions that erode silently as teams grow force developers to learn multiple competing patterns and reason about which applies where -- a direct multiplication of cognitive load. "Having a 'better idea' is not a sufficient excuse to introduce inconsistencies" (Chapter 17). Replacing an existing convention with a marginally better one almost always destroys more value through inconsistency than it creates.

Good Examples

Treating invariants as consistency eliminates special cases. If a property is always true (e.g., every text line terminated by a newline), code never needs to check whether it holds -- the same mechanism as "define errors out of existence." (Chapter 17)

Automated enforcement beats documentation for maintaining conventions. A project with line-termination problems tried documentation first; it failed. A pre-commit script rejecting carriage returns "instantly eliminated the problems." (Chapter 17)

The three naming consistency rules: (1) always use the common name for a given purpose, (2) never use that name for anything else, (3) ensure the purpose is narrow enough that all variables with that name behave the same way. (Chapter 14)

Counterpoints

Go style favors short, reused names (ch for character or channel). Ousterhout's response: readability is determined by readers, not writers. But he agrees with the Go principle that name length should scale with the distance between declaration and use. (Chapter 14)

Event-driven programming makes control flow determined at runtime, not visible in code -- creating unknown unknowns. (Chapter 18)

Generic containers (e.g., Pair) give meaningful data meaningless names (getKey), producing shallow interfaces that obscure intent. Declaring List but allocating ArrayList forces the reader to hold both types in mind simultaneously. (Chapter 18)

Code that violates expectations (e.g., a main method that does not exit the program) breaks implicit contracts without notice, creating unknown unknowns. (Chapter 18)

Key Quotes

"If you find it difficult to come up with a name for a particular variable that is precise, intuitive, and not too long, this is a red flag." -- John Ousterhout, Chapter 14

"If different variable names had been used for the different kinds of blocks, such as fileBlock and diskBlock, it's unlikely that the error would have happened." -- John Ousterhout, Chapter 14

"Having a 'better idea' is not a sufficient excuse to introduce inconsistencies." -- John Ousterhout, Chapter 17

"If someone reading your code says it's not obvious, then it's not obvious, no matter how clear it may seem to you." -- John Ousterhout, Chapter 18

Rules of Thumb

  • If naming is hard, treat it as a design problem: the entity likely does too much or cuts across concerns
  • Name length should scale with the distance between declaration and use
  • Never reuse a name for a semantically different purpose; never use different names for the same purpose
  • Prefer automated enforcement (linters, pre-commit hooks) over documented conventions
  • Change a convention only when the new approach is so superior it justifies updating every old use
  • Obviousness is determined by the reader; use code review as the primary instrument for detecting obscurity
  • Avoid generic containers that replace meaningful names with meaningless ones
  • Design for ease of reading, not ease of writing

Related References