tech, developers, and the code underneath

issue 157· essay·

Naming things: the actual rules

It is one of the two hard problems and it is treated as a matter of taste. It isn't. Here are the rules that hold.

Naming gets treated as bikeshedding — a matter of taste that reasonable people disagree about and that is not worth arguing over.

It is not taste. A name is the compression of everything the reader needs to know about a thing, and a bad one costs every future reader time. There are rules, they are learnable, and most codebases violate them consistently.

the rules#

1. Length should be proportional to scope.

A loop index used on the next line can be i. A module-level constant read by forty files needs a full sentence of a name.

python
for i, x in enumerate(items):     # fine, two lines of scope
    ...

MAX_UPLOAD_SIZE_BYTES = 10 * 1024 * 1024   # not MAX_SIZE

The inverse error is as common: for currentItemIndex in ... in a three-line loop is noise.

2. Name what it is, not what it does.

getUserData and fetchUserData and loadUserData all mean the same thing, and the differences imply distinctions you probably do not intend. Pick a convention — get for cheap and local, fetch for network, load for disk — and hold it.

3. Booleans read as assertions.

isValid, hasPermission, canRetry, shouldRefresh. Never a negative: isNotReady produces if not isNotReady, which no human parses correctly on the first read.

4. No abbreviations except universal ones.

id, url, http, db, max, min are fine. usr, cfg, mgr, svc, impl are not. You saved four characters and cost every reader a translation step, forever.

The test: would a competent engineer who has never seen this codebase know what it means? If they would have to check, spell it out.

5. Units in the name.

timeout is a bug waiting to happen. timeoutMs is not. Same for sizeBytes, distanceMeters, priceCents. Every mixed-unit bug I have ever debugged was preceded by a name that did not say the unit.

This is the highest-value rule on this list and it is the most ignored.

6. Avoid meaningless suffixes.

UserManager, DataProcessor, RequestHandler, ThingService. What does a manager do? Nobody knows, which is why the class has grown to nine hundred lines — there is no name-based pressure to keep it focused.

If you cannot name a class without Manager or Helper or Util, it is probably doing several unrelated things and the naming problem is telling you so.

7. Symmetry.

open/close, not open/dispose. start/stop, not start/end. add/remove, not add/delete. A reader who learns half your vocabulary should be able to guess the other half.

8. The name should not lie.

The worst possible name is one that was accurate and is not anymore. validateEmail that also normalizes and saves. getUser that creates the user if absent. These are worse than no name, because the reader trusts them and does not check.

When a function's behavior changes, changing its name is part of the work.

the tell#

Here is the diagnostic that turns naming from taste into information:

If you cannot name it clearly, the thing is probably wrong.

  • A function you cannot name without "and" is doing two things.
  • A variable you cannot name specifically holds something too vague to be useful.
  • A class you can only name Manager has no coherent responsibility.
  • A boolean parameter you cannot name is a sign the function should be two functions.

The naming difficulty is a signal about the design, and it arrives at the exact moment when the design is cheapest to change.

the domain language rule#

Use the words your users and your business use, exactly, and use them consistently.

If the business says "subscription," do not call it plan in one module and membership in another. Every translation between the domain language and the code is a place where a misunderstanding hides, and there will be several.

The corollary: if the business uses one word for two things, or two words for one thing, you have found a domain modeling problem that predates your code. That is worth surfacing.

on renaming#

Modern tooling makes renaming safe and cheap in a typed language. Do it. A name that is 20% better, applied across a module, is a real and permanent improvement to every future reading.

The objection is git blame noise, which is a real cost and a small one. git log --follow and blame-ignore files handle most of it.

the one-line version#

Say what it is, include the unit, do not abbreviate, do not lie, and if you cannot name it, fix the thing rather than the name.

Dom, May 1, 2026

get README in your inbox

One dispatch, no noise. Tech and developer news, plus the occasional long piece on the craft.

subscribe →