Comment-Free Coding

It is a truth universally acknowledged, that a readable codebase in possession of a good engineer, must be in want of comments. As manipulators of logic, we programmers (and sith, I guess) tend to have a habit of dealing in absolutes. You’ll often see “well commented” as a metric of readability on university marksheets and interview homework checklists. In the spirit of breaking that habit, I’m not about to argue against comments as a whole. Instead, I’ll show you how thinking of them as a last resort it can force you to deal with the root cause of confusing code- instead of just treating the symptoms.

Do Comments Have Downsides?

Comment-free coding doesn’t mean you have to say less. It means that you’re moving what you’re trying to say into the code itself, which has a number of benefits.

Increases information density

ย When presenting any information it’s always important to consider your medium, whether it’s a bottle label or a roadside billboard. Code is usually viewed on screen sizes down to about 13″, so make the most of that limited space by keeping information relevant. When code isn’t padded out with comments, you’re more likely to be able to see the whole scope of an if statement or the signature of the function you’re reading.

Information is available in more places

It’s pretty common practice to explain a function or variable’s purpose in a comment. Some IDEs will put adjacent comments into a tooltip, but I prefer having the symbol’s name and type tell you what it’s for. Without a comment, you’re forced to explain your variable where it can be seen at every reference.

A missing comment is better than a bad comment

You can waste a lot of time poring over confusing code whenย a well worded comment could clear things up in a second. You can also waste time being led in the wrong direction by a comment that’s inaccurate, out of date, or poorly phrased.

The latter is an easier mistake to make; explaining code through code is a consistent language, often enforced by the compiler. Explaining code through spoken languages has an extra step of obfuscation. Good comments and clear code are not mutually exclusive, but a comment can easily make things worse if not written and maintained well.

The Right Tools for the Job

There’s plenty of places in your code that you can convey meaning that aren’t a comment. If you’ve cleaned up your code as much as possible and it still seems fuzzy, try using these tools.

Longer variable names

It’s pretty popular to dunk on the perennial single-letter variable name, and in the vast majority of cases I’m inclined to agree. Still, people can be reluctant to have a variable longer than a couple of words. I find that when code that’s laid out in simple steps without having lots of long variables on a line, it doesn’t hurt the readability.

You might find that when you’ve done your renaming your code becomes very wordy and solid. If this is due to your variables having a lot of qualifiers, I would consider organising the data into structs or maps. When names like “NumOfEnemiesInCurrentWave” look wordy, try “Wave[CurrentIndex].EnemyCount”. This replaces vague prepositions like “of” and “in” with unambiguous operators. Which of these you use is down to your discretion, and how it looks in the context of the surrounding code.

Split up functions

I’m a fan of keeping functions short and my general rule of thumb is that a function should fit on one screen. Before I stopped relying on them, my most common use of comments was summarising big sections of code.

Now where I would have been tempted to put in a comment, I’ll extract that section into new function. The nice part of taking functions out is you not only get to describe the function in its name, but also define its input and output programmatically using the arguments and return type.

Give everything a name

“Magic numbers”- numerals with no explanation for what they represent- are the most common demonstration of the value of a name. You might be already on board with the idea that saving numbers as meaningfully named constants is good practice. Sometimes function parameters can be a hiding place for “magic” values which aren’t as obvious as an “if(value == 5)”. This may look like a familiar pattern:

void SpawnNPC( bool IsHostile, int AmountOfHealth );

Calling it can result in a fairly confusing line of code, easy to clear up with a comment.

//Spawn hostile difficult NPC
SpawnNPC( true, 1000 );

The 1000 is an obvious magic number, and should be in configurable data. However, the boolean is just as much a magic value as the number. It could be replaced with an enum called NPCType, containing entries Friendly and Hostile. This makes the comment totally obsolete:

SpawnNPC( NPCType::Hostile , NPCHealthLevels.Difficult );

Another scenario where naming values by caching them into local variables can come in handy is in testing a set of conditions. When you have to test a condition by a secondary outcome of the behaviour, the logic is removed from context. This is a classic opportunity for commenting.

For example, imagine you’re testing if all the enemies in a level have been defeated. The simplest way to do this might be testing if any are remaining in the level:

//Test all enemies have been defeated
if(GetAllEnemies().Num() == 0)...

This is where you can move the information out of the comment and into the code itself:

bool AllEnemiesHaveBeenDefeated = GetAllEnemies().Num() == 0;
if(AllEnemiesHaveBeenDefeated)...

This particular example doesn’t clean up a lot, but it’s more useful when the conditions are complex or numerous. Laying out conditions like this can also make debugging a little easier:

if(AllEnemiesHaveBeenDefeated 
    && IsFinalWave
    && PlayerHasEnoughHealth
    && PermadeathEnabled)
{
    SpawnBoss();
}

A note on typedefs

A lot of programmers like to apply the “name everything” concept to types and use typedefs liberally. I’m not so keen on them. I think that they don’t add information, but obscure the programmatic specification of the type with a potentially vague name.

Syntactic error defence

This article overlaps a little with another one of my posts, Code Hazards and How to Avoid Them. In that post I covered how you can prevent future misuse of your code resulting in bugs, without having to resort to “//Don’t do this!”.

The popular paradigm is that you should use comments to explain why, not what. The tips I’ve covered in that article are all about making the “why” more self-explanatory and self-enforcing. As Code Complete puts it, “Make interfaces programmatic rather than semantic where possible”. Make it so that the way your code should be used can be enforced by the compiler instead of specified in comments and documentation.

A Sidenote: Kuzco’s Comments

I’d like to bring up a particular style of comment I like to call “Kuzco’s comments”, named for a line from the highly underappreciated Disney film “The Emperor’s New Groove”:

If84

This cocktail of tautologies may be reminiscent of the kind of comment you put in your university project to get that marksheet box ticked. Many programmers keep them up as a habit:

//Increment count by 5
count += 5

I do think it’s important to remember that the people reading your code may have different backgrounds, communication styles, and experience levels. What they will have in common, however, is knowing the basic syntax of the language it’s in. Kuzco’s comments are fairly harmless, but the line padding effect is a compelling reason to eliminate unnecessary comments.

What to Keep

I’m probably not the best advocate of how to write good comments since I barely use them as a habit. I do find that they have much more use in code that can’t be optimised for readability. This can be because it has (usually mathematical) concepts behind it that don’t translate well into code. It can be because of quirks of systems you don’t have control over.

My trajectory calculation code, for example, didn’t break down into meaningful steps without deriving it from first principles. Longer variable names made complicated equations look like a huge mess. It was clearer to add a comment with the equation, a key to the variable meanings, and a link to the wikipedia page.

These sort of summary comments can be really useful, as they give you space to explain concepts behind your code without padding it out.


Once again, I’m not advocating banning comments completely. I’m giving you reasons that before thinking “What comment can I write to explain this?” it can help to try “How can I improve the code so that I don’t have to explain?”. The issue is maybe not with comments, but with the mindset that commenting as a habit can give you.

“Self-documenting code” is sometimes thought of as a lofty ideal. I think that as with anything else, it comes with useful ideas that are worth giving a try at your discretion.

One thought on “Comment-Free Coding

Leave a comment