How to decide when a comment should be a name.

•

•

If You Must Explain It, Rename It

I was staring at a screen of nested ternary operators at 2:14 AM during a deployment failure at my old logistics firm, and I realized I wasn’t actually reading code anymore; I was translating a foreign language. I had a block of logic that was “explained” by a three-line comment sitting right above it, which is the ultimate red flag. Most people try to solve this by quoting some “Clean Code” chapter about abstraction, but that’s usually just more noise. The real question isn’t about following a style guide; it’s about how to decide when a comment should be a name so that the next person—which is usually me, six months later—doesn’t have to perform mental gymnastics just to understand a single conditional.

I’m not going to give you a checklist of academic rules or tell you that “everything should be a function.” Instead, I want to talk about the friction you feel when reading a pull request. I’ll share the specific, messy signals I look for to determine when a comment is actually a debt signal masquerading as documentation. My goal is to give you a practical way to spot when your comments are hiding logic that should have been a variable, so you can stop writing explanations and start writing code that explains itself.

Table of Contents

When Comments Hide Code Smells and Refactoring Opportunities

When Comments Hide Code Smells and Refactoring Opportunities

I’ve learned the hard way that a comment is often just a bandage on a wound that actually needs stitches. If I find myself writing a paragraph to explain what a specific block of logic is doing, I’m usually not documenting the code; I’m apologizing for it. This is one of those classic code smells and refactoring triggers that I used to ignore. I’d think, “This logic is complex, so I’ll just add a note,” when the reality was that the logic itself was too opaque. When you rely on a comment to bridge the gap between the code and the reader’s understanding, you aren’t writing self-documenting code; you’re just adding a second place where the truth can drift away from the implementation.

The real goal is reducing cognitive load in programming. Every time a developer has to jump their eyes from a line of code to a comment above it to mentally “compile” what is happening, they are spending mental energy. If I see a comment that says `// check if the user is eligible for the loyalty discount`, and the code below is a mess of nested `if` statements and bitwise operators, that’s a signal. I don’t need a note; I need a boolean variable named `isEligibleForLoyaltyDiscount`. If the name is right, the comment becomes redundant, and the code finally starts to speak for itself.

Reducing Cognitive Load in Programming by Deleting the Prose

Reducing Cognitive Load in Programming by Deleting the Prose.

Every time I see a block of prose explaining a complex calculation, my brain does a little involuntary skip. It’s a mental tax. When you’re deep in a debugging session, your working memory is already stretched thin; you don’t want to be translating English sentences back into logic. I’ve found that reducing cognitive load in programming isn’t about writing more documentation, but about removing the friction of translation. If I have to read a paragraph to understand what a loop is doing, the code has failed its primary job.

The goal is to move toward self-documenting code vs comments by shifting the explanation from the margin into the logic itself. Instead of a comment saying `// check if the user is eligible for the discount based on their loyalty tier`, I’d rather see `if (user.isEligibleForLoyaltyDiscount())`. The latter doesn’t just tell me what is happening; it becomes part of the structure. By improving code expressiveness through meaningful variable naming and small, well-named functions, the prose simply evaporates. You aren’t just making the code “cleaner”—you’re making it so that the next person (which is usually me, six months later) can scan the logic without having to stop and “read” like they’re studying for a history exam.

My rule of thumb for the "comment vs. name" triage

  • If you find yourself writing “if” or “while” inside a comment to explain the logic, you’ve already lost. If the comment says `// if the user is an admin and has a premium subscription`, the code should just be `if (user.isPremiumAdmin())`. The prose is a symptom of a missing abstraction.
  • Watch out for the “magic number” trap. I used to see comments like `// 86400 is the number of seconds in a day`. That’s just a waste of my eyes. If I have to read a comment to understand what a literal value represents, that value deserves its own constant name.
  • Use comments for “why,” not “what.” If the comment explains the mechanics of the line, it’s a sign the code is too dense and needs a descriptive variable or function name. If the comment explains a weird business rule from the insurance firm that makes no sense to a sane person, keep the comment.
  • The “scrolling test.” If I have to scroll past a block of three lines of comments just to see the actual logic, the code is too opaque. I’d rather have a slightly longer line of code with a well-named variable than a paragraph of text explaining a cryptic one.
  • Treat comments as a debt collector. Every time I write a comment to explain a complex expression, I mark it as a task to refactor that expression into a named variable. If I don’t, I know from experience that I’ll be the one staring at that same mess six months from now when I’m trying to fix a production bug.

