It sounds absurd that naming variables and functions is considered one of the hard parts of programming. Yet experienced developers agree it genuinely is, and they treat it seriously. A name is not decoration; it is the primary way future readers — including your future self — understand what code does without reading every line.
The difficulty is real because a good name requires real understanding.
A name is understanding, compressed
To name something well, you must first understand exactly what it is and does — its single, precise responsibility. Vague or misleading names are often a sign the thing itself is vague or does too much. In this way, the struggle to name something is diagnostic: if you cannot name it cleanly, the design may be muddled.
The best names capture intent, not mechanism — what something is for, rather than how it happens to work today.
The cost of bad names
Poor names impose a tax on every future reader. A misleading name is worse than a vague one, because it actively sends people in the wrong direction. Code is read far more often than it is written, so a name that saves a few seconds now but costs every future reader minutes of confusion is a bad trade repeated endlessly.
Abbreviations that made sense to the author, single-letter names outside tiny scopes, and names that no longer match what the code does are all quiet sources of friction.
Practical habits
Favour names that reveal intent and can be read aloud; keep them honest by renaming when behaviour changes; and let the difficulty of naming prompt you to reconsider whether a function or variable is doing too much. Consistency across a codebase matters too — the same concept should wear the same name everywhere.
Naming is hard because it forces clarity of thought. That is exactly why the effort pays off: a well-named codebase is one that explains itself.
A name is a compression of a decision, and compression loses information by design
Every name a developer chooses stands in for a much larger, more detailed understanding of what a piece of code actually does, why it exists, and what its boundaries are — and the entire difficulty of naming comes from the fact that compression is lossy by nature, so a name inevitably leaves out some of that fuller understanding, and the skill is choosing which details to compress away and which ones the name absolutely must preserve. A name that tries to capture too much becomes unreadably long; one that compresses too aggressively loses the specific detail a future reader most needed, and there is no formula that resolves this trade-off automatically, which is a large part of why naming resists being reduced to a simple, mechanical rule.
Why a bad name costs time repeatedly, while a bad implementation costs time once
A subtly wrong implementation typically gets discovered and fixed once, at which point its cost is paid and it stops recurring, but a misleading name keeps extracting a small tax from every single person who reads it afterward, for as long as the name remains unchanged — each reader has to notice the mismatch between what the name suggests and what the code actually does, work around that confusion, and move on, and multiplied across every future reader over the code's entire lifetime, a persistently bad name can end up costing considerably more total time than most implementation bugs ever do, precisely because implementation bugs get fixed and bad names are so often left exactly as originally written.
Why naming is genuinely a design activity, not merely a labeling one
Struggling to find a good name for something is frequently a signal about the thing itself rather than about vocabulary — a function that is hard to name well is very often a function trying to do more than one coherent job at once, and the naming struggle is an early warning that the underlying design has not yet settled into a single, clear responsibility. Experienced developers learn to treat a difficult naming decision as a prompt to reconsider the design itself, splitting an awkwardly-named function into two well-named smaller ones, rather than treating the difficulty as purely a vocabulary problem to be solved with a thesaurus.
Why renaming is cheap in tools and still expensive in practice
Modern editors can mechanically rename every reference to a symbol across an entire codebase in seconds, which makes the pure text-substitution cost of renaming close to zero — and yet renaming still carries real cost in practice, because a rename touches every file that references the symbol, which means every one of those files shows up in the diff of what was otherwise meant to be an unrelated change, complicating code review and version history for reasons that have nothing to do with the rename's actual merit. This gap between mechanically cheap and practically costly is exactly why getting a name closer to right the first time is worth real deliberate effort, rather than assuming a rename can always cheaply fix it later without any real downside.
Why a name chosen under time pressure rarely gets revisited later
A placeholder name chosen quickly while focused on getting a feature working — `data`, `temp`, `handleThing` — has an unfortunate tendency to survive far longer than anyone intended, since renaming later requires noticing it is still there and deciding it is worth the interruption, and both of those are easy to skip once the code is already working and attention has moved elsewhere; this is exactly why building the habit of pausing to choose a real name even under pressure, rather than deferring it to a cleanup pass that may never actually happen, matters more than it initially seems.
Why naming gets harder, not easier, as a codebase grows
A five-file project has relatively little competition for any given name, but a codebase with thousands of files accumulates many existing uses of similar concepts, which means a genuinely good name for a new piece of code increasingly has to also avoid colliding, in meaning if not in literal syntax, with something similar already named slightly differently elsewhere — this growing difficulty is not a sign of doing anything wrong, it is a direct, expected consequence of a codebase's vocabulary filling up over time, and it is part of why an established, consistent naming convention becomes increasingly valuable precisely as a project grows larger.
Why a team glossary of agreed terms reduces the burden on any individual
Much of the difficulty in naming comes from having to decide, alone, in the moment, what the right term for a concept is — a maintained glossary of a team's core domain terms, agreed on collectively rather than reinvented by whoever happens to be writing a given piece of code that day, removes a meaningful share of that burden by turning many naming decisions from an individual judgment call into a simple lookup against an already-settled team convention.
Why a name review deserves its own moment during code review
Naming quality is easy to skip past during a code review focused primarily on correctness and logic, and yet a reviewer who deliberately pauses to ask 'does this name actually convey what this does' is applying exactly the same scrutiny to naming that the rest of this article argues naming deserves — building this specific question into a team's review habits, rather than treating naming as a purely personal, unreviewed choice, extends the same discipline discussed throughout this article from an individual practice into a shared, team-level one.
Why naming difficulty is sometimes a sign the abstraction itself is missing
Occasionally, no name feels quite right not because of a shortage of vocabulary but because the concept being named has never actually been made explicit as its own distinct thing in the codebase before — struggling to name 'the logic that decides whether a user can perform this action' is often a sign that this decision deserves to be pulled out into its own clearly named function or class in the first place, rather than remaining implicit, scattered across several places that each partially implement it without any of them being the one place actually responsible for it.
Why explaining a name choice out loud to someone else is a genuinely useful test
Trying to justify a chosen name to a colleague, even briefly and informally, frequently exposes a weakness in the name that silent, solitary consideration missed — stumbling to explain why something is called what it is called is a reliable, practical signal that the name itself is not doing its job, and this quick, low-cost check is worth building as a habit specifically because it catches problems that reviewing the name alone, without narrating the reasoning behind it, tends to miss.
Why naming a boundary matters more than naming what is on either side of it
The names attached to an interface, an API endpoint, or a module boundary carry outsized importance relative to purely internal, private names, since a boundary name is a promise made to every piece of code that depends on it, while an internal name only has to make sense to the code immediately around it — spending disproportionately more naming effort on boundaries than on internal implementation details is a reasonable, deliberate allocation of the genuinely limited attention naming can realistically receive.
Why the effort spent naming something well is rarely visible to anyone but its beneficiaries
Nobody praises a pull request for having particularly excellent variable names, and a genuinely well-named codebase tends to simply feel unremarkable and easy to work in, rather than earning explicit credit for it — this invisibility is exactly why naming discipline is easy to under-invest in relative to more visible engineering work, even though its cumulative payoff, spread across every future reader, is real and substantial.
Why a short cooling-off period before finalizing a hard name choice helps
A name that feels perfect in the middle of writing a function sometimes reads as subtly off an hour or a day later, once the immediate context that made it feel obvious has faded — deliberately revisiting a genuinely difficult naming decision after a short break, rather than locking it in the moment it was first typed, catches a real fraction of names that would otherwise have stuck around despite not quite fitting.
Why naming a temporary or throwaway variable still deserves a moment's thought
It is tempting to reason that a variable only meant to live for a few lines does not deserve the same naming care as a long-lived one, but a throwaway variable named poorly can still mislead the very next line of code reading it, and the cost of choosing a slightly better name over a lazy one is the same trivial few extra seconds regardless of how long the variable is expected to live.