Beyond "Clean Code": Why Your Comments Matter

chmaynard2 pts1 comments

Beyond “Clean Code”: Why Your Comments Matter - Tom Moertel’s Blog

Tom Moertel’s Blog

Home<br>About<br>Archive

Beyond “Clean Code”: Why Your Comments Matter

By<br>Tom Moertel

Posted on July 27, 2026

Tags: code, comments, clean code, good code, nature of code, purpose of code, source code, definitions, theory, philosophy, engineering culture

I have argued that comments are necessary in good code. My rationale, in short, is that your code’s logic can only express one thing clearly and faithfully: what you actually instructed the computing device to do. But your code’s audience—the people who will read and maintain your code—must also understand what you intended the device to do and the all-important “why” information behind your coding decisions.

To the extent that your programming language lets you express these things naturally in your logic, you should do so. But don’t contort your logic to accommodate intent and “why” information that would be easier for your audience to understand in natural language. Just use a comment! That’s what comments are for! To let you speak directly to your audience in plain language.

But not everyone agrees. In his book Clean Code, Robert C. Martin (aka Uncle Bob) writes that “comments are always failures”:

“The proper use of comments is to compensate for our failure to express ourselves in code. Note that I used the word failure. I meant it. Comments are always failures. We must have them because we cannot always figure out how to express ourselves without them, but their use is not a cause for celebration. So when you find yourself in a position where you need to write a comment, think it through and see whether there isn’t some way to turn the tables and express yourself in code.”

(Note: what Mr. Martin calls code I call logic to distinguish it from commentary.)

I have a hard time swallowing Mr. Martin’s argument because it goes too far.<br>If he had claimed that comments must be used with care, lest they become a crutch to prop up logic that ought to be rewritten instead, I would have heartily agreed.<br>But “comments are always failures”?<br>That admonishment is harmful.<br>Why?<br>Because eschewing comments makes code harder to understand and maintain by forcing you to express in logic any ideas that would be more clearly and directly communicated via commentary.

As I have argued above, logic cannot be trusted to express intent: it represents only what the device was actually told to do. If your logic contains an error, was that your intent?

Further, the syntax of logic does not allow for natural language, only a crude and limited approximation of it, and natural language is the, well, natural way to express the all-important “why” information underlying your logic.<br>That’s why the original source materials for this information are almost always written in natural language. Consider:

“We use scoring rules from the United States Bowling Congress: https://bowl.com/keeping-score.”

“Two Newton–Raphson iterations get us close enough to prevent noticeable visual artifacts.”

“We impose a global lock order to prevent deadlock with competing services.”

“Invariant: From this point on the array’s length must be 3N + 1 for some integer N.”

“We use simple brute force here because instances are guaranteed to be small (see guard above).”

“Limit each request to one day’s data; otherwise, we won’t get 1-minute resolution.”

“A binary search using this method of finding the midpoint still runs in O(lg N) expected time because, on average, we’ll be able to discard a quarter of the active range in at most two iterations, limiting the number of iterations to O(log(n)/log(4/3)) = O(log n), just as in the quickselect algorithm with random pivots.”

“We allow inserted rows to replace existing rows for the same device and timestamp because we want to allow for the possibility that the upstream source will revise data, and we prefer the most-recent version of any data we already have.”

“Repack the weighted pairs into a single array of blocks, each having a weight of exactly the mean and each representing one or two of the original values.”

In production code, this kind of information is often the most important. How would you communicate it clearly without using comments? Should you name your function ScoreAGameOfBowlingAccordingToTheUnitedStatesBowlingCongressRulesAtBowlDotComSlashKeepingHyphenScore? To communicate that an array-length invariant holds for the second half of your algorithm’s logic, should you exile that half to a new function you invented solely to let you name its argument array_having_length_3n_plus_1_for_some_integer_n? Does breaking the natural flow of your algorithms to invent naming sites make your code clean? Does using unwieldy names instead of natural language make your code clean?

Or contorted?

To be clear, I am emphatically not arguing against expressing intent and “why” information in logic . I believe that you should express them in your code’s logic to the extent...

code comments logic express clean language

Related Articles