Skip to content

Chapter 17: Consistency

In a consistent system, similar things are done in similar ways and dissimilar things in different ways. Consistency gives “cognitive leverage”: what you learn in one place applies everywhere, and assumptions based on familiar patterns are safe. Keep it by documenting conventions, enforcing them with tools and reviews, and following local practice.

  • Where consistency applies:
    • Names (ch14).
    • Coding style: style guides for indentation, brace placement, declaration order, naming, commenting, and dangerous language features.
    • Interfaces: an interface with multiple implementations; learn one and the rest are easier.
    • Design patterns: accepted solutions such as model-view-controller, which make code faster to write, more likely to work, and more obvious.
    • Invariants: properties that are always true, such as every stored line ending with a newline. They reduce special cases and make reasoning easier.
  • Ensuring consistency:
    1. Document: list the most important conventions in a conspicuous place, such as the project wiki. Ask newcomers to read it and others to review it now and then; consider starting from a published style guide. Document localized conventions, such as invariants, at an appropriate place in the code. “If you don’t write the conventions down, it’s unlikely that other people will follow them.”
    2. Enforce: write a checker tool and block commits that fail it. This works best for low-level syntactic conventions. Code reviews also enforce and teach conventions: “The more nit-picky that code reviewers are, the more quickly everyone on the team will learn the conventions.”
    3. When in Rome …: “the most important convention of all.” In a new file, look at how the existing code is structured (public before private? alphabetical methods? camel case or snake case?) and follow anything that might be a convention. When making a design decision, find a similar decision elsewhere in the project and copy its approach.
    4. Don’t change existing conventions: “Having a ‘better idea’ is not a sufficient excuse to introduce inconsistencies.” Change one only if both answers are yes: (a) Do you have significant new information that wasn’t available when the convention was set? (b) Is the new approach so much better that it’s worth updating all old uses? If your organization agrees, convert everything, so no sign of the old convention remains.
  • Cognitive leverage: knowledge from one place applies to others that use the same approach.
  • False familiarity: in an inconsistent system, two situations look the same but differ, and developers make wrong assumptions.
  • Invariant: “a property of a variable or structure that is always true.”
  • Pre-commit check: an automated script that blocks commits violating a convention.
  • “the value of consistency over inconsistency is almost always greater than the value of one approach over another.”
  • Consistency only helps if developers can trust that “if it looks like an x, it really is an x.” So dissimilar things must look different.
  • Consistency is an investment: deciding conventions, writing checkers, looking for examples to copy, and reviewing code all take work, and the payback is code that is more obvious.
  • Newcomers inventing conflicting conventions because they don’t know the existing ones.
  • Trying to “improve” a convention in one place, which leaves two conventions.
  • Taking it too far: forcing dissimilar things into one approach, such as one variable name for different things or a design pattern that doesn’t fit the task.
  • Relying on memory alone: even good documentation won’t be remembered without enforcement.

Line endings in a mixed Unix and Windows team.

  1. Problem. Unix developers’ files ended lines with newlines; Windows developers’ tools used carriage-return plus newline. A small edit on one system sometimes made the editor rewrite every line terminator, so the diff showed every line as changed and the real changes were hard to find.
  2. First attempt: a documented convention. The team decided files should contain newlines only. But they couldn’t make every developer’s every tool follow it, and each new developer caused “a rash of line termination problems.”
  3. Fix: enforce with a tool. A short script runs automatically before each commit. It checks every modified file and aborts the commit if any contains carriage returns. It can also be run by hand to repair files, replacing carriage-return/newline pairs with newlines.
  4. Result. The problems disappeared at once, and the script also trained new developers.
  1. Do similar things the same way and different things differently.
  2. Write conventions down where people will see them.
  3. Enforce syntactic conventions with automated pre-commit checks.
  4. Be nit-picky about conventions in code review.
  5. Copy the conventions and design decisions already used around you.
  6. Change a convention only with new information and a plan to convert all old uses.
  • Ch 2: inconsistency is a source of obscurity and cognitive load.
  • Ch 7: multiple implementations of one interface.
  • Ch 14: consistent naming.
  • Ch 18: consistency is one of the main ways to make code obvious.
  • Ch 19: design patterns and their over-application.