/ golang

Why I refuse to give up code comments

There's a growing movement in software whereby programmers are conciously omitting code comments from their code. When I was job hunting last year, I was even marked down in a technical test for having comments in my code.

The argument is, and I think the argument has its heart in the right place, that code should speak for itself.

Code should be readable, it should more or less read like a text document. Variables should be named something sensible, something that makes sense; that's inddicative of the domain. Functions and methods should demonstrate some indication of what they do, or what to expect in return. Classes and structs, too, should be clearly named and give some clue as to what they are.

The second argument is that code comments become out of date with the code itself.

But I think there are two flaws in this approach, which I see very often.

Firstly, there is a naivety in thinking, that programmers will always follow these principles in the same way as you. Some engineers will have a different interpretation as to how to desribe that class, or that method.

What fulfillOrder means to one engineer, could be interpreted differently to another engineer. Does fulfill order mean, take a payment? Does it mean to simply store the order? Does it perform a transaction? Does it send an email confirmation?

Okay so that may be a bit of a tenuous example, but it shows that something very simple, two words infact, can be 100% implicit, and obvious to the person whom wrote it. But can actually be open to interpretation to a new person blindly trying to traverse their way around this unfamiliar code with little context.

Yes, a function should only do one thing, and perhaps that's why my example isn't the best. You could name a function saveOrderToDatabase, and you should probably have a sendUserEmail separately somewhere later. That would read better, and would be less ambiguous. But this is a very simple example. In many real-world cases, you find yourself up against an inherently large and complex system, with many moving parts and complexities beyond your current comprehension. In these situations, you will come across functions or variables, which made perfect sense to the original author, but will be completely meaningless to you.

So why is that? What's missing, that can't be summarised within the code itself in a complex system? Context.

Context is a huge part of programming, it is meta information which exists somewhere between the code itself and the organisation who owns the code. It's the invisible ether in the nether region between the cold hard classes, the white boards, and the product managers. It's the assumed knowledge, it's the bigger picture.

Sure you could name something sendUserConfirmation, but when exactly should that be sent? Under what conditions? It's never as simple as that in a large business. In most codebases, the sendUserConfirmation, might be behind an if statement which switches between a legacy SMTP server and the new cloud provider based on a config file, which is only set on some servers, for whatever reason. It might be in a function call, that's only triggered, if an environment variable is set by an ops team in a different country, if there's a sale on.

My point is, however cleanly written your code is, it's almost impossible in my view, to describe the context which surrounds most code, without some code comments.

What is the result of omitting comments in a large, complex set of codebases, typically found in a large organisation? Even with the best engineers, you will come across sections of code, which on the very surface make sense. Code that reads well, but you have no idea where it's used, what calls it, when it's executed, or perhaps how configuration affects it.

I don't think anyone in the right mind would suggest comments such as:

// check subscription has referred user

That is completely arbitrary, it's already obvious what it does. In this situation, it is pointless adding comments, because the code does speak for itself, the comment isn't useful. But take this for example...

// we check the subscription has a referred user here
// so that we know we need to update the referred user count
// and not end the request.
// This will default to true if SKIP_REFERRED is true.

As you can see in this example, there's some additional meta context in the comments. Which serves as a reminder to someone making changes to this code, that there's some conditional operation, which also checks some configuration else-where, to be mindful of. It saves the user time digging around in this function. A new programmer can now infer more information about how this code works, that wouldn't neccessarily be infered from just the code. This is a vastly over-simplified example, it's naturally tricky to demonstrate this without having a complex code-base/example to give you.

I believe that code comments should exist, but should be used sparingly, for the purpose of explaining some of the additional context around the code, which can't neccessarily be summarised in a variable name, or a function signature. They should give some history, explain some of the business decisions, and fill in the gaps.

Whilst code speaking for itself is a grand idea. I'm yet to see a commentless codebase, that truly, dutifully explains itself with perfect clarity. And that isn't a slight at any of the codebases I've worked on, far from it, even some of the best codebases I've ever worked on, sans comments, have failed in some aspects to give proper context.

To address the second argument I've heard for omitting code, 'comments can get out of date', well surely that's true of all things. At least if the comment lives with the code, you can update the comment when you update the code. Surely, as engineers, we have a duty, and are capable of at least trying to keep these comments in-check as we update our code?

I could be completely wrong, and I'm willing to be convinced otherwise.

Discuss on Hacker News

If you are finding this series useful, and you use an ad-blocker (who can blame you). Please consider chucking me a couple of quid for my time and effort. Cheers! https://monzo.me/ewanvalentine