Hacker News new | ask | show | jobs
by rimantas 5050 days ago

  “Don’t comment bad code—rewrite it.”
  —Brian W. Kernighan and P. J. Plaugher
Is that senior enough for you?

  > Anyone who advocates against comments is justifying
  > laziness, and they're wrong
No, they are actually advocating to put more effort in thinking about stuff: how you name your functions/methods/whatever, how do you name your arguments/parameters, how do you write the code itself.

To anyone interested I recommend to get a copy of "Clean Code" and read the relevant chapter. IIRC "Code Complete" mostly agrees.

4 comments

> Is that senior enough for you?

No. Have you read 70s and 80s C code? Tried tracing through the original UNIX kernel sources? Tried working with them?

To understand all the invariants of one small aspect of the system quite often requires tracing through the whole system until you get to a well-documented input/output module point (via comments, man pages, or otherwise).

Also, the quote (aside from it being out of context) says to not comment bad code.

> No, they are actually advocating to put more effort in thinking about stuff: how you name your functions/methods/whatever, how do you name your arguments/parameters, how do you write the code itself.

You can't define all the invariants -- or summarize for readability -- in pure code.

> No. Have you read 70s and 80s C code? Tried tracing through the original UNIX kernel sources? Tried working with them?

Yes. It's some of the easiest to understand code I've read. For example, http://unixarchive.cn-k.de/PDP-11/Trees/V6/usr/sys/ken/slp.c

They're actually quite decently commented. The functions describe what they do clearly, and the bodies show how they do it tersely, with comments around the sticky bits.

Have you read through the original Unix kernel sources? Claiming that they're uncommented and difficult to work with is surprising. (On the other hand, the directory structure could be better.)

Without tracing the backing kernel structures and the code that relies on them, please describe why sleep(chan, pri) works, and as a maintainer, what I need to watch out for when modifying that code.

What does swtch() do? What does issig() do? Does that mean it's checking for a signal during sleep? What signals could be generated? Under what circumstances do I need to check for those signals? Are there any race conditions? Does ordering matter? What happens if I move the call to issig?

Beyond the invariants, this code is NOT READABLE. I can't just glance at the comments for an atomic unit of 4-5 LoC and see what it does -- I have to examine the code in depth, running the logic in my head, and explore the workings that way.

Reading code without comments is like tracing out a circuit without a schematic or documentation. First you have to manually establish the what, and only then can you even start to spend your time determining the why.

I work on modern BSD code. It's better than this old stuff, and I still have to dig to figure out how/why things are supposed to work. It's a headache compared to properly commented and documented code, where I can just skim standalone units and know what they do without having to trace everything myself.

Of course you need context to understand code. You can't get away from that without essentially translating the rest of the code into prose and attaching it to each line. At which point there are enough comments that you need context to figure out which parts of them you care about, reading them becomes a chore, and they essentially become noise. I've seen codebases with insane levels of commenting. I found myself ignoring the comments and tracing through the code.

If the model is simple and the code is clear, learning the context becomes easy, and it fits into your head. Following code becomes easy.

> Of course you need context to understand code.

Comments decrease the amount of code you must personally read and understand, and define invariants that can't be expressed purely through the code.

> At which point there are enough comments that you need context to figure out which parts of them you care about, reading them becomes a chore, and they essentially become noise.

I've never seen this outside of contrived examples from lazy developers that think they're too smart to need to comment their code.

> If the model is simple and the code is clear, learning the context becomes easy, and it fits into your head.

In other words, you must trace the entire system to understand it and then fit it into your head. This is not advantageous to maintainers.

> you must trace the entire system

No, just the part you care about. You do need a high level mental model of the system. I've never seen a system where this is not the case, regardless of the number of comments. Even literate programming -- or at least, the examples of it that I've seen -- suffered from this. (Amusingly, I found literate programming examples were often easier to understand by mostly ignoring the prose and looking at the code.)

That code you linked has lots of comments containing lots of information. How is this an example of how Senior Programmers are against comments?
Maybe I haven't read K&R carefully enough but how can you have a function declaration like

    sleep(chan, pri)
without any data types?
Because the default datatype is int:-

  $ cat z.c
  foo( a, b )
  {
          return( a+b );
  }
  
  main( void )
  {
          return( foo( 3, 4 ) );
  }
  $ gcc z.c
  $ ./a.out
  $ echo $?
  7
Since you have already dismissed a well thought response, let's try irony instead:

"When you have spoiled ingredients, dispose 'em. Do not try to cover the bad flavor with condiments." - Famous Master Chef.

"You see? Master Chef does not like condiments. They take away the natural flavor of the food and anyone who uses them is an idiot who never will be a true cook". - Zealot Wannabe.

Actually the people I have met who tend to be most against documenting what code does with comments tend to have the best commented codebases I have ever seen.
You never specified that your backslash referred exclusively to comments that document what the code does. This kind of comments are in most cases the result of bad habits taught by introductory programming books and instructors alike, with possible one exception [1].

But comments are incredibly useful to document why code exists in the first place, what are the assumptions that must hold for it to behave as expected (including but not limited to preconditions, invariants and post-conditions), and possibly how to use it (if you are using some utility like javadoc to generate other types of documentation from source code).

[1] The exception I am thinking about is that in real life you cannot always deliver the best quality possible in your projects. You have to interact with horrible systems, make ugly tradeoffs and meet deadlines with limited resources. Things get convoluted from times to times, so the best you can hope for is to leave thoughtful comments explaining how some specially hairy component works. The maintainers of that software (including a potential future version of yourself) will be very grateful for this.

Agreed on this point. The idea is that the comments should have something to say apart from the code. You don't put a footnote in a book to repeat what you just said. You put one in to add a reference to something else, explain a caveat, or otherwise say something useful out-of-band.

In general, in my experience, the people who are most hostile to willy-nilly comments have some of the best commented code. They see the code as written both for the computer and the programmer, and the comments are thus either interface promises, or are footnotes. Most of the people like this I have worked with tend to produce extraordinarily readable code which contains a good number of comments which should be there. But the worst codebases I have worked with hands-down are full of comments.

As for your exception, I agree. I think it's worth flagging such comments however so that the reader immediately knows that this is a special clarification.

The last time I described what my code did, I was using Perl 5.6 or something and was trying to do a method call to a fixed name in a variable package and was having a horrible time. I ended up, I think, using the symbol table directly and the syntax was worse than hairy. It was downright misleading. So I added a comment something like:

# HELP! I can't find a better way to write this. The syntax is .... Anyone have any suggestions?

If you understand you are writing for a human audience and that your comments will be read only if generally useful, then the this leads to both code clarity and comment clarity. It may not always be possible to maintain and hence one would add comments explaining tradeoffs or flagging a section as unclear (and possibly explaining it). But these are avoided as best one can.

> “Don’t comment bad code—rewrite it.”

That's advocating against bad code, and specifically the fairly widespread practice of commenting what it does rather than fixing it.

It's not a blanket statement against comments in general.

Kernigan is absolutely right here btw.

There are so many problems with trying to make up for unclear code in comments, that's a real losing battle. I recognize that it may be worth breaking that rule sometimes, but then it is worth noting that, and flagging it so that other programmers can see and fix it. A comment like "#FIXME: This code is unclear: What it does is...." is perfectly acceptable.

Comments are for collaboration. You do NOT want to make them even appear useful for debugging.