I think "why" comments are the most useful, but "what" comments are a bit undervalued. A few types of "what" comments are, I find, very useful:
1. Comments that are effectively headers:
# If the user is foobar, do thing
user = User.find(current_user_id)
user.preload_bizbaz!(cache: false)
is_foobar = user.bizbaz.foobar.status == "yes"
if (is_foobar) { do_thing(user) }
Yes, you can read the 4 lines of code to see the "what' - the comment is duplicative. But when I'm skimming through a large codebase trying to find or understand something, these headers can be invaluable.
2. Comments on dense code
# Matches any email like foo@bar.com (only .com, .net, .org email addresses)
return email.match(/^.*@.*\.(com|net|org)$/)
Yes I can that regex, but I can read that comment a lot faster.
I love header comments, but many people fail to get their usefulness, and I get the "good code does not need comments" mantra recited to me pretty often.
Here is the thing: Header comments are not really about explaining their following code. They are about reducing the lines you need to read to navigate through the code by a factor of 5 to 10. Huge time-saver, and helps a ton newcomers to become productive quickly.
// The following block should have the same
// result as this (simpler) code:
// <code>
// but for <reason> this version is better
This is great for things like opaque optimizations, things that mimic a library function except for one critical difference, blocks that become really convoluted to deal with special cases, and similar.
> I think "why" comments are the most useful, but "what" comments are a bit undervalued. A few types of "what" comments are, I find, very useful:
I agree. However, "what" comments need a little more skill and judgement to know what to write and what to leave out.
Having a terrible memory helps develop that skill, because you kind of get a sense of what you'll want explained to you again in six months and what's hard to decode.
> And the latter is a perfect example of what goes wrong, when someone adds "gov" to the regex but doesn't notice the comment to update it.
That always gets trotted out, but it's sort of like "don't write code unless you can guarantee the code won't have any bugs, so never write any code."
The trick is write code and comments, but be a little skeptical of both. If you're disciplined (especially with commit messages), it's usually pretty easy to figure out a mistake or omission after the fact.
I am 99% in agreement with everything you said, so of course I'm going to focus on the 1%! If you have a 4 line stanza that needs a comment to explain what it's doing then I'd suggest that needs breaking out into a function so that your code then becomes `if (is_foobar?(current_user_id)) {do_thing()}`. Just as readable with no comments needed.
There are definitely places where that's hard or impossible and your regex code is a good example of that. I write a fair amount of C at the moment and you can have some pointer arithmetic that's not even that complicated, but a comment on it makes scanning through the function much simpler.
> If you have a 4 line stanza that needs a comment to explain what it's doing then I'd suggest that needs breaking out into a function
I'm mostly in agreement, so I'm going to focus on my disagreement too! ;)
This view is pretty common in the ruby community. So much so that I think they take it too far at times. I sometimes find myself reading a class that could have been a single 24-line method but is instead one method with method calls, each of which calls 0-2 more methods.
This style is good for when I'm trying to quickly understand what that class is supposed to do - I just read the top-level method that looks like:
But it's terrible when I need to understand what that function is actually doing - eg to debug it or to find some underlying function call I'm looking for. I have to bounce all over the file to mentally reconstruct a linear sequence of code which could have just been one function with some headers.
Of course, this style is a reaction to impenetrable 500-line functions which are also terrible. I'd definitely prefer many small functions to that! I think it's a matter of judgement and experience to know whether some code is better as small stanzas with comments or small functions.
For your first example, use a method with a fitting name.
Second one is not a good example, because I think it's a very common pattern and email.match with com|net|org provides enough context by itself. It's just bloat imo.
1. Comments that are effectively headers:
Yes, you can read the 4 lines of code to see the "what' - the comment is duplicative. But when I'm skimming through a large codebase trying to find or understand something, these headers can be invaluable.2. Comments on dense code
Yes I can that regex, but I can read that comment a lot faster.