I'm a junior/trainee developer and I was advised that comments should explain why something is happening, not what is happening. The what should be self explanatory by reading the code, but knowing why something is being done is useful when you, or someone else, has to look at it again in the future.
This is the advice I give the junior devs I mentor. Write your code clearly and for other developers to read (yes that one-liner is clever, but refactor it so someone who just worked a 14 emergency deployment can understand it). Comments are for the why - quirky business rules, environment-specific issues, explaining an algorithm. Etc.
And a comment explaining why is especially useful when the code is a bit more dense and hard to follow - which is unavoidable at times.
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'.
on top of that the why can extend as to why this specific implementation route was chosen. Some algorithms are less efficient in a general case, but may be much more suitable to the specific case at hand. Things that were tried and proven not to work even though they seem beneficial at first glance.
I think this is one of those things that is more about wisdom than anything else. You get a sense of what to comment over time and experience.
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.
Some high level "What" comments are useful though even if just for yourself, especially for code that can't be easily broken down into modular units. Even if the code itself is very clean, it's still faster to read that one line comment which summarizes it succinctly in plain English.
Given we are a small team and know each others typical structures. It also helps that i only did this in a MVC environment, so structure was given mostly.
I dont want to link to company applications honestly, and my personal ones are way to messy in terms of inline documentation anyway.
Visual Studio Pro & up has a great feature that puts a tiny snippet of text above each class & method that says the last author, how many authors & how many changes have been done on that specific class or method. You can hover over this text and see a box with a scroll bar that shows you the commits & comments that changed the class or method.
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.
I assume every damn editor out there has a plugin that makes this a complete non issue. I spend most of my time in a terminal anyway and know my way around it, i prefer it by far to comments, also because of the metadata like dates and authors which rarely is found in comments.
Isn't a short comment a much quicker method to get why something has been done that way instead of having to check git log? Also, if you rely on git log for that, don't commit messages become unnecessarily long and detailed?
no, that rarely happens. There are plugins where you can run git blame within your text editor by marking text. It is like you have a comment but without making the code more messy as it only shows with a "click".
Another point is that people tend to write awful comments anyway.
>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.
Commits should be long and detailed, though the details for the commit log are for a different purpose. In the commit logs I want to know why the change was developed -- what issue it fixed, what feature request it implements. I want the code comments to explain the logic of a large chunk of code, at a higher level than just reading line by line.
Thats a bit much to suspect based on a single sentence don't you think?
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.
If you would work in the company i worked (e-gov in switzerland) comments are strongly discouraged (except as said if you do something stupid and you expect the reviewer to notice and give some inputs).
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.
This is the main reason. I also find a few other instances where it's useful:
* 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
If possible, document invariants as part of the code, not as a comment. Make it as hard as possible to misuse the thing. People not only don't read manuals, they also don't read comments. Which isn't to say you shouldn't comment your code.
I wouldn't use a comment in that situation either - I don't think a comment hurts, but I'd rather the code failed in an obvious way if I tried to use it incorrectly.
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".
It is also sometimes useful to determine places that should be commented not only from structure perspective, but also from call-stack. You can save few minutes yourself by explaining how this innocent assignment influences behavior several levels down there and vice versa, and that it was planned.
One of the best ideas I saw here on HN was someone saying that they will mentor their employees to add comments to their code exactly under one condition: you add a comment above it explaining why the comment below needs to exist.
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?
This is a great point, code is often very messy, and often misleading the way it's written, and often has bugs.
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.
Easy to say. Hard to implement consistently. It takes only one failure for the whole thing to fall apart; once it's fallen apart, every comment you run across becomes suspect, making the value of the comments a net negative.
The thing is, even code can be suspect. Does ParseCommand just parse the command, or does it also run the command?
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. :/
Not mentioned in this article is the effect that dynamic typing vs. static typing has on how you comment. It is common practice in Clojure, for example, to heavily document every function, because it is a dynamic language and there are no other obvious ways to indicate the types of arguments or the function's return value (though that is gradually changing in the language, but not entirely). This practice is so encouraged and standard in Clojure that all functions can be defined with language-standard documentation strings that become a part of the function definition, which can then be looked up at the REPL.
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.
+1. It's inevitable that we have to do non-obvious and quirky things, slightly hacky sometimes, or have some complex algorithsm, and a couple of lines here and there can really help.
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.
> 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.
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.
Everything is a public facing API. The private function you wrote is public to the person who is fixing a bug / adding a feature to the code (which might still be you, a year from now).
Right, but the person fixing the bug or adding the feature is going to be reading the codebase. I don't want to have to read a libraries codebase just because I want to use it's public funcitons.
How to create readable code that explains itself should have more focus. It's not just about naming classes, methods and variables, but also about structuring your code. It's quite possible to create a method with the perfect name that is over nine thousand lines long and difficult to understand.
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.
Just to echo what has already been brought up here, sometimes it's not the what that is important, but the why. Reading the code is unlikely to explain the why for quite a few complex things.
One more justified case for commenting is in my opinion when you have to work around some bug or specific behavior of 3rd party library by doing unusual construct.
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.
One more justified case for commenting is in my opinion when you have to work around some bug or specific behavior of 3rd party library by doing unusual construct.
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.
It would be really cool if whether the method takes an array or a hash table could somehow be part of the code itself, and if the function is updated but not the callsite an error is shown?
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.
Once I had to work with a well written but undocumented NodeJS application (in ES5, dynamically typed). I didn't know what to expect from any function, neither the structure of the data. Suppose you have a function that returns an Employee, but you do not know how the Employee is defined, so you need to look on the database schema to know the basic structure -- but when you use it you see that there is data that wasn't in the initial definition! The Employee is mutable and some data was added in some place along the app. Good look finding the actual expected output! This is easily fixed by adding some comments about the expected data returned by the function.
Please, just document your code and update if any code comment if needed. It's cheap and easy.
Yikes. That's one of the things I like least about dynamic languages. Being able to add properties onto an object after it is initially defined willynilly is a disaster for trying to understand what is going on.
While I understand that comments can make it more difficult to understand code, I have frequently seen this advice taken too far. What is clear to the writer may not be clear to readers so they may avoid commenting complex code they have been working in for awhile.
It's curious that the answer to "people don't have the discipline to update comments" is "develop the discipline to code in a way that avoids comments".
The point is not whether to comment or not - it is just to do whatever it takes to make what is happening on every level more understandable whenever there's the slightest doubt that it might appear unclear to anyone else (including the future you). It doesn't matter if it requires rewriting the function, adding a link to more in-depth documentation or populating the code with ASCII art of wild flowers - just make sure that the next person that has to understand the code won't curse you...
I've felt that business requirements tend to be the sort of thing that benefit from code comments. Because too often you don't have time to create the whole machination that is required to fulfil some arbitrary business rule.
At a minimum, unless it is a trivial piece of code (like a few lines), you should comment about the purpose of a function and usage.
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.
I find the argument not very strong. While stating that comments will become outdated, the author also states that he uses comments for code organization. There's nothing inherent about code organization comments that would somehow make them less likely to become outdated or not used at all (header styles wouldn't be prevented from going under some other comment heading by default, to take the example the author stated).
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.
I think the author missed the opportunity to show how choosing better identifiers for his example would have eliminated the need for comments immediately. Also notice how his comments were actually bad from the beginning: it said the method returns something even though it doesn't.
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.
What am I allowed to pass into this function? a hash? a list? To me, player position by names sounds like a hash of name:position. Your code assumes the input is in bat order, but doesn't say that anywhere (and how does that work with a hash?). This is why you need comments.
This may sound tedious and strange, but I've learned to comment nearly every line I write. I think the cognitive load while skimming is much lower, but MUCH more importantly, the process of writing them is a very valuable perspective shift. It forces me to look at a block of code more holistically, and as a result I tend to catch most of my bugs while writing comments.
95 comments
[ 1.7 ms ] story [ 909 ms ] threadIMHO, 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).
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".
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?
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. :/
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.
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.
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.
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.
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.
* 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".
"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."
Please, just document your code and update if any code comment if needed. It's cheap and easy.
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.
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.
Example:
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.