How should a name's length and specificity relate to the size of its scope, and what makes a name "searchable" and "pronounceable"?
answer
- long scope → long name; short scope → short name
- distance from declaration drives descriptiveness
- functions invert it: public longer, private helper shorter
- MAX_RETRIES is searchable; 3 is not
- genymdhms can't be said in a standup
basics
~20 sThe further a name travels from its declaration, the more descriptive it must be. i is fine in a three-line loop; a module-level export needs a full phrase. Searchable means findable by text search — MAX_RETRIES can be found, 3 cannot. Pronounceable means you can say it aloud.
solid answer
~50 sTwo complementary heuristics. **Scope-length correlation:** short names for short-lived, narrow scopes (`i`, `n`, `e` in a small block), long descriptive names for anything visible across a file, module or API. Equivalently (the Go/Kernighan formulation): the greater the distance between declaration and use, the longer the name should be. Function *names* invert this — a short private helper called from three lines away can be terse; a widely called public function needs a precise verb phrase. **Searchability:** a name should be findable with one search. Single letters and bare literals are not — `MAX_RETRIES` is greppable, `3` returns thousands of hits — so any value you might one day need to locate deserves a name. **Pronounceability:** if the team cannot say `genymdhms` out loud, it cannot be discussed in review, standup, or at a whiteboard; `generationTimestamp` can. These are readability heuristics, not laws — a very long name in a tight inner loop hurts more than it helps.
code
pseudocode · 14 lines// narrow scope: short names are correct
for (i = 0; i < values.length; i++) sum += values[i]
// wide scope: full, searchable, pronounceable names
const DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000
function resolveShippingAddressForOrder(order) { ... }
// unsearchable + unpronounceable
if (retries > 3) { ... } // searching "3" -> thousands of hits
genymdhms = now() // cannot be said out loud
// repaired
if (retries > MAX_RETRIES) { ... }
generationTimestamp = now()go deeper
State the basic rule with examples: i in a tiny loop is fine, module-level names need full phrases; named constants are searchable, literals are not.
Add the distance-from-declaration formulation, pronounceability and how it affects review conversations, and the acceptable-abbreviation test.
Note that function names invert the variable rule, that searchability matters most where tooling cannot resolve symbols (literals, config keys, metrics, cross-language references), and that a name needing six words is design feedback.
Treat these as team-level conventions worth encoding in a style guide and linter, and connect long-name pressure to module decomposition — the durable fix is usually smaller scopes, not longer identifiers.
## Heuristic 1 — name length should track scope A name's job is to survive the distance between where it is declared and where it is read. - **Tiny scope, tiny name.** In `for (i = 0; i < n; i++) sum += values[i]`, `i` and `n` are near-universal conventions and the declaration is two lines above the use. Renaming them to `currentArrayIndexPosition` and `totalNumberOfElements` makes the loop *harder* to read: the signal-to-character ratio drops and the actual logic is pushed off the line. - **Wide scope, full name.** A module-level constant, an exported function, a public field, or a class name is read by people who will never see its declaration. It gets a complete, unambiguous phrase: `DEFAULT_CONNECTION_TIMEOUT_MILLIS`, not `TMO`. - **The Go / Kernighan–Pike formulation** says the same thing more precisely: *the greater the distance between a name's declaration and its uses, the longer the name should be.* That phrasing handles the case of a long function where a variable declared at the top is used 80 lines later — nominally the same scope, but a long distance, so it needs a fuller name. (It also hints at the real fix: shorten the function.) - **Functions invert the rule.** Robert C. Martin's observation is that *function* names behave oppositely to variable names: a small private helper used right next to its definition can be short, while a widely-called public API function needs a long, precise verb phrase. The unifying principle is the same — descriptiveness must scale with how far the reader is from the definition. ## Heuristic 2 — searchability A name is **searchable** when one text search (or one IDE "find usages") locates every occurrence of the concept and nothing else. - **Bare literals are unsearchable.** You cannot search for `7` and find the week-length assumption. `DAYS_PER_WEEK` you can. This is the strongest practical argument for named constants, distinct from readability: it makes a future change *possible to scope*. - **Single letters are unsearchable.** Searching for `e` matches every word containing the letter. This is the real cost of one-letter names in a wide scope. - **Common English words are weakly searchable.** A class named `Data` or a method named `process` cannot be found without noise. Distinctive names are cheaper to maintain. - **Split identifiers hurt search too.** If a name is assembled at runtime (string concatenation for a metric key, a reflective lookup, a generated field name), no search finds the usage. Prefer literal, whole identifiers wherever tooling has to see them. Note the interaction with symbolic tooling: IDE "find usages" is symbol-aware and far better than text search, so searchability matters most for things tooling cannot resolve — literals, strings, config keys, log fields, metric names, and cross-language boundaries (a column name referenced from SQL, a field name referenced from a template). ## Heuristic 3 — pronounceability Programming is a social activity: names are spoken aloud in reviews, pairing, standups, incident calls, and at whiteboards. `genymdhms` (generation date, year, month, day, hour, minute, second) forces every conversation into spelling. `generationTimestamp` can simply be said. Practical consequences: - **Avoid vowel-dropping and invented contractions** — `cstmr`, `msgQ`, `hndlrFctry`. - **Well-known abbreviations are fine** — `id`, `url`, `http`, `db`, `io`, `xml`, and domain acronyms your team says out loud daily. The test is whether a new team member would recognise it in week one. - **Casing of acronyms** should follow one convention (`HttpClient` or `HTTPClient`, not both), because inconsistency breaks both reading and prefix search. ## Trade-offs and edge cases - **These heuristics can conflict.** Searchability pushes toward long distinctive names; readability in a tight loop pushes toward short ones. Resolve by scope: the loop index stays `i`; the constant becomes `MAX_RETRIES`. - **Mathematical and domain-conventional short names are legitimate.** In a matrix routine, `i`, `j`, `m`, `n` are the domain vocabulary; renaming them to prose makes the algorithm unrecognisable to anyone who knows the maths. - **Long names can hide a design problem.** If a name needs six words to be unambiguous (`processUserOrderPaymentAndNotify`), the *thing* is probably doing too much. The naming difficulty is design feedback: split it. - **Consistency of length within a scope matters** — mixing `i` with `currentIndex` for two loops in one function is worse than either choice applied consistently. ## In review A useful review question is: *how far from here is this declared, and could I have guessed what it means from the name alone at that distance?* If the answer is no, lengthen the name — or shorten the distance by extracting a smaller function, which is often the better fix.
- A reviewer insists a loop index be renamed from `i` to `currentArrayIndexPosition`. How do you respond?Push back on the grounds that descriptiveness should scale with scope and with the distance between declaration and use. In a three-line loop `i` is a universal convention; the longer name adds characters without information and pushes the actual logic off the line. If the loop body were 60 lines, the right fix is to extract a function, not to lengthen the index name.
- Why does searchability argue for named constants beyond mere readability?Because it makes future change *scopable*. You cannot find every place that assumes a seven-day week by searching for `7`, so a change to that assumption is unbounded and risky. `DAYS_PER_WEEK` turns the same change into a finite, reviewable set of call sites.
- When is a name being hard to choose a signal about design rather than about naming?When the only accurate name is a conjunction — `processOrderAndSendEmailAndUpdateInventory` — or when no noun fits and you fall back on `Manager`/`Helper`. Both mean the unit has more than one responsibility; the fix is to split it until each piece has a short, honest name.
A name is a road sign. Inside your own kitchen a note saying "salt" is enough; a motorway sign read at speed by strangers needs the full destination, spelled out.
saying these in an interview costs you the question
- "Never use single-letter names" — applied absolutely, ignoring loop indices and mathematical conventions.
- "Longer is always clearer" — padding names with words that add no information.
- Assuming searchability is irrelevant because the IDE resolves symbols — it does not resolve literals, config keys, metric names, or cross-language references.
- Building identifiers by string concatenation for metrics or reflection, then wondering why usages cannot be found.
- Solving a long-lived variable in a 200-line function by lengthening its name instead of extracting functions.