A comment is worth leaving. I’ve come round to thinking there isn’t one that explains what the code does. If you need a sentence to say what a block is for, the block is telling the wrong story. Rename the function. The comment disappears because nothing needed explaining.
People hear when I say this that I want no comments at all. A comment that explains why, or cites the paper the algorithm came from, or records the incident that made this branch exist, is doing work the code cannot do. That kind of note belongs next to the module and ages fine. The one I want gone is the running narration, the line above the loop that says what the loop does. Those rot first, because the code underneath them changes and the sentence above it doesn’t.
This is not a style preference. A comment is a second copy of the meaning. The code does what it does and the comment says what it used to do. The reader now has to decide which one to believe. That’s worse than no explanation at all, because the wrong one is right there in the same file looking authoritative.
Agents have made me firmer on it rather than softer. A developer reading a vague function works the intent out from everything around it. An agent takes the function name and the comment at face value and builds on whichever it read last, so a lazy name becomes the vocabulary for the next twenty files. The code is the meaning because the code is what gets copied.
If the meaning isn’t obvious, the move is always the same: rename the function, split it, improve the parameter names. Look again and look harder before you reach for the comment.
The full write-up is at https://prickles.org/tenet/self-documenting-code/F5
Personally I like the exception message and debug message and log outputs approach.
Comment just for what you said, a kind of historical graffiti.
Exceptions should catch why something didn’t work and where. Debug should be telling where in the process something is happening. If it’s descriptive enough without code in front of me it extra useful with code in front of me.
ADRs, and tests should cover the whys and expectations for a code base.
I do wish I had a better structured framework for debug statements that could be tested/verified easier (do you all right tests for debug outputs? That sounds like hell tbh).
This is a fantastic discussion on the issue:
https://github.com/johnousterhout/aposd-vs-clean-code
In brief: Robert “Bob” Martin, author of “Clean Code”, could not explain an algorithm he published himself in his own book. He published it without comments.
He was also not able to change it without breaking it, because he did not understand the invariants in the code he published.
Bonus points for that he copied the algorithm from Don Knuth, who published it as an example for his lucid invention of “Literate Programming” - a method to better explain code and its pre-conditions and invariants, by interspersing explanatory text with the actual code.
Extra bonus points for that the algorithm which Don Knuth documented was first published by grandmaster Edsgar Dijkstra in “Notes on Structured Programming”. A brilliant book chapter which explains once and for all invariants in code and data structures.
BTW… my impression is that “ai” tools (LLMs) are pretty shit at invariants. Invariants require understanding.
I’ve always hated AI comments. They’re the bastard fusion medium blog spam and data labelling from underpaid and exploited people seeping into the slop.
Comments are for why, edge cases, and caveats. They should help explain unintuitive behaviours that usually must be learned the hard way, they help expose a larger structures, they explain an optimization, a shim, or a complex regex, or they explain where a temporary measure exists. Things of that nature.
Self documenting code is about thinking of the reader. I’ve worked in places that uphold self documenting code as gold and banned code comments at all and I’m convinced that’s wrong. It’s a burden on readers to have to go through history to find the addition, but the file has changed names or moved without a proper git mv and it’s a waste of time.
On that note, learning objective C and Swift did a lot for how I think about what naming could be. I try to focus on clear verbs and nouns so the action and target are always clear, avoid side effects, include examples in my docs, and embrace typing structures like nanedtuples in untyped languages.
Comments rot. The code changes. The comment beside it doesn’t. By the third commit the prose lies about the line above it.
That only happens if people editing the code do not see comments as valuable and important. The fix is easy: Unterstand the code, its changes in the version log, and update and correct the comments as you change the code.
And: If LLM tools could really understand code, it would be easy for them to check changed code and point out where code and comments do not match any more - and why.
The worst, I think, is to have all three of specs and requirements, code, and comments and documentation generated by LLMs.
Because then you have nothing which is checked by a human whether any of it makes really sense.
If the LLM tool just implemented a signature/spec/architecture wrong that was written by a human, this would be easy to fix later, without messing up the interfaces within the system. Not so if you have ai Spaghetti code created without human understanding.
When I was a newbie, the “self documenting code” screed made sense to me, but with experience I’ve come to learn the type of person that is likely to latch onto it and advocate for it writes the least maintainable code.
Don’t make 80 character function names or change to structure of code to something worse to try to make it self documenting. Don’t write comments that are already obvious from the code. Don’t be shy about writing comments otherwise. Do update comments and ask people to update comments in PR feedback.
Most of all, fuck writing less maintainable code to try to satisfy LLM agents.
LLMs love to over-engineer for edge cases that don’t even exist. I have to call that out regularly in almost every PR review.
Yup, and the people that submit these PRs are outsourcing their work to you and getting away with it
Comments can help people see what the code is doing at a glance, without having to figure out what a particular function call is doing in the context where it’s being called. Sometimes, you’re just skimming, because you’re looking for something specific. Perhaps it helps you when searching for keywords? Here, I’ll include an example: Yesterday I wrote a little Godot mod loader, part of which is tweaking the project export to .zip up mods separately instead of including them in the main game.
# Ensure the output `mods/` directory exists. DirAccess.make_dir_recursive_absolute(output_mods_path) # Clear out old mods from the output `mods/` directory. for name in DirAccess.get_files_at(output_mods_path): DirAccess.remove_absolute(output_mods_path + "/" + name)Now, admittedly, Godot’s naming of its built-in functions isn’t helping. But yeah, you can take a couple seconds to understand what the function call does, or you can read the comment and immediately have context for the code after it. I don’t think throwing these 3 lines into their own 2 extra functions would help anyone. Then again, maybe these are 50% “why” comments and 50% “what” comments.
On the other hand, here’s a larger comment that is needed to explain why that bit of code exists:
# Resources reference additional files that may be compressed or otherwise pre-processed, # which are exported to `.godot/` instead of `mods/` and are listed in the `.import` file. var import_file_path := file_path + ".import" if FileAccess.file_exists(import_file_path): var config := ConfigFile.new() config.load(import_file_path) for dep_file_path in config.get_value("deps", "dest_files", []): _zip_file(zip, dep_file_path)I understand that over-commenting things can be annoying, I understand that it’s good to encourage people to name symbols appropriately and to split things into functions that in some way act as good documentation on its own. But if you go too far, you end up with tons of methods that you have to jump around in the source code to figure things out, and that could pull you out of the flow too.
Commenting for the sake of commenting? No. AI slop comments? Heck no.
Commenting because it helps you internalize how something works, or helps you remember? Go for it! Commenting because you feel like it’ll help the next person understand your code? Please don’t shy away. I’d rather have a couple more unnecessary comments than too few with a spaghetti of nicely-named function calls.
over-commenting things can be annoying
Not only that, it can also be a wrong comment when forgotten to update them when changing the code. In such cases no comment is even better. So I do less comments than before nowadays, especially with Python. You also have to think who your target audience is (future you? teams of professional game devs? scientist without much programming knowledge? random online beginners?). Finding a middle ground is mostly impossible, so having the target audience in mind is important in my opinion.
Imo it’s not that hard to fix. If someone changes code then you force them to update the associated comment as well. Don’t allow them to merge without updating the documentation.
In regard to audience, I guess I’m lucky because only engineers will read our code and I suspect that’s true for most people. I wouldn’t concern myself with beginners tbh, unless there’s some reason you really need to. I think that’d lead to unnecessarily verbose comments that wouldn’t help anyone.
I’d much rather have both “self-documenting” (which I don’t fully buy as a concept) and well-documented code at the same time.
Self-documentation has many of the same problems people point out with comments anyway.
The point of self-documenting is, that if you need to explain it in a comment, you probably should update the code to make it readable by its own. This is not meant to be the only way going forward. It’s just to have this in mind and try to do it whenever an opportunity you see. More a thumb of rule thing, rather than hard reality.
Agreed. I tend to write one-liners that I don’t want to re-parse myself later, much less force someone else to parse. A simple comment can be a major help and time saver for everybody.
Emphatically this.
Self documenting code goes only so far. At some point, you want to explain why you do it, not what you do. And commenting blocks of code will be necessary to have good documentation. Sometimes having too long function and variable names can make the code less readable, so that is not always a good idea. For an LLM it is excellent, but if a human reads the code, then its different.
So don’t forget writing / changing code is not just for reading by agents (LLMs) and code reviewer tools. You can satisfy them, but it might cost you readability for humans. I also like having code searchable through grep (line wise thinking, also good for git changes) or search and replace (variable names in example). These are interactive tools as I call them, and are meant for used and read by humans too.
There is lot of consideration when it comes to make code readable and usable in long term.
There is no such thing as self documenting code. In any project the code can only ever tell half the story, the rest must be documented. Even then, I don’t always want to have to go back and figure out what each part does. There is a reason basically all code repos also have built in wikis.
int a; // integer aOkay, and where is the rest of your code?
Why do you need more code? This has comments. It’s perfectly clear.
The other comment I constantly see is the function header that’s obviously copy-pasted from another function and literally nothing changed to reflect the function it’s meant to document. Not the return type, not the parameters, not even the function name.
Or the “helpful” ones that were once true but no longer are due to subsequent changes, which waste more of your time than if they never existed.
Comments are a smell.
Because if you are going to be a pedantic asshole and miss my point then so am I.
I literally mentioned code repo wikis…
Honestly though, it doesn’t seem like you have ever worked on a large project with multiple devs if that is really what you think.
😄
I wrote code for FDA Class III medical devices. Dozens of engineers, plus a controls team, plus a design verification team, plus a regulatory team. At a real company, not some hopeful startup.
Real engineers don’t look at comments, they look at code.
And unit tests.
And SITL tests.
And requirements, which are called-out in the tests.
And FMEAs.
Keep your comments. They do more harm than good.
Okay, obviously rage bait. Don’t feed him
cites the paper the algorithm came from
Having done this, I usually put a comment referencing which step of the algorithm I’m on along with whatever the “title” of that step is (the primary action from it, like “collect flex items into flex lines” from CSS Flexbox Level 1 step 9.3.5). Sometimes, the following line of code is that entire step and is self-explanatory, but I still feel like the comment explains why that line exists by referencing the algorithm directly.
Just keep in mind that method names can also get stale and you have to be extra careful there because, when reading the parent method, you only see the method name without the code alongside it.
Exactly. Imo “self-documented” code is mostly not a thing. I’m all for descriptive variable and function names but those are not an automatic replacement for good documentation. And yes you do need to maintain the documentation and variable names too.
Indeed. Don’t comment “what”, only comment “why”. If you’ve written code that looks like a mistake but is there for a reason - poor algorithm, not idiomatic, etc. - then the proper “comment” is a unit test that exercises the business logic behind it, but a one-liner to stop someone from “fixing” it is maybe polite too. Don’t write an essay for private functions; rename them so they’re obvious.
Yeah, I always tell people the fundamental problem with comments is that they’re only visible in one place. Method/variable name, log outputs, error messages, docstrings all show up in at least two places, which makes them more valuable in general, but also makes it more likely for them to be read+updated.
How would you do this with SQL?
And sure, we can carefully choose the names of our SQL stored procedures and input arguments. But inside of a procedure where actions take place and statements are made to achieve those? How easy is it, in your experience, do split off sections into their own procedure and rework their name?
For me, the same rules apply, but as you say or hint, SQL as a language is different from higher, “structured” programming languages.
Adding comments on subqueries, applies, conditions, doing deliberate line breaks or oneliners, procedure comments and documentation where they make sense - most of the same things apply and are applicable. Structuring and commenting works quite well, until it doesn’t for performance and readability reasons where you don’t want to introduce additional procedures or functions or separate other aspects.
In those cases, it is what it is. Often comments can live on the lines where the aspect is.
I also like to use block comments with open and closing block indication like
-- \ Table or aspect something stuff \ […] -- / Table or aspect something stuff /The language doesn’t provide the structure for it, but I can still implement that structure through text comments alone.
Docstrings are fine as well. I mean for generating something like an API documentation with Sphinx. Other than that, yes. Everyone should learn this in programming school right at the start. Get into the habit. Name things properly. Write it in a way the code is expressive in what it does and how it does it.
Yes, docstrings are a different thing. They’re actual documentation. Comments serve no functional purpose. The only useful comment, of the top of my head, is one that explains why certain choices have been made.
I have never gotten anywhere with coworkers arguing this. They write the dumbest comments and resist feedback in PRs. Now with LLMs we’re adding a bunch of unit tests that are about half comments. I cannot begin to express how useless these comments are. No one is going to read 15 paragraphs to understand a slop unit test. If that shit breaks it’s not going to be obvious why. Between the verbosity and writing style, these comments are some of the least grokable shit I’ve seen in my career. My coworkers have basically let me know that my feedback is noted but they disagree.







