Exactly! I have written code that required comments five times as long as the code itself to defend the code against well meaning refactoring by people who did not understand the code, the domain, or the care needed to handle large dynamic ranges.
I have also written substantial functions with no comments at all because it was possible and practical to name the function and all the variables so that the meaning was clear.
If you didn't back that documentation up with some tests to reflect the necessity of that complexity, this is an avoidable tragedy. But if the junior then comes in and deletes your tests because they don't pass, that's a firin'.
It's fun and enlightening to go ham on any particular style/framework/philosophy, but actually living by dogma in prod gets kinda dangerous and imo is counter to the role of a senior+ engineer
1) empirical measurement compared to a large number of alternatives ... the empirical measurement or study is never mentioned: because they do not exist
2) the best practice is valid in all measurements and criteria of comparison: performance, elegance, simplicity, correctness
3) since there is no data, the reasons for why the practice was designated best are rarely even explained
4) nor are the circumstances or individual or source of "best practice" detailed
5) it will always be the best practice: it is the BEST! It CANNOT be improved.
So we have an unsubstantiated, unargued, unsourced, non-authoritative, exaggerated declaration in virtually every case of "best practice"
I have regretted following that lesson ever since.
If you're commenting about the code, do.
There's a huge difference in the value between one or the other.
Therefore, comments should only be used for things like psuedocode, or as help for fellow developers during dev.
Then, they should be removed once the code is done.
But yea, not a good idea.
If you can make your code more clear, so that comments aren't necessary to explain what it does or how it works, that is probably (but not always!) something you should do. But that doesn't mean you shouldn't have comments. At the very least there should be comments explaining why (or why not) things were done a certain way.
But of course you will have some individuals who think it is cooler not to, and they are probably the same people who think use after free bugs can be avoided by the shere willpower of the solo-male-genius that they are.
Good readable code removes the need for comments about what the code does, if the working of the code needs extra explanation then perhaps it is being too clever or overly terse, but there are other classes of comment that the code simply explaining itself can't cover.
Some of my comments cover why the code does what it does, perhaps linking it to a bigger picture. That could be as simple as a link to work ticket(s) which contain (or link to) all the pertinent details, though I prefer to include a few words of explanation too in case the code is separated from whatever system those work items are logged in.
Many comments state why things were not done another way. This can be very similar to “why the code does what it does” but can be more helpful for someone (perhaps your future self) who comes along later thinking about refactoring. These can be negative notes (“considered doing X instead, but that wouldn't work because Y or interaction with Z” – if Y and Z become irrelevant that future coder can consider the alternative, if not you've saved them some time and/or aided their understanding of the bigger picture), helpful notes for future improvement (“X would be more efficient, but more complex and we don't have time to properly test the refactor ATM” or “X would be more efficient but for current use patterns the difference would be too small to warrant spending the time” – the “but” parts are not always stated as they are usually pretty obvious). A comment can also highlight what was intended as a temporary solution to mitigate external problems (“extra work here to account for X not being trapped by Y, consider removing this once that external problem is fixed” or “because X should accept Y from us but currently doesn't”).
This is one of those blindspots devs have in that they believe their code to be good and obvious to everyone but in reality it is not even good and obvious to their future selves who will be the ones maintaining that code
That could be used to see how good a language is for specific tasks. If you need to write lots of comments, maybe you have the wrong language.
That and “those who actually use power are likely to be those who shouldn't have been given it”!
I did a survey once in about 3/4 of the comments were either wrong or useless. Examples:
//Add 1 to x
x+=1;
//Add 1 to x
x+=2;
//Seconds per normal day
x = 86400;
--
"Why not" comments are incredibly valuable except they suffer from explanatory decay as much as other comments.
The hope behind Intention Revealing Names is that the dissonance will be too great for the subsequent developers to ignore when they change the code.
Of course, that isn't always true.
x = 86400
If I were forced not to write comments, I'd write that as x = 24 * 60 * 60
and let the compiler optimize that.> Examples:
> //Add 1 to x
> x+=1;
If 3/4ths of comments are like this, maybe show a sampling of public source code (e.g. from github) that shows how prevalent comments like this are in any real codebase.
I've been programming since 1982 and have never seen this type of "add 1 to x" comment in real code, outside chapter 1 of some intro to programming book.
I will als name each db table column in the correct order by its correct name right above that what decided the value.
// id
user_id = getUserId();
They serve as dividers.
using namespace std; // using namespace standardAnd, you definitely had little experience with under-documented code
Also: if the code and the comments appear to disagree, there is a reasonable likelihood that both are wrong in some way.
Git commit messages are better than comments, because they tag the specific baseline of code where a decision was made, and you can write multiple paragraphs to explain something (including all the "why not"), without cluttering the program text.
The problem with comments is that they also pertain to a revision that existed around the time they were written, but they stick around, pointing to newer revisions, perhaps falsely. They add clutter. Unless you use a folding editor, comments can separate pieces of code so that you see a smaller window of the program.
One line of code can be touched by many, many commits. Each of those commits should have something to say about that, and all that talk cannot possibly be put into a giant, ever-growing comment next to that line of code. In regard to my previous point, a lot of that talk won't even be relevant to the current version of that line!
I've taken the view that the thing I'm developing is a git repo, not the source tree.
A source tarball is just something for building and deploying, not for development.
If someone wants to understand why something was done, they must use the repo, and not a source tarball. If they insist on just working with the source snapshot, but ask questions that are answerable in the git history, I cannot support them.
That said, git commit messages as a meaningful source of information aren’t for me, I prefer reading the code as a single pane of information. We alleviate concerns about doc strings and comments becoming out of sync with the code by just reviewing comment salience as part of standard code review.
Either way, I think there’s no wrong answers, if it works for you and your team then that’s good.
In my open source projects, I use GNU ChangeLog format in the log messages. This mentions every file that is touched, and every defined entity (function, type, macro, variable, ...). In a code review, while it would still be difficult to enforce the quality of what is written about these things in the comment due to subjective reasons, there are objective aspects to it. When reviewing, you can point out something like "you changed the initializer of global variable g_foo, but it's not mentioned in the commit message".
Sure, API comment headers can be enforced reviews. But those are not the comments this discussion is about (and elsewhere I identified these as necessary comments that can't be farmed out into the git log messages).
I do not think that helps much, in the general case
> The problem with comments is that they also pertain to a revision that existed around the time they were written, but they stick around,
Comments do require maintenance. It is part of professional practice
- The code 'tells you' what it does
- The comment for the code tells you what the author intended it to do.
The gap between the two is where bugs can be found.
log.Debugf("Foo is: %#v", ...) //You think: this is probably filtering code log.Debugf("Foo without X is: %#v", ...)
Not quite.
The comment for the code tells you what the author of the comment understood the code to do when hen wrote the comment.
I don't write what the code does or even what "I understand the code to do". I explain choices, especially ones that the next developer or my future self is likely to misunderstand when looking at the code.
I've always said coding is a cottage industry!
It's luckily rare for people to add wrong comments, though (and those who do should be publicly fustigated).
By the way, please never state something as it were the truth if you're not sure that it is. Saying "I think" is perfectly fine, and might save people days of investigation.
I've seen 64 character variable names
Names should be mnemonic. Reminding, not describing
There's vanishingly few cases where this extra logging statements will ever be a problem and they can all be handled autonomously if they ever are - but it will save everyone else a ton of time in deployment.
Re: busy, no because I only enable debug logging when I need it
Re: loops, I wrote a deduplicating logger, so if there are 200 identical messages from within a loop I see:
{event: "thing happened"}
{event: "thing happened",
duplicates: 100,
since: "2024-09-11T01:05:00Z",
reason: "count reached"}
That is, supposing that it's set to saturate at 100 events and they all happen fast enough that it doesn't reset the count. In this case it'll log another batch of 100 on the 201st event.I think it's important to log the first one immediately, just in case you want to alert on that message. It wouldn't do to wait for the other 99 before raising the alarm.
I wrap my loggers in deduplicators only when I'm about to hand them off to a loop. Otherwise it's the normal ones.
The point is there's a big difference between "we've got a problem, we need to add logging and redeploy to try and isolate it" versus "we might have a problem, bump the logging level up on that service to see what's going on" (which with the right system you can do without even restarting).
It would be nice if they could be like footnotes, or boxed out-takes, that could be pushed to side notes. We have had the typography, even if it was just markdown with a rendered code reading mode.
Rich text code would create so many problems, too. You get locked into a special editor. You need special version control. Grepping becomes difficult. Diffs become difficult. You'd need a whole separate ecosystem, and for what? We have treesitter; we can already treat code like data.
So, less comments wins out, but faced with a code base without comments you have to inspect it to tell the difference between a beautifully crafted piece of brilliance or a totally flaky codebase written by a bunch of newbie hacks.
This is a common experience when I use a new language or framework. At the start I comment a lot of things because I think it's useful for future me, but as I learn more I realize that many of the comments are redundant so I end up removing them.
That is things like cases it doesn't support, or weird results in some cases.
One example is a shop I worked many years ago that had a function which did time conversion on date times without adjusting the date portion. Obviously, objectively, wrong.
However the callers to this function expected this errant behavior. Actually changing it to behave correctly would require a coordinated change. Putting that comment in place prevents a new hire from going "oh this is obviously wrong!" and fixing it, causing an outage.
If it's not answering why or at least providing a very concise how to very verbose code, then it's just adding noise
And C-level engineers write a comment "X hours have been wasted on refactoring this code. Should you decide following the example of your priors, please increment this counter."
Sometimes, even what appears to be an utter hack job actually is the best you're gonna get.
I'm apologising because the code isn't obvious, or the language not sufficiently expressive, or the good-idea-at-the-time no longer is. Ideally I wouldn't need to write many comments, but I often find myself sorry things are not simpler.
You are right in spirit to say sorry when the code cannot be self-explainatory, but consider that sometimes even if the code is self explainatory, comments can help your reader to see the grand picture faster or to avoid interpersonal ambiguity by allowing you to use two different ways of phrasing a thing.
Cursor cursor = getCursor(); // Cursor. class User {
public String getName() { ... }
}
to have a doc comment explaining what getName does and also what it returns. Before git, they sometimes needed to see who wrote it and when.Somethings I include brief explanations or links to a particular piece of hard-to-find documentation.
I suggest providing that sort of high-level decision information in a separate design document. This sort of documentation is written before the code and is presented/discussed with management and peers.
That is how it was done at a couple of companies I worked at and it was very effective. Naturally, this was done at the feature level, not on a function to function basis.
The nice thing about comments is that they're in the code. You can't update the code without at least looking at them; that's more visibilty than you'll get from anything else.
Having documentation in your repo describing high-level architecture choices and peculiar quirks for future maintainers is nice, sure, but I think that's a separate document with different goals and relatively little overlap. It shouldn't be organized by feature, for starters.
Also, if the remarks in that document are granular enough to exist as comments, why not just leave them as comments? Then they're more visible and more likely to remain up-to-date.
Alternatively, if your org or reach for this feature is so large that you need to communicate and decide its internals with a lot of people and as such require something like a design document, then you've already failed and you have way too-many cooks in your kitchen. Design by committee is always doomed to failure.
Thirdly... if you need a design document to communicate your feature to "management" then that means you don't have autonomy to design this feature as an expert, and again, you have too many "fingers" in your pie.
Does this mean you should go into a basement and design your feature like a hermit? No, but a design document shouldn't be your answer, it should be a better team and process around you, as well as a clear business specification.
If you need to communicate your design to a lot of people, that's probably because a lot of people are depending on the output of your work, and they want to make sure it suits their needs. That's not design by committee—that's just designing something that will be widely used.
The process led to not only better designs, but also better visibility for all stakeholders, from technical leads to individual contributors.
I'm talking about products that shipped on billions of devices, products that you have most certainly used. It worked.
void vendorReturnsDataInInvalidFormatAndButShouldBeResolvedByVendorOpenTicketXYZ_123ExpectedResolutionQ42024(String input) {}
/s
"A junior engineer writes comments that explain what the code does. A mid-level engineer writes comments that explain why the code does what it does. A senior engineer writes comments that explain why the code isn't written in another way."
(except punchier, of course. I'm not doing the quip justice here)