Chapter 14: Choosing Names
Core Idea
Section titled “Core Idea”Names are a form of documentation and abstraction. Good names are precise and consistent, so a reader’s first guess about what a name refers to is correct. Because complexity is incremental, thousands of slightly vague names add up to real complexity, and a single bad name can cause a severe bug.
Frameworks Introduced
Section titled “Frameworks Introduced”- Create an image: a name should create an image in the reader’s mind of what the entity is, and just as important, what it is not.
- Test: “If someone sees this name in isolation, without seeing its declaration, its documentation, or any code that uses the name, how closely will they be able to guess what the name refers to? Is there some other name that will paint a clearer picture?”
- Limit: names become unwieldy beyond two or three words, so find the few words that capture what matters most.
- Two properties of good names:
- Precision: avoid generic or vague names. Also avoid names that are too specific for what the entity really is.
- Consistency, which has three requirements:
- Always use the common name for its purpose.
- Never use the common name for anything else.
- Keep the purpose narrow enough that every variable with that name behaves the same way.
- Distinguishing prefixes: when you need several variables of the same kind, keep the common name and add a prefix, such as
srcFileBlockanddstFileBlock. - Distance rule (from Andrew Gerrand, which the author agrees with): “The greater the distance between a name’s declaration and its uses, the longer the name should be.”
Key Concepts
Section titled “Key Concepts”- Red Flag: Vague Name: a name broad enough to refer to many different things conveys little and invites misuse.
- Red Flag: Hard to Pick Name: if it’s hard to find a simple name that creates a clear image, the underlying entity may not have a clean design. Perhaps one variable represents several things and should be split.
- Boolean names should be predicates:
cursorVisible, notblinkStatus. - Loop variable convention: if you use
iandj, always useifor outer loops andjfor nested ones. Short names are fine when the whole range of use is visible. result: reasonable in a method that returns it; misleading in a method with no return value.
Mental Models
Section titled “Mental Models”- Think of a name as an abstraction: it should focus attention on the most important aspect of the entity and omit the rest.
- “Readability must be determined by readers, not writers.” If people find your short names cryptic, lengthen them; if they find long names hard to read, shorten them.
- Treat naming skill as an investment. It is slow and frustrating at first, then becomes almost free.
- Don’t settle for names that are “reasonably close”; take a little time for names that are “precise, unambiguous, and intuitive.”
Anti-patterns
Section titled “Anti-patterns”- Generic names:
getCount()(count of what?) →numIndexletsorgetActiveIndexlets.x,yfor a character’s position in a file (they suggest pixel coordinates) →charIndex,lineIndex. - Names that say a value is special without saying how:
VOTED_FOR_SENTINEL_VALUE→NOT_YET_VOTED. - Too specific:
void delete(Range selection)suggests only selected text can be deleted;rangeis right. - One short name for several things: the Go practice of
chfor character or channel, ordfor data, difference, or distance. The author expects this to cause the same confusion as theblockbug.
Code Examples
Section titled “Code Examples”// Blink state: true when cursor visible.private boolean blinkStatus = true;
// Controls cursor blinking: true means the cursor is visible,// false means the cursor is not displayed.private boolean cursorVisible = true;- What it demonstrates: “status” says nothing about what true means, and “blink” doesn’t say what blinks.
cursorVisibleis a predicate, so true and false are obvious. Why the cursor blinks is less important, so it moves to the comment.
The Go style debate. Gerrand argues that “long names obscure what the code does” and prefers the first version below:
func RuneCount(b []byte) int { i, n := 0, 0 for i < len(b) { if b[i] < RuneSelf { i++ } else { _, size := DecodeRune(b[i:]) i += size } n++ } return n}The second version uses buffer, index, and count in place of b, i, and n. The author finds it no harder to read, and count saved him from working out what n meant. He accepts n if the whole system uses it only for counts.
Worked Example
Section titled “Worked Example”The Sprite file system bug, “The most challenging bug I ever fixed.”
- Symptom. In the Sprite distributed operating system (late 1980s to early 1990s), files occasionally lost data: one block suddenly became all zeroes though nobody had modified the file. It happened rarely, and several graduate students gave up on it.
- The hunt. The author, who considers “any unsolved bug to be an intolerable personal insult,” spent six months on it.
- Cause. The file system used the name
blockfor two things: a physical block number on disk and a logical block number within a file. In one place, ablockvariable holding a logical block number was used where a physical one was needed, so an unrelated disk block was overwritten with zeroes. - Why reviewers missed it. Several people read the faulty code. Seeing
blockused as a physical block number, they assumed it held one. Only instrumentation that narrowed the corruption to one statement got the author past “the mental block created by the name.” - The fix in naming terms. Distinct names such as
fileBlockanddiskBlockwould almost certainly have prevented the bug, since a programmer would knowfileBlockcouldn’t be used there. This is a violation of the third consistency requirement: one name covered two different behaviors.
Key Takeaways
Section titled “Key Takeaways”- Test each name in isolation: could a reader guess what it refers to?
- Prefer precise names, but not names narrower than the entity’s real role.
- Pick one name per recurring concept and use it everywhere, for that concept only.
- Use predicates for booleans, and longer names for variables used far from their declaration.
- If a good name won’t come, rethink the variable or method’s design.
Connects To
Section titled “Connects To”- Ch 2: vague names are a form of obscurity; complexity is incremental.
- Ch 3: good names are an investment.
- Ch 13: names and comments share the work of precision.
- Ch 17: consistent naming is one form of consistency.
- Ch 18: good names make code obvious.