Naming things
A name is the interface every reader touches and the one thing the compiler
never checks for truth. Names are read far more often than written, so a vague
one taxes every future reader to reconstruct the meaning the author already
held.
Method
- Size the name to the scope it lives in. A three-line loop index can be
i; a value passed across functions or modules needs a self-explaining
phrase like unacknowledgedEventCount. Wider reach and less shared context
demand a longer name.
- Spell words out; refuse invented abbreviations. Write
request,
message, or the project's already-established short form, never a one-off
req2, msg, or flg. Each abbreviation trades one saved keystroke for a
lookup on every future read.
- Name the concept, not the container or type. Prefer
dueInvoices to
invoiceArray or data. The type already appears in the declaration; spend
the name on the meaning the type cannot express.
- Make booleans read as a claim at the branch.
isActive, hasAccess,
and shouldRetry read cleanly in if (hasAccess). Avoid negatives like
notReady that force if (!notReady), a double negative readers misparse.
- Keep one word per concept across the codebase. If you
fetch in one
module, do not get, load, and retrieve the same thing elsewhere. Grep
for the existing verb before coining a new one.
- Rename the moment the code reveals the true concept. The stand-in name
flag that turned out to gate exports should become exportsUnlocked now,
while the change is one commit, not after ten call sites depend on the vague
name.
- Cost the rename before you make it wide. A function-local name is free
to change; an exported symbol, a serialized field, or a database column
ripples to callers, stored data, and other repos. For those, ship the new
name beside the old, deprecate, then remove.
Litmus tests
- Can a reader who lands mid-file guess what the name holds without scrolling
to its definition?
- Does every abbreviation in the diff already appear elsewhere in the project,
or did you just invent it?
- Read each boolean aloud inside its
if: does it state a true or false claim,
or pose a riddle?
Boundaries
Established domain terms and house conventions outrank these rules: match the
codebase's accent even where you would choose otherwise. Some short names are
idiomatic (i, err, id), and lengthening them for a rule's sake only adds
noise. Where a linter already fixes casing and prefixes, follow it.
1---2name: naming-things3description: Choose names that carry meaning so readers grasp intent without chasing definitions. Use when naming variables, functions, types, or files, or when a name reads as vague.4---56# Naming things78A name is the interface every reader touches and the one thing the compiler9never checks for truth. Names are read far more often than written, so a vague10one taxes every future reader to reconstruct the meaning the author already11held.1213## Method14151. **Size the name to the scope it lives in.** A three-line loop index can be16 `i`; a value passed across functions or modules needs a self-explaining17 phrase like `unacknowledgedEventCount`. Wider reach and less shared context18 demand a longer name.192. **Spell words out; refuse invented abbreviations.** Write `request`,20 `message`, or the project's already-established short form, never a one-off21 `req2`, `msg`, or `flg`. Each abbreviation trades one saved keystroke for a22 lookup on every future read.233. **Name the concept, not the container or type.** Prefer `dueInvoices` to24 `invoiceArray` or `data`. The type already appears in the declaration; spend25 the name on the meaning the type cannot express.264. **Make booleans read as a claim at the branch.** `isActive`, `hasAccess`,27 and `shouldRetry` read cleanly in `if (hasAccess)`. Avoid negatives like28 `notReady` that force `if (!notReady)`, a double negative readers misparse.295. **Keep one word per concept across the codebase.** If you `fetch` in one30 module, do not `get`, `load`, and `retrieve` the same thing elsewhere. Grep31 for the existing verb before coining a new one.326. **Rename the moment the code reveals the true concept.** The stand-in name33 `flag` that turned out to gate exports should become `exportsUnlocked` now,34 while the change is one commit, not after ten call sites depend on the vague35 name.367. **Cost the rename before you make it wide.** A function-local name is free37 to change; an exported symbol, a serialized field, or a database column38 ripples to callers, stored data, and other repos. For those, ship the new39 name beside the old, deprecate, then remove.4041## Litmus tests4243- Can a reader who lands mid-file guess what the name holds without scrolling44 to its definition?45- Does every abbreviation in the diff already appear elsewhere in the project,46 or did you just invent it?47- Read each boolean aloud inside its `if`: does it state a true or false claim,48 or pose a riddle?4950## Boundaries5152Established domain terms and house conventions outrank these rules: match the53codebase's accent even where you would choose otherwise. Some short names are54idiomatic (`i`, `err`, `id`), and lengthening them for a rule's sake only adds55noise. Where a linter already fixes casing and prefixes, follow it.