
I once spent forty minutes naming a function. The function was four lines long.
My teammate watched me rename it three times in the PR and finally asked, gently, if I was okay. I was. I just knew something he'd later agree with: that name would be read a thousand times and written once, and I was the only person who'd ever get to choose it.
Naming things is the hardest part of coding. Not the algorithms. The names. Here's why, and how I finally got less bad at it.
Naming is hard because a good name is a compressed explanation — it has to carry intent, scope, and contract in a few characters, to a reader you'll never meet, who has none of the context you have right now. It's not a typing problem; it's a thinking problem. If you can't name something cleanly, you usually don't understand it cleanly yet. The name is the test.
You know the joke: there are only two hard things in computer science — cache invalidation, naming things, and off-by-one errors.
We laugh and move on. But naming earned its spot on that list, and we treat it like the throwaway.
A name is the only interface most people will ever have with your code. Most developers will never read the body of calculateUserDiscount. They'll read the name, trust it, and move on. If the name lies — if it actually calculates and applies the discount, mutating state as a side effect — you've planted a small bomb in everyone's mental model.
That's the real weight. A name is a promise you're making to every future reader, including yourself at 2am during an incident. It's one of those quiet craft skills that separate working code from senior-level code — the same theme I dig into in the brutal truth about becoming a senior developer.
Photo by Priscilla Du Preez on Unsplash
Here's the thing that finally made it click for me. A good name does the job of a comment, but it can never go stale, and it gets read every single time the symbol is used.
// the comment most people would write
// gets active users who haven't logged in for 30 days
const u = getUsers();
// the name doing the comment's job
const dormantActiveUsers = findActiveUsersIdleFor(30);
The second one needs no comment. The name is the documentation, and it's documentation that can't drift away from the truth, because it lives right on the thing it describes.
That's also why it's so hard. You're not labeling a box. You're compressing a whole explanation — what it is, what it returns, what it promises not to do — into a phrase a tired human can parse instantly. Compression is hard. Lossless compression that survives six months and three teammates is brutal.
This is the lesson that changed how I work. When I can't name something, it's almost never a vocabulary problem. It's a comprehension problem.
If a function resists a clean name, it's usually because it does two things. validateAndSave. processData. handleStuff. The word "and" in a function name is a confession. The vague noun "data" is a shrug.
The struggle to name it is the design feedback. The code is telling you the boundaries are wrong.
So now, when a name fights me, I stop fighting the name and fix the code:
validateAndSave becomes two functions, validate and save, and suddenly both are easy to name.processData was hiding three responsibilities; split out, they're parseCsvRows, normalizeAddresses, dedupeContacts.handleStuff had no business existing.The name didn't get hard by accident. It got hard because the code was muddy. The name was just the messenger. This is the same instinct that makes a good code review rule change a whole team: the friction is feedback, not an obstacle. Even MDN Web Docs leans on this — its readability guidance treats naming as a core part of writing maintainable code, not a cosmetic afterthought.
If you can't name it, you don't yet understand it. The naming pain is a design review for free.
After enough forty-minute naming sessions, I stopped relying on inspiration and started using rules. These are the ones that earn their keep.
1. Booleans read like questions. isActive, hasPermission, canRetry, shouldRefresh. If you can put it after "is the user…" and it makes sense, you've named it well.
2. Functions are verbs, values are nouns. user holds a user. getUser fetches one. Mixing these is how you end up with a "config" that's secretly a function.
3. Match the name to the abstraction level. Low-level code can say buffer and offset. Business code should say invoice and customer, never obj and data. The name should sound like the layer it lives in.
4. Length should match scope. A loop index living for three lines can be i. A value that lives across a 200-line module needs to earn its keep with a full, descriptive name. Tiny scope, tiny name. Huge scope, generous name.
5. Avoid the noise words. Manager, Helper, Util, Data, Info, Processor. They feel like they mean something and mean nothing. A UserManager that does nothing a User couldn't is just a place where responsibilities go to hide.
6. Name the concept, not the type. A list of users is users, not userArray or userList. The reader can see it's a list; what they can't see is that it's the active users, or the invited ones. Spend your characters on the meaning the type can't carry, never on repeating the type itself.
7. Be consistent across the codebase. If you fetch with getUser in one place, don't fetchAccount in another for the same idea. A reader builds a vocabulary from your code, and every synonym you introduce is a tax on that vocabulary. Pick one word per concept and hold the line everywhere.
| Weak name | Why it's weak | Stronger name |
|---|---|---|
data | What data? | pendingOrders |
handleClick | Handle it how? | submitCheckout |
flag | Flag for what? | isEmailVerified |
UserHelper | Helper is a non-word | UserMailer |
temp | Temporary forever | unsavedDraft |
Photo by Ilya Pavlov on Unsplash
Here's the part I wish someone had told me earlier: you don't have to get the name perfect the first time.
Modern editors and developer tools rename a symbol across a whole codebase in seconds. The cost of a rename is near zero. The cost of living with a lie for a year is enormous.
So the move is: name it good enough to keep moving, and rename it the instant a better name reveals itself. Naming isn't a one-shot ceremony. It's a thing you tidy continuously, like making your bed.
The only sin is defending a bad name because you've gotten attached. Names are cheap to change and expensive to misunderstand. Optimize accordingly.
I keep a tiny ritual for this: whenever a name confuses me — the person who wrote it — I rename it on the spot, before I lose the context. If present-me is confused, future-me and every teammate are doomed. The confusion is the cheapest signal I'll ever get, and it expires fast. Catching it in the moment costs seconds. Discovering it during a 2am incident costs everyone.
There's a deeper payoff too. The discipline of naming well leaks backward into your design. When you commit to giving every function an honest, single-responsibility name, you stop letting functions quietly grow three responsibilities — because you'd have to name the mess, and you can't. The naming standard becomes a design standard. You write cleaner code not because you decided to, but because the bad designs no longer have anywhere to hide.
Q: Should I use short names or long descriptive ones? Match length to scope and to how far the reader is from the definition. Short for tiny, local, obvious things. Long for anything that travels. A name's job is to spare the reader a trip to the definition — pay whatever characters that costs.
Q: Are naming conventions like camelCase vs snake_case worth arguing about? No. Pick whatever your language and team already use and never bring it up again. Consistency beats correctness here. The quality of names matters far more than their casing.
Q: Is it okay to use abbreviations?
Only ones your whole domain already shares — id, url, http. Invented abbreviations like usrMgr save four characters and cost every reader a guess. Bad trade.
Q: How do I name something genuinely new with no precedent? Describe what it does in plain words to a rubber duck, then compress that sentence. Often the verb and noun you naturally reach for are the name. If even the sentence is fuzzy, your design is fuzzy — go back a step.
Q: Should AI tools name things for me? They're a great first draft and a good thesaurus. But they don't have your domain context, so treat their suggestions as a starting point, not a verdict. The understanding still has to be yours.
Naming feels like a small thing, a cosmetic flourish you do after the "real" work. It isn't. It's the place where your understanding of the problem gets written down in the most-read, longest-lived form it'll ever take.
Code tells the computer what to do. Names tell the humans what you meant. The second audience is the one that maintains it.
Get good at naming and a strange thing happens: your designs get cleaner, because you can no longer hide a muddy idea behind a vague label. The name won't let you.
If naming as a design tool resonates, try treating your next confusing name as a free design review — and stick around for more of these craft notes on leveling up as an engineer.
So next time a name won't come — don't push through it. Stop and ask what the code is trying to tell you. What would you have to change for the perfect name to be obvious?
No following, no network, no luck. Just an unglamorous system I ran for eighteen months. Here's exactly what I did.

I went from 200 to 11,000 subscribers without hiring anyone. AI didn't write my newsletter — it did everything around it.

I chased big, audacious goals for years and burned out every time. Then I built my whole life around wins so small they felt like cheating.

Comments
Sign in to join the conversation
No comments yet. Be the first to share your thoughts!