Compilers, interpreters, and runtimes strip your variable names away. By the time your code runs in production, userAccountBalanceAfterFeeDeduction and x are functionally identical to the machine. The CPU doesn’t know or care. Memory addresses don’t have feelings.

Your teammates do. And so does the version of you that opens this file at 11pm six months from now trying to understand why the billing service is charging customers twice.

Naming is one of those skills that seems trivial until you spend a few hours inside a codebase where someone clearly didn’t think about it. Then it starts to feel like the most important thing in software.

The Cost Is Paid at Read Time, Not Write Time

When developers talk about code quality, they often focus on things that are measurable at a distance: test coverage, cyclomatic complexity, bundle size. Naming is harder to measure, so it gets less attention. But the costs of bad naming are real and they compound.

Consider a function called process(). What does it do? Unclear. You have to read the body to find out. Now imagine that function is called in thirty places across the codebase. Each callsite forces the reader to carry ambient uncertainty. Is this the same process() I saw earlier? Does it mutate state? What does it return?

Contrast that with validateAndNormalizePhoneNumber(). You know what it does before you read a single line of the implementation. You can read the callsite, understand the intent, and move on. The function name did work so the rest of the code didn’t have to.

This is the core asymmetry of naming: the cost of choosing a good name is paid once, by the writer, at the moment of creation. The cost of a bad name is paid repeatedly, by everyone who reads the code after that, often under pressure.

Diagram showing how clear naming creates navigable structure while vague naming creates ambiguity
A name isn't just a label. It's a contract between the writer and every future reader.

What Makes a Name Bad

Abbreviations are usually the first culprit. usrAcctBal saves maybe two seconds of typing and costs far more in comprehension. But length alone isn’t the issue. A name can be long and still be bad.

The more common failure mode is names that describe implementation rather than intent. A variable called filteredArray tells you what happened to the data but not what the data means. Is this a list of active users? Unpaid invoices? Flagged transactions? The word “filtered” is a verb dressed up as a noun, and it leaks implementation detail without providing meaning.

A related problem is false precision. Names like data, info, result, and value are technically specific words but carry no information in context. They’re placeholders that got promoted to production. When you see a function returning something called result, you have to go read what the function does, which defeats the purpose of naming anything in the first place.

Then there are names that were once accurate and have since drifted. A class called UserManager that started out managing users but now also handles session state, permissions, and email preferences is technically named but practically misleading. The name became a lie over time, and nobody updated it because updating names feels like optional cleanup work rather than a correctness issue. It isn’t optional. A misleading name is a bug.

Naming Is a Design Activity

Here’s what most naming guides miss: if you’re having trouble naming something, the naming is usually not the real problem. The thing itself is probably poorly defined.

A function that’s hard to name is often a function that does too much. A variable that needs a paragraph-long comment to explain it usually represents a concept that should be formalized into a type or a class. When you find yourself reaching for vague names, treat it as a signal that the abstraction underneath needs work.

This is why naming deserves to be treated as a design activity, not a cleanup task. The discipline of asking “what is this actually for” before writing the name often surfaces structural problems earlier, when they’re cheaper to fix. Good names emerge from good understanding. They’re a byproduct of thinking carefully about what your code is doing and why.

This becomes especially pointed when you consider how AI coding assistants handle naming. They’re very good at generating plausible-sounding names quickly, which can mask the fact that the abstraction underneath is fuzzy. A well-named function generated by autocomplete might look fine on first read and fall apart the moment someone needs to extend it. The name can be right while the concept is wrong. (If you’re thinking about how autocomplete shapes the way you write, this connects to something worth reading about how smarter tools affect the quality of your thinking.)

The Context Problem

Names don’t exist in isolation. They exist inside namespaces, classes, files, and functions, and the quality of a name is relative to the context it appears in.

getUser() on a UserRepository class is fine. getUser() on a class called OrderProcessor raises a question. user.getUser() is redundant. The same string of characters can be clear, misleading, or absurd depending on where it lives.

This is why naming conventions that focus on individual identifiers miss something important. What you’re really designing is a vocabulary. Within a codebase, related concepts should use related words consistently. If you’re calling it an “account” in the domain model, calling it a “profile” in the service layer and a “user” in the API response creates translation overhead that every developer on the team has to carry in their head.

Domain-driven design formalized this as the “ubiquitous language” concept: use the same terms that domain experts use, consistently, across your code, your database schema, your API contracts, and your conversations. The goal is to reduce the distance between what the business means and what the code says. When those two things use the same vocabulary, a lot of confusion simply disappears.

Names Are a Form of Documentation That Actually Gets Read

Documentation has a maintenance problem. Comments go stale. READMEs drift from reality. Wiki pages get updated once and then abandoned. But names live right next to the code they describe. When the code changes, the pressure to update the name is immediate and visible, even if developers don’t always act on it.

This makes names the most reliable form of documentation in a codebase. Not because developers are disciplined about keeping them current, but because the feedback loop is shorter. A wrong comment can survive for years. A name that’s obviously wrong gets noticed every time someone reads the line.

The investment in good naming pays compounding returns. A well-named codebase is easier to onboard into, easier to audit for security issues, easier to refactor, and easier to hand off. None of those benefits show up in a sprint velocity metric, which is part of why naming never gets prioritized the way it should. But any senior developer who’s had to maintain someone else’s codebase knows exactly what bad naming costs in human hours.

The machine doesn’t care what you name your variables. It will execute them faithfully regardless. The question is who you’re writing for, and the honest answer is that you’re writing for people, most of whom haven’t been born into your codebase yet.