“Don’t comment bad code—rewrite it.”
—Brian W. Kernighan and P. J. Plaugher
> Anyone who advocates against comments is justifying
> laziness, and they're wrong
To anyone interested I recommend to get a copy of "Clean Code" and read the relevant chapter. IIRC "Code Complete" mostly agrees.
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.
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.)
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.
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.
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.
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 is extremely time-consuming to build without code comments and documentation, regardless of how "literate" the code is, because code alone can not express sufficiently detailed invariants, and simple logical/atomic operations involve a non-trivial amounts of code. (especially when writing in C).
There's almost nothing I hate more than inheriting a complex uncommented code base and spending hours or days tracing out the code to build a high-level mental model, when instead, with reasonable comments, I could have had that model nearly immediately.
Comments embedded in source code are singularly unsuited to giving the sort of interconnection of concepts that allows you to quickly and efficiently understand build a model of the system. They are a poor substitute for real documentation.
Something like this should always be present to describe the overarching structure of the system: ftp://gcc.gnu.org/pub/gcc/summit/2003/GENERIC%20and%20GIMPLE.pdf
Incidentally, I'm not sure if you're familiar with literate programming. That's where the code is almost an afterthought to the comments. This is an example of a literate program: http://tug.org/texlive/devsrc/Build/source/texk/web2c/tex.we.... You may be familiar with it -- it's tex, the core engine used by LaTeX. Compiled to PDF, the source looks like this: http://eigenstate.org/tmp/tex.pdf.
Good comments are golden, but bad comments (those that tell you what the code is doing or duplicate coding logic in the comments) are worse than useless because they make it harder to spot and read the good comments.
I think the only thing worse than an uncommented codebase is a codebase full of comments that tell you what the code is trying to do in full detail, every few lines.....
The two are hardly correlated.
Have you ever worked with some of the Mac OS X code written by poorer teams? For instance, the security framework? The internals of that code is a disaster at best, and yet, the core OS enjoys tremendous success and market share.
> Thus developers can get on with their job and be more productive when they don't have to duplicate their efforts for dubious benefit.
How do you determine the invariants of your APIs when writing code against a module? I don't trust arguments that boil down to "we're much too important to waste our time documenting, code is perfectly expressive!"
It's not. You're just wasting your time somewhere else, in little tiny increments, every time you have to trace code a few steps down just to figure out what it probably is supposed to do.
Or, sometimes in BIG increments, when somebody new has to learn the code base.
How is that relevant? OSX has at best around 10% global market share? I'm talking market dominance here.
> How do you determine the invariants of your APIs when writing code against a module?
We flick through the well-documented code just as you would largely ignore the code and flick through well-documented comments. Here is a simple example for you:
public class EntitySynchroniser : IEntitySynchroniser
public EntitySynchroniser(BusinessObjectFactory factory, IDirectorySearcher directorySearcher)
this.factory = factory;
this.directorySearcher = directorySearcher;
If readers want to know what this API is and what it can do they need only look to the interface, or the implementation of it's methods in the class. Each method explains what it does by maintaining the same level of abstraction within the method. Like:
public void MethodA()
// do less high-level things
> You're just wasting your time somewhere else, in little tiny increments, every time you have to trace code a few steps down just to figure out what it probably is supposed to do.
If I needed to figure out why code wasn't working the way it should what's to say a comment would be more forthcoming in explaining the reasons for the defect? Surely if MethodA did "thing A" but was really doing "thing B" the comment would tell me "thing A", therefore I'd be forced to examine the code further anyway, only I'd be hampered by the deceitful comment also? This is the nature of a defect - something that operates outside the documented behaviour of the system or module.
Not to mention that your stated opinion is that comments should explain the inner workings of things so that consumers can be well informed. This has the potential for exponential maintenance as really low level changes are made. Imagine that you change the conditions under which data access-level exceptions are raised. If anything that ever touched your data source explained what happened in exceptional circumstances you'd have to change hundreds or thousands of comments, or face the sort of comment rot I mentioned earlier. This is the real time waster!
> ...when somebody new has to learn the code base.
This is always going to be the case. Comments don't make this task any easier than a well structured codebase. A well structured codebase comes from developers making the conscious decision that any reliance on the crutch of a comment is a failure to write proper self-documenting code. A well-structured self-documenting codebase by definition requires no comments (except for the "why" not the "how", which I fully support doing by the way).
Fine, I'm familiar with OS X, but I'm sure there's equivalent stupidity in Windows.
> The arguments here are invariant - they must not be null. I don't need a comment that may or may not be written in precisely the same format between 100 developers maintaining the codebase. I simply look for the one call to Argument.NotNull that all developers use in this case. The code is MUCH more readable than if the constructor had a comment explaining that each should not be null, mixed in with explaining what each should do.
No, it's not much more readable, because if properly commented, I WOULDN'T HAVE TO READ THIS CODE AT ALL. Instead, my IDE or documentation browser would tell me, inline, exactly what I needed to know.
> If readers want to know what this API is and what it can do they need only look to the interface, or the implementation of it's methods in the class.
If you have to look at code's implementation, you've failed. Why isn't that code a black box to me? Why do I care at all how it's implemented?
Why on earth would I want to waste time doing that instead of instant access to high-level API documentation?
Moreover, it's a contrived example, because nullable/not-nullable is the least of an API.
> Not to mention that your stated opinion is that comments should explain the inner workings of things so that consumers can be well informed. This has the potential for exponential maintenance as really low level changes are made.
No, my stated opinion is that comments that are externally visible should document externally relevant invariants.
Comments that are internally visible should document internally relevant invariants (if the code does not adequately express those, as it often does not).
> A well structured codebase comes from developers making the conscious decision that any reliance on the crutch of a comment is a failure to write proper self-documenting code.
A well-structured code base comes from writing good code. Comments are part of writing good code. Self-documenting code isn't fully documented code, unless it's literally a literate programming language. Claiming otherwise is just an excuse for you to be lazy and not write comments under the misguided auspices of being much too smart to need them.
I'd suggest you stop trying to tell the world that senior developers must conform to your narrow views (narrow, by the sheer size of the response against your point of view here). Calling people things like "lazy" and insinuating they inflate their own abilities simply because they don't do what you think they should do is a pretty trollish thing to do. You obviously missed the first point in the original link.
$ cat z.c
foo( a, b )
return( a+b );
main( void )
return( foo( 3, 4 ) );
$ gcc z.c
$ echo $?
"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.
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).
 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.
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.
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.
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.