The TL;DR for when you're staring at a messy diff

If you find yourself writing a sentence to explain “why” a specific value exists, stop. That value is a magic number or a configuration constant that deserves its own name.

Use comments to explain the “why” of a business decision or a weird workaround, but use variables to explain the “what” of the logic. If the “what” requires a paragraph, your code is lying to you.

If you can’t delete the comment without the code becoming a mystery, you haven’t written a comment; you’ve written a patch for a bad abstraction. Refactor the abstraction instead.

The Bottom Line

The Bottom Line: Use descriptive code.

At the end of the day, my rule of thumb is simple: if I find myself writing a sentence to explain what a line of code is doing, I’ve probably failed to name the thing correctly. Comments are great for explaining why we took a weird shortcut to fix a production bug, but they are a terrible substitute for clear, descriptive identifiers. If you’re spending more time reading the prose next to the logic than the logic itself, you’re just adding unnecessary cognitive tax to every developer who touches that file. Stop treating comments like a safety net for messy code and start treating them as a last resort for the edge cases that even a perfect variable name can’t capture.

I’ve spent enough late nights staring at screens to know that code is read far more often than it is written. We aren’t just writing for the compiler; we are writing for the person who has to fix this at 2 AM when the pager goes off. When you take the time to turn those sprawling comments into meaningful names, you aren’t just “cleaning up”—you are building a map that actually works. It might feel slower to refactor that block of logic today, but it is a small price to pay for leaving a trail that the next person can actually follow without needing a translator.

Frequently Asked Questions

What do I do if the "name" becomes a massive, unreadable sentence that's longer than the code it's replacing?

If your new variable name looks like a paragraph, you haven’t solved the problem; you’ve just moved the clutter. A name that long is a signal that your function is doing too much or your logic is too nested. Don’t try to squeeze the entire context into one identifier. Instead, break the logic into smaller, private helper functions. Let the function name do the heavy lifting, and keep the variables short and meaningful.

Is there a point where I've gone too far and ended up with "variable soup" where everything is a tiny, single-use name?

Yeah, you can definitely overcorrect. I call it “variable soup,” and it’s just as exhausting to read as a wall of comments. If I’m scrolling through a function and seeing `isUserEligibleForDiscountAfterApplyingSeasonalCoupon` every three lines, I’ve lost the forest for the trees. If the name is so long it feels like a sentence, you’ve just moved the cognitive load from reading prose to parsing identifiers. Keep names descriptive, but keep them lean.

How do I handle comments that explain *why* a weird hack exists—can those be turned into names, or do they actually need to stay as prose?

This is the tricky part. If the “why” is a business rule or a weird edge case—like ‘because the legacy billing API fails if we send more than 5 items’—that stays as a comment. You can’t name a variable “because-the-api-is-broken.” But if the “why” is just explaining a convoluted math formula, name the formula. If the prose is describing the intent of a hack, keep the comment, but wrap the hack in a function named after that intent.

At what scale does this start to matter; am I over-engineering this for a small internal tool or is this rule universal?

It matters at scale one, which is the moment you aren’t the only person looking at the code. Even for a small internal tool, you’re writing for your future self—and as I’ve learned the hard way, “future me” is a stranger who has forgotten everything you currently think is obvious. If the tool is going to live longer than a single sprint, treat the naming like it’s production code. It’s not over-engineering; it’s just avoiding future debt.

Tomasz Wierzbicki

About Tomasz Wierzbicki

I am not interested in arguing about frameworks. I am interested in why the thing broke at two in the morning and what would have prevented it. Most of what I know came from being wrong in production and writing it down afterwards.