Should I Comment My Code? The Case Against Code Comments
crondose.com
crondose.com
IMHO, your default mode should be to not to comment because you should instead focus on 'code as comments' - the code should be easy enough to read that it explains itself. Occasionally (for the reasons you pointed out) you need to fall back to english prose to explain those 'whys'.
Typically following language best-practices is ideal (pydoc, godoc, Javadoc, etc) so you can get easily-generated documentation for free. Following the standards will make any custom APIs consistent with the standard library API docs.
The most important thing though is to ask for peer review on the code. When you are writing code (just like regular language) it will make sense to you regardless of comments or proper variable names. Have someone else read it and tell you what the confusing bits are. If there is no one to do that because you're a lone wolf, then step away from the work for a couple days and play golf or something. Then come back, read the code, and ask if it could be more clear. Then either change variable names or add comments for clarification.
Tl:dr; i only do comments to excuse really stupid code.
I dont want to link to company applications honestly, and my personal ones are way to messy in terms of inline documentation anyway.
I'm not sure if any other IDE or editors have this but I really love this feature as a method of documentation. I'm not saying it is the best method or the only method one should use, just a useful method that I wish more IDEs & editors had.
Another point is that people tend to write awful comments anyway.
This. When we talk about stellar teams with stellar writers both in programming language and english, it seems nice to throw comment here and there. But when I look at what we do at work, I just... want to s{//.+$}{}, because comments there are A) misleading, B) senseless, C) grammatically awful, D) obsolete. Today almost everyone can be a programmer, but only few know how to explain things in short text at right place. You have to be writer to do that.
The best way to test a comment is to turn it into code and test it as code. Or, in more modern way, make a neural network that parses comments and check if these apply.
I am sure there are environments where this would be super messy, but if you work in small teams in a given structure always following best practice and basic refactoring. 99.9% of the code gets pretty obvious in its use.
My rule is like: Make the code say what it does, if you have to explain why it does what it does do it in the commit message.
* Calling confusing 3rd party APIs - sure, maybe all your code is self-explanatory but your code probably has to talk to somebody else's code and theirs won't necessarily be so self explanatory.
* Links to wiki pages and tickets.
* As a stepping stone to cleaning up technical debt you might want to explain what is going on before refactoring the code into something more self-explanatry.
* Adding context to an otherwise contextless module.
* If somebody asked a question in a pull request based upon the code (if the reviewer didn't understand, it often needs a bit more explanation).
# we leave the existing pattern alone if it's the same
# this is a performance optimisation to save us rerunning the
# searches and cc resolution again # NOTE(coderguy): Calling this method before calling
# Init will result in a runtime error.
I use comments to make people aware of invariants the code expects that aren't necessarily obvious from reading that code.My comments are generally along the lines of "so you're here because you need to change something? here's what you need to know", rather than "this is how you use this thing".
Some statically typed languages don't suffer from this particular problem of making types clear, so you will see comments less, and reserved more for cases where logic is hard to parse conceptually. But some static languages have a similar problem due to type inference, which causes commenting in the same fashion as a dynamic language.
I am of the school of thought that except for making types clear, the best way to comment your code is to make the code as clear as possible so that it is obvious without extra explanation. Often, you can refactor a clumsy or confusing piece of code in a way to make its intent clear.
But sometimes you cannot, and that's where comments come in.
- Public facing APIs where you're very specifically clear about how something works, to be consumed by people who don't intend on or need to read your code
- Explaining away seemingly weird code, odd choices, things new developers might think are mistakes but aren't, choices that may not on the surface appear to be important for performance, or solving edge cases etc.
Ideally, code makes usage and implementation details obvious. In practice, subtlety occurs, and comments can be useful to destroy that subtlety.
In Ruby it might be the type returned by a function - even though in C++ this would be obvious.
In C++ it might be the dividing line between when it's safe to throw exceptions, and when it's safe to mutate the object, to maintain your exception safety invariants - when in LISP everything might be immutable anyways.
In C it might be the special treatment of "-1" or validity of "NULL" as arguments, when in Rust you'd have an enum explicitly listing edge cases, or an Option<> making None s explicit.
After 20 years of professional coding, I find this one incredibly, astoundingly important do to for myself. I keep continuously writing code that I come back to later and can't figure out why I did what I did. I simply cannot remember my own choices. I cannot count the number of times I've looked at something I wrote and thought it must be a bug, or wondered how it could possibly work, only to realize later that it works, but I was too clever by half.
A big corollary to this is: strive hard to keep code simple, strive hard to avoid clever things that need a ton of commenting, strive hard to make code obvious. I still don't do it properly, but I'm working on it.
I write comments for a few different reasons, the most important being to document my thought process at the time of coding and to note other approaches that failed or why it's done in a specific way. This helps the coding process itself.
Focusing on the what and why makes it easy to skim through code that someone else (including one's past self from several months ago) wrote. While good naming could help to some extent, there is no substitute to longer comments to capture thoughts and assumptions that could be revisited in the future to learn from as well as identify opportunities for improvement.
* the code itself - I.e. function names, class names, parameter names
* test and assertion names
* comments in code
* comments in tests
* version control repository commits
* some external documentation repo like Confluence or MediaWiki
Comments are good when they describe why, not how or what. For example, good comments might be "Had to do it this way to support v2 of the API".
I hate going to documentation for an API and seeing "setFoo() - sets the foo value".
Comments that don't match the code should be flagged in code review.
I'm sort of surprised that the argument wasn't based upon "the principles of DRY"
Code never lies, comments sometimes do. - Ron Jeffries (says clojure-emacs/cider)
To make a few... - misleading function/variable names - improperly captured errors/exceptions - improperly structured locking/concurrency - code that's overly complex or naively simplistic eg naively insecure.
But, fwiw my reaction to your first line is that to announce your disagreement is to not get the sentiment of the quote. What he meant was that code is executed and comments are not. When he said "code never lies" he meant that if your code is buggy, then the bugs will be experienced by users. So your point is actually orthogonal to the point being made, and doesn't either refute or support the quote.
If you've never come across a completely horribly badly named function/type whose original purpose has completely changed, but changing the name itself is too much work.... then you're pretty lucky.
At my current job we have a type with a method called "VisitWebpage" ... its main function is to prompt for a username and password on the command line. :/
Please, just document your code and update if any code comment if needed. It's cheap and easy.
Top level comments explain the purpose behind a function or type. It can explain nuances that can't be discovered from the name (does this function append a newline at the end? Does it ignore empty values? What happens if this value is null? etc).
Aside from trivially bad comments (i.e. "add 1 to n"), comments are almost always helpful to get into the head of the person that wrote the code (even if that person was you, a few weeks ago). Comments are great at explaining why. Why this code exists at all, why it's doing things the way it is, why the hell we're removing the last character of this string, etc.
Sure, you should write clear code... but there is no way that a function name can convey all the details of the function... otherwise the name would be as long as the comment you put above it:
IndentJsonWithTheGivenIndentStringAndReturnWithoutTrailingWhitespace
If your comments are getting out of step with the code - you need better code reviewers. Code review should be a part of any professional development organization. If you're just hacking on a side project on your own... then yes, it means you have to review your own code. This is a skill, it takes practice, but one of the things you should always be looking for is "do the comments match the code?"
I would be very VERY skeptical of any experienced developer that said they don't comment their code.
Says who? Comments, like unit tests, and READMEs, need just as much attention as raw app code. As others have said here, explaining what the code is doing isn't the end goal of comments, because you can read the code for that.
I tend to use comments mainly for handoff purposes. One of my peers needs to know what I was thinking, goals, anomalies, etc., rather than how to parse syntax, which they can do already. Here's a random example:
/*
* checkReady() starts the winston logger, which is set to catch unhandled exceptions. We don't want
* to do that until both the web and SMTP listeners have started, so that they can throw errors and
* exit the app. This is important because running on well-known ports without cap_net_bind_service
* shouldn't fail silently.
*/
function checkReady() {
if (++serverCount == 2) startLogger();
}
...And whether or not I've made a bad decision here regarding startup logic is moot. :)Sometimes the lack of comments leaves you to wonder if you are looking at a bug or a deliberate design decision. When working on projects that have history, one sad thing is that usually everything else gets lost over time except code and comments. Design docs, issue trackers, emails, commit logs - all gone when companies change, code is moved around etc.
My general instruction would be that if you are thinking if you should write a comment, then write it. Writing a comment takes no time at all and it is easy to remove later. Coming up with the same insight that would be captured by one line comment may take hours when somebody else is looking the code 12 months later.
If that were an isolated incident I would blame it on the individual developer, however it's been a constant trend in the apps I've taken over through the years.
Example:
def printPlayerLineup(playerPositionByNames)
batOrder = 1
playerPositionByNames.each do |name, position|
puts "#[name} bats #{batOrder} and plays #{position}"
batOrder += 1
end
end
There are also a few tips to give about how to pick good names. For example if you expect an array of player names the argument should be called `playerNames`, not `players`. Another example is function names should always start with a verb.Also, if you end up writing comments just to specify types, consider using a statically typed language instead.
Here is an example of how the old school numerical analysts documented purpose and usage of their code (the short variable names are a historical artifact) http://www.netlib.org/lapack/explore-html/d0/db8/group__real... For the more curious, this is a Fortran subroutine that solves a linear system of equations.
That's a pretty interesting way to enforce some discipline in the commenting process, basically by adding some necessary friction into it (while also keeping it generally simple).
Curious if there are people who have tried this approach or a similar system, and how it worked out?
Reading code, it’s pretty astoundingly rare that I look at code without comments and think, man, this code is so self-explanatory! Conversly some of the best code I’ve ever read has comments that clearly explain what is expected, why the code works this way, and what other parts of the system use it.
If you comment that part, it will be much easier to read the code and avoid changing such construct. I know it should be covered by tests anyway, but it will save some time for your coworkers.
"We have to trim the last character because this third party library we're calling has a bug that doesn't handle null terminators"?
Or "we have to continue to support the old-style url for backwards compatibility reasons"
or "we're dropping down to assembly here because it's 100x as fast as the naive solution"
or even "This function ensures the returned string ends in a line return."
Alternative title: "Should I use a type system?"
Sarcasm aside: comment anything non-obvious, and make the non-obvious things as few as possible. It's always better to have two lines of overly obvious code, than to have one line of opaque code plus one line of comment.
If I have to refer to some research, a bibliographical reference, some outside documentation about data formats, or some special business rule which impacts the case I make a note. They are for asides, deeper context, and outside references.
Don't use footnotes to explain the paragraph. Use them to explain the context in which the paragraph is to be understood. Likewise, use code comments to explain the context for the code.
Many of my comments are an example record for some legacy data format. I don't write a comment for every line of the parsing routine. I give the example record and the code. Many are also notes about an RFC or standard, down to the paragraph, and where my implementation ignores some obscurity in that or which way I interpret some ambiguity in it. Why that standard was chosen rather than a competing standard, though, is often more suitable for the developer doc / README rather than in the comments themselves.
This can be very subjective, but code complexity metrics can help identify problem areas. I find that areas with high complexity often benefit from refactoring into smaller pieces making it more readable and self explanatory.
If you can't structure your code to explain itself, perhaps commenting isn't such a bad idea, at least it would be a record of your thoughts at the time, until someone else comes a long and hopefully cleans it up.
I can just about accept that in a sufficiently descriptive language that what the code is doing can possibly be made clear (in practice for things like embedded C, this isn't actually true). But no code, however well named, can ever tell you WHY it is doing what it is doing. Those code comments are invaluable.
They can range from the trivial explanation of a corner case bug as the rationale for an otherwise pointless looking bit of error checking, to discussing a system requirement when explaining the implementation choice for a whole module.
// gets bear count
function getNumber() ...
is not as good as just
function getBearCount() ...
Places where comments are still useful, IMHO:
- complex or clever code; e.g. when I use shift for division by 2, that tends to confuse some coders, or regular expressions in javascript (for some reason JS devs seem scared by regexp)
- strange requirements or bugs or other reason to do something in a weird way
- other places why it may not be clear what I am trying to achieve
I've found I've never had to use a Regex in Javascript yet. Also I don't think anyone enjoys reading Regex. Writing it is a lot easier. :)
Reading `/2` or ` * 2` is more intuitive than `<< 1` or `>>> 1`. Although I learned a new code obfuscation technique! ;) [0]
Testing 2^39 and bit shifting is negligibly faster. At lower values (2^4) it is equivalent. For any multiplication/division by a higher power of 2 (2^2, 2^3, 2^4) they become equivalent in speed.
549755813888 * 2 x 1,526,678,336 ops/sec ±0.67% (97 runs sampled)
549755813888 << 1 x 1,562,645,566 ops/sec ±0.26% (99 runs sampled)
549755813888 * 16 x 1,552,125,291 ops/sec ±0.33% (100 runs sampled)
549755813888 << 4 x 1,530,867,164 ops/sec ±0.35% (98 runs sampled)
This seems like a case of "being too clever" by trying to optimize something that the compiler can optimize itself.2. They should describe the purpose of the code in general not the quirks in the code
3. The exception rule is when the code can't be self-explanatory. Hacks are undesirable, but in real life you have implement them sometimes anyway - then comments are necessary
4. Docstrings in everything are wrong, the code itself is a documentation.
If you take the time to refactor a function it takes no time at all to edit the block comment above the code.
Lately I've been caring less about how long the name of a function may be, and I've found it much more helpful when looking back at code I've previously written.
Put in a bug tracker number, description, and your name, and end up with a comment much larger than the code actual change. Also comment the end of the change.
DO NOT REMOVE! Almost all web analytics tracking tags have these. Do not remove? I do that all the time. Those messages are probably there for brain dead people, but it doesn't stop them either.
DRY: DRY in the sense where "I have three nested ifs, but to avoid I have to compare against this variable three times so my code now is simpler. RIGHT?"