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

Comments as a Design Tool

comments abstraction design-process documentation

Key Principle

Comments are structurally necessary for abstraction, not decorative. A method signature expresses types and arity but cannot express behavior, boundary conditions, or semantics. Without comments, users must read the implementation, which destroys the abstraction and re-exposes all the complexity the module was built to hide. Useful comments operate at two levels: precision (units, boundaries, null semantics) and intuition (purpose, conceptual framework). Writing comments first -- before implementation -- turns them into a design validation tool that catches bad abstractions early.

Why This Matters

Deep modules become shallow in practice without comments. The interface cost stays low (few methods) but the cognitive cost reverts to the full implementation complexity, eliminating the module's design value. The causal chain is direct: no comments leads to users reading implementations, which collapses abstraction, fully exposing complexity, and wasting the deep module investment.

Developers who write same-level comments that merely repeat the code conclude all comments are useless and stop writing them. The abstraction layer that comments should provide never forms. Meanwhile, writing comments as an afterthought produces poor documentation because the designer has "checked out mentally" and merely restates the code. (Chapter 15)

Good Examples

Lower-level precision: // Current offset in resp Buffer improved to // Position in this buffer of the first object that hasn't been returned to the client. The improved version specifies what "position" means, what "object" refers to, and the relationship to the client -- none of which the code can express. (Chapter 13)

Higher-level intuition: a complex loop's conditions all become explicable from one sentence: // Try to append the current key hash onto an existing RPC to the desired server that hasn't been sent yet. The reader understands the purpose without decoding each conditional. (Chapter 13)

Variable comments should use nouns, not verbs -- describe what a variable represents, not how it gets manipulated: "True means that a heartbeat has been received since the last time the election timer was reset." The manipulation behavior follows from the definition. (Chapter 13)

Counterpoints

Robert Martin's Clean Code frames comments as failures to express intent in code. Ousterhout's rebuttal: extracting comments into method names produces long cryptic names like isLeastRelevantMultipleOfNextLargerPrimeFactor that convey less information than a comment and must be repeated at every call site. Code signatures are formally precise but expressively narrow -- human language captures semantics that code structurally cannot. (Chapter 12)

The acid test for comment quality: could someone write this comment just by looking at the code? If yes, the comment adds nothing. A practical forcing function: use different words from the entity's name. (Chapter 13)

Cross-module design decisions affect multiple modules and have no natural single home. Without a central designNotes file or equivalent, these decisions go undocumented and become disproportionately bug-prone. (Chapter 13)

Key Quotes

"If users must read the code of a method in order to use it, then there is no abstraction: all of the complexity of the method is exposed." -- John Ousterhout, Chapter 12

"Comments serve as a canary in the coal mine of complexity." -- John Ousterhout, Chapter 15

"If you write comments describing the abstractions at the beginning, you can review and tune them before writing implementation code." -- John Ousterhout, Chapter 15

"Documentation also plays an important role in abstraction; without comments, you can't hide complexity." -- John Ousterhout, Chapter 12

Rules of Thumb

  • Write interface comments before implementation code; if the comment is long or convoluted, the abstraction needs rethinking
  • Lower-level comments add precision: units, inclusive vs. exclusive boundaries, null semantics, resource ownership
  • Higher-level comments add intuition: what the code is trying to do, not how it does it
  • Variable comments describe what a variable represents (nouns), not how it is manipulated (verbs)
  • The farther a comment is from the code it describes, the more abstract it should be
  • Use different words from the entity's name to avoid restating the obvious
  • For cross-module design decisions, maintain a central designNotes file referenced from code

Related References