A good name does more work than it appears to.

When you name a variable data, you’ve said nothing. When you name it unvalidatedUserInput, you’ve created a constraint. Every time someone reads that name, they get a reminder that this value has not been checked. The name carries the intent, and the intent travels with the code.

This is what I mean by load-bearing. A good name holds up part of the understanding, so the surrounding code doesn’t have to. It reduces the amount of comment and documentation that needs to exist, because the thing is already saying what it is.

The inverse is also true. A misleading name is a trap. isComplete that sometimes means “attempted” and sometimes means “succeeded” is worse than no name at all, because it actively misdirects.


Three questions I ask about names now:

  1. Does it describe what it is, or what it’s called? userList vs eligibleRecipients โ€” one is a type, the other is a meaning.
  2. Would I have to explain it out loud? If so, the explanation should be in the name.
  3. Does it age well? Names written in a hurry often reflect the implementation, not the concept. When the implementation changes, the name lies.

Naming is thinking. The struggle to name something clearly is often the struggle to understand it clearly. Which means if a name is hard to find, the concept might not be solid yet.