197 comments

[ 3.2 ms ] story [ 263 ms ] thread
I've always treated comments as code smells. Not necessarily something bad, but something that at least suggests the possibility of suboptimal code.

One of the best cases for comments IMO is documenting an unexpected behaviour on the part of a third-party API. But even then, correct exception / error-handling code can obviate the need for comments in many cases.

If I'm reading code (from an experienced programmer) and I see a comment, I immediately pay attention, because Here Be Dragons.

The situation must be differentiated by language/environment. The suggestions for Haskell are certainly not bad. They hold, too, for many systems programming.

For scientific coding, comments should align with the underlying theory for the code: “This implements matrix transposition with regard to ... as defined by ...”, so that next generations can align code with papers better.

And when you’re in a wacky environment like the PHP runtime or coding for a moving target like the browser, comments might be indispensable to explain one or the other really strange way of doing things, where you simply have no other choice. Look at the [jQuery source code](https://github.com/jquery/jquery/tree/master/src), where they comment excessively, which browser quirk they address with which work-around.

> For scientific coding, comments should align with the underlying theory for the code

100x this. Scientific software should be held to a different set of standards than non-scientific software, primarily because you can probably not assume that your reading is familiar with the underlying domain.

> Scientific software should be held to a different set of standards than non-scientific software, primarily because you can probably not assume that your reading is familiar with the underlying domain.

As someone who works as a programmer and system analyst dealing with code in a non-scientific business domain where I've also worked on the domain side, I don't think that this separates scientific code from any other codes. Programmers often disdain domain knowledge beyond that which they already have found to be immediately relevant. Which is perfectly understandable -- there's a reason they chose to specialize in programming rather than as domain experts in whatever domain.

I thought through this some, and your comment resonates -- it's not right to set aside scientific code from other code with a complicated domain.

But I think complicated program segments related to business practices etc. also deserves comments, even just "see spec xyz" or "see section 1.2.3 of code xyz" (similar to how you might say "See Smith et al. '14" in a scientific setting)

One case of unexpected behavior which is best described in comments is when the simple and obvious solution to the problem is wrong, and has already been discarded.

(Preferably the reasons for discarding the simple solution should be provided as well, as circumstances may change.)

I often have to go commando scripting small tasks to deliver things within the week, and the only comments I couldn't live without are TODOs to mark things that are hacked together. If time is limited I'd always rather write cleaner code than more commented code.
Remember your gas mask if you ever check out literate programming...
I agree. Comments sometimes make it difficult to go through the source code. That's why I always loved Java naming convention that suggests variables and method names to be self-explanatory.
> I repeat: Try hard - very hard - preferably repeatedly - to remove unexpected behaviour from your program. Comments can never fix unexpected behaviour.

This is golden!

The article correctly advices against commenting the obvious. I think it is often practice by novice programmers to assure themselves about what the language expression actually does.

What the article omits is the suggestion of commenting the right way, i.e. adding reasoning or the description of the high level logic behind the code.

Yes, obviously the examples given in the link are bad style of comments. But sometimes you need to explain the reasons behind the (Haskell) equations, just like one would do in a Math paper. So there's a use case for the literate Haskell files *.lhs (http://www.haskell.org/haskellwiki/Literate_programming).
Comment only magical code, but don't write magical code.
(comment deleted)
The article is spot on. Comment as last resort.
I was always told that if someone couldn't tell what your code was doing by glancing at it, you'd done it wrong and should re-write it.

I know that's absurd in practice, we don't always have the time but I've always used comments as a last resort.

If I need to comment code to make it understandable at a glance, so be it but I'd rather avoid them all together and rewrite until it's clear enough without them.

I disagree with that sentiment.

Using Python or Perl it is easy to go from a for loop to a map or list comprehension. For many less experienced programmers it will make it less readable and more difficult to comprehend. Using a more functional approach will usually lead to less side effects and silly bugs, so I prefer to code this way, and add a comment to explain what the line is doing if it is not obvious.

I want comments to give me a short-cut to reading a long block of code, and I want comments to give me a basic method of analyzing the code for correctness. The thumb-rule of documenting "why" rather than "how" seems to apply.

I shouldn't have to read code in detail to understand it, unless it is broken and I am fixing it. Comments should inform me on the broad strokes of the code.

I totally agree with this. I like to put a bigger comment block at the top of my source files explaining the overall concepts and data structures used and then put few actual comments in the code. Instead I think about my variables and function names and make them talk for them-self. Commenting each and every element of your code will just make people (possibly yourself) curse at you when debugging your code and realizing that the comment was rendered obsolete 15 iterations prior and the code does something entirely different.
I generally sympathise with your sentiment - I think this jives fairly well with comments talking about 'why' rather that 'what'. I do favour function-level comments quite a bit for more complex functions.

That said, I think some of the commenters in this thread should spend time maintaining a MLOC+ sized code base before dismissing comments as 'code smell'. Even in well-written code, if you're a maintenance programmer who is unfamiliar with a particular functional area, a few comments talking about the overall purpose of the code and why it works the way it does can save you enormous amounts of time.

Finally, if people are letting comments go out of date, IMO they have a quality issue. Either the comments are useless and should be removed, or they're useful and should be kept up to date. If your developers are letting useful comment areas go out of date, it should get caught by code review.

This submission needs to have a different title. It's not very clear whether the submitter is being genuinely surprised or sarcastic.
I would say, never assume sarcasm is in play unless it's absolutely clear. So I think this title is fine.

If the OP meant to be sarcastic, that's just like me saying "yes" when I mean "no"---my mistake, not yours, and you can't be blamed for assuming I meant what I said.

This is not convincing to me because the examples are trivial:

    -- swap the elements of a pair
    swap :: (a,b) -> (b,a)
Yes this is redundant.

    let b=a+1   -- add one to 'a'
Yes this is also redundant

Does it mean that every piece of code can be expressed as clearly as in a one-line comment in natural language? I don't think so.

The argument is not to never use comments, but rather to avoid bad comments.
I realize this, but the article doesn't provide any clear definition of what actually is a bad comment. It only gives trivial examples of bad comments such as "increment a by one".

Since I don't think anyone here would argue that "increment a by one" is a useful comment, the part about duplicate/obvious comments isn't adding much to the discussion about the usefulness of comments.

Nevertheless, it's true that comments cannot be checked by the compiler, and that's a more interesting point, I think.

But you see, nobody on the internet has ever offered up examples of good comments before, at least that I can find. So if you say these comments are bad, but there exists good comments, why not provide examples of good comments to make your argument stronger?
What about the Code Complete examples posted somewhere on this thread? ("above", at the moment)?

What about checkable specifications together with a comment explaining the formula, particularly for anything with a nice physical intuition? This kind-of addresses the out-of-date comment problem.

Another example which came to mind is a Lamport comment about some sort of layout-related thing, I can't remember specifics. The comment gives a really good intuitive feel for why his code produces a nice-looking layout. Without the physical intuition provided by the comment, the code is pretty difficult to grok. I can't find it, so I really hope I'm not making this up...

edit: 2nd par

I have never seen comments like these except during arguments that good code doesn't need comments.
To rephrase - code makes comments understandable?
Comments say what your code does, your code says how you do it. The swap example is trivial, but for most functions it is good to add an API comment, because how you use the function shouldn't depend on how it's implemented, but what it should do, described in the comment. That way you can change your implementation as long as you don't change the contract. In other words, changing how your code does something shouldn't therefore change what it does. And this last part is specified in the comment.
Well, this is Haskell we're talking about. Between the name, type signature and the fact that most functions are pure (so, no side-effects to describe), it's often obvious what they do.
Like

  (<+>) :: Monoid m => m -> m -> m
  (^?) :: s -> Getting (First a) s a -> Maybe a
As a Haskell beginner I didn't find it to be a particularly self-documenting language. Between the use of custom operators and point-free style you can write a lot of code without naming anything to give a hint about what you're doing.
So as another Haskell beginner, let me take a stab at the first one.

  * Return the first parameter
  * Return the second parameter
  * Perform param1 `mappend` param2
  * Perform param1 `mappend` param2
  * Return the mempty value for the Monoid m
The first two are unlikely to be correct, since if all they were doing was returning a particular parameter, then there is no reason to have the Monoid type constraint. The last one similarly makes no sense, since it's a function that is identical to `mempty` irrespective of it's parameters.

The order of operations however should be documented. I'm almost certain that the implementation is the third function, but a one line comment stating that could possibly be useful.

All of my above reasoning was predicated on an understanding of Monoids. So while I'm not sure the right thing to document is the function, I do think an explanation of `Monoids` should be documented in `Data.Monoid`.

PS - Where is that first function defined? I've used a similar operator defined in XMonad, but if I remember right that was defined over Arrows. Also is that second function from Data.Lens?

I assume line 4 was meant to be:

    * Perform param2 `mappend` param1
I'd be a little surprised if it was the third option, simply because that's already spelled <>. Hoogle doesn't turn up a definition with that signature, though.
Regarding the second, that sounds like lens. First of all, stay away from lens as a Haskell beginner :-P

But let's take a swing at it. We start with something of type (s). At the very end, we're left with something of type (Maybe a). Since we know nothing about the types (s) or (a), we need something to relate these to each other if the function is going to produce a (Maybe a) for us (unless it just always gives us Nothing).

There's a lot going on in that second argument, but we can clearly see that it's some type parameterized by (s) and (a), so it provides that connection. It "tells us how to get an (a) out of an (s) in a way that might fail" - which intuition is additionally helped along by the fact that the type so parameterized is called Getting.

There's a little more going on, and for that you'll need to dive into the (extensive) documentation for lens. One thing that is not going on is any side effects though. The operator section (^? foo) will take some (s) and turn it into some (Maybe a) based only on the information contained in that (s) and foo.

(comment deleted)
(comment deleted)
I think the saying is that comments explain why the code does something.
As another commenter said above, comments shouldn't say "what" your code does, but "why" you do it,... when you need an explanation. There's no better comment of what code does that code itself.
Leo Brodie says in "Thinking Forth" in the style section: "The most-accurate, least-expensive documentation is self-documenting code". I am sure there are other prior examples.
I'm a big believer in function level comments in code, in a sort of doxygen-ish style (I write mostly C).

It allows you to document the intended inputs and outputs of the function and state its purpose. This increases maintainability and reusability.

Functions themselves should be short and written as a sequence of logical steps.

I'm also a big fan of doing things right rather than just hacking until it works, which seems to put me in a minority.

I also like to add doxygen headers to functions, but have stopped adding the inputs and outputs. Refactorings causes the doxygen to go out of sync with the code.

Currently I only do the following:

  /**@fn    foobar
   * @brief Does foo
   */
-edit formatting
This is true, if you're lazy!

In C at least, I think it's important to specify whether we're expecting a pointer to a single element, a pointer to an array, if the pointer is an output, etc etc. A uint8_t* could be many things...

But the thing is, in C a geocoding function would probably receive two ints and return a string, while in Haskell you'd probably have a function of type "Location -> Address". The type system obviates much of the need for those comments.
Indeed, a solid type system would remove some of that need, in C it can be very important to document what precisely that pointer is pointing to. Is it a provided buffer, something allocated and returned? Multiple or single element? etc etc.

I'm guessing Haskell doesn't need that? A simple statement of purpose would still help though?

Note that this isn't the "official" Haskell style guide. We don't have one (although we probably shouldn't). This is one of the competing guides out there.
There's similar advice in the Ruby Style Guide - https://github.com/bbatsov/ruby-style-guide#no-comments

Comments often go out-of-sync with the code, so I think it makes a lot of sense to prefer writing comprehensible code instead of trying to explain with comments something totally incomprehensible.

It's weird to me how people will slate low quality code, but think it's okay (or inevitable) to let comments go out of date. If your comments aren't useful, delete them. If they are, keep them up to date. It's part of behaving responsibly towards the rest of your team just as much as writing readable code is.
Comments are lousy for describing what you are doing, but there are no alternative to comments for describing why something is done.
Avoiding comments that do what your code should be doing is common practice, and I think that's what this style guide is recommending.

Comments are useful to describe __why__ you're doing something, often when you are not able to change the unexpected behaviour. Whenever I build an API library, my code is littered with comments like "Acme Corp API requires this happens before that" with a link to that bit of the API documentation.

Here's a C++ example about "documenting surpises" (taken from Steve McConnell's Code Complete:

    for ( element = 0; element < elementCount; element++ ) {
        // Use right shift to divide by two. Substituting the
        // right-shift operation cuts the loop time by 75%.
        elementList[ element ] = elementList[ element ] >> 1;
    }
And a Java example:

    /* The following code is necessary to work around an error in
       WriteData() that appears only when the third parameter
       equals 500. '500' has been replaced with a named constant
       for clarity. */

    if ( blockSize == WRITEDATA_BROKEN_SIZE ) {
         blockSize = WRITEDATA_WORKAROUND_SIZE;
    }
    WriteData ( file, data, blockSize );
He also gives a whole list of situations in which comments are a bad idea, and it's similar to the OP.
Completely agree :) In some cases I prefer to wrap it in an aptly named function, but in other cases I prefer the whole algorithm to be in a single function, making comments a very useful tool for "naming".
in other cases I prefer the whole algorithm to be in a single function

A modern compiler can inline most of your function calls if you like. That way you can factor the code appropriately for both concerns.

Putting the whole algorithm in a single function isn't for the compiler's benefit but for the reader's. Especially in languages with side effects any function call you need to analyse takes time and then you need to come back to the main function and remember your mental state.

Please note that in many cases putting an algorithm in a single function is the wrong choice but there is also a cost in splitting it.

That's the only thing that must be said about this topic.

As a rule of thumb, if I've thought more than 20 seconds about what a particular section of code has to do, I comment it.

The point of Haskells type system though is that those annotations tell you most if not all of those things, they're a form of documentation that is very powerful and designing your types clearly makes it even better.

Plus your annotations are updated! Comments wither and die.

[Edit] to be clear, if there is something going on that would cumbersome to "document with types" i just write comments. There's also a place for function description and example.

It's doesn't recommend avoiding comments - it encourages to write understandable code and avoid meaningless comments. It is a basic rule of the clean code.
Good code should be self documenting.
> Good code should be self documenting.

Good code needs no test either,... wait no ,that's a stupid thing to say,because nobody writes "good code",code isnt good or bad,it either results in the expected behavior or not.

Depends on how you define "expected behavior".

If it means "the machine executes it and is able to produce the expected outputs with the right inputs", and nothing else, then you are missing a key concept about code.

You see, code is not written for machines. If that was the only reason, we would all write direct binary. Code is written for people. More specifically, other people. (Or you, in the future).

If no one (except a machine) is capable of understanding a piece of code, then that code is indeed bad; it has failed its main purpose. The more understandable by people code is, the better it is.

I agree that once compiled/interpreted, these differences don't matter. Until the next bug or feature request arrives. Then it matters quite a lot.

I've seen this many times:

    ...thus they (comments) tend to diverge from actual implementation.
It happens, you update/refactor code, and forget to update the comments. Thus the comments are outdated or worse not applicable anymore. Common mistake by less-detailed oriented developers. Begs the question, in this case is is better to have confusing/incorrect comments, or no comments at all?
No comments are better than bad comments. There is nothing worse than a misleading description.
I've always gone with the adage: if the comment and code do not agree, don't assume that either of them are correct.

A bad description isn't just a problem in itself, it can indicate a worse problem sat waiting to jump out and bite as you walk by.

comments might diverge from behaviour but the code, almost by definition (modulo some crazy magic happening/broken interpreter ) _is_ the behaviour.
The best commenting system is a debugger stepping through the code. Unfortunately, I've yet to see a commenting style that is able to really document mental models about how the code works.
SEURAT is a research project that attempted this. I was a test subject for it a while back and found it pretty interesting. But its implementation at the time was an Eclipse plugin that probably hasn't been kept up todate. You can find a paper on it on the ACM digital library:

http://dl.acm.org/citation.cfm?id=1368215

I'm sure the dissertation is available somewhere on cs.wpi.edu, too.

> code, almost by definition _is_ the behaviour.

Yes, but is it the intended and/or desired behaviour in all cases that the codepath in question will be expected to experience?

That is the problem, especially in code that deals with rare edge cases so is not run often, and/or covers many circumstances where it is right but is wrong for one set of inputs that no one thought to test before (or since that code last changes).

" ...thus they (comments) tend to diverge from actual implementation."

In my experience comments are no more likely to diverge than tests are. With tests you have the advantage that they must compile. With comments you have the advantage that they are inline/interspersed with your code and so get read every time the code is read.

"It happens, you update/refactor code, and forget to update the comments."

So then the next developer to read that part of the code notices that the comment doesn't make sense, or is not well written, and they update it. No different than if they notice poorly named/misleading functions or variable names or a dozen other code smells. No big deal and certainly not a good case for commenting less.

"With comments you have the advantage that they are inline/interspersed with your code"

Just as a heads up, there are lots of testing paradigms that have the tests inline with the code it is testing. That they aren't the default in most languages is most disappointing.

It's often a good idea to comment "why" the code exist, if it is non-obvious (e.g. it's obvious to sanitize input parameters). The comment must be short and possibly point to a ticket wrote somewhere else.

It may be a good idea to comment "what" the code does, if it isn't clear (the code itself is "how" it is done, but "what" does it do may be hard to read, e.g. sometimes you use a clever hack for performance reasons).

As always, handle with care :-)

Personally I have no problems with comments in code for complex functions etc. But pointless comments like this below drives me insane.

// get the user $user = $this->getUser();

Times that by the thousands of lines in a project and you have one big headache!

> Personally I have no problems with comments in code for complex functions etc

I hope you have a problem with complex functions. (They should be made as simple as possible).

(comment deleted)
Why fear complexity when its the only way to get something done, other than not doing it?
There is no such complex function that can't be decomposed to bunch of simple(r) functions.
Often only with a deep understanding of the complex problem to understand its simplicity. But you have to ship in 4 weeks, so why not just get something working first?
Because simpler code usually leads to less bugs, which is faster and cheaper than complex, buggy code.
I find that the better I understand a problem, the simpler code I can solve with it. But I can also understand the problem better by solving it with code, and repeat a few times for a few months to approach an ideal solution.

Writing simpler code is more expensive than writing complicated code for that reason, unless you are a genius who can simplify any complex problem instantaneously. Anyways, your argument basically amounts to "do good, no do bad."

> But you have to ship in 4 weeks, so why not just get something working first?

Of course, this sometimes happens, but it shouldn't be encouraged. This way you are creating technical debt, which will be very expensive to pay off.

At what point is simple simple enough? You can simplify for a long time just by working at the same problem for a few years. But wow...not everything is a basic crud app.
> At what point is simple simple enough?

It's hard to explain. You know it by experience.

I actually work on problems that haven't been solved previously (or why not just get a dev to do it rather than a researcher). I get offended when some dev who writes web apps connecting to databases all the time says "all code should be simple." They really don't have a clue.
> But you have to ship in 4 weeks, so why not just get something working first?

If you do that, after the deadline is over, you will get assigned another task with another 4-week deadline. And then another. The code will get increasingly complex until you can't keep with it any more. And then you will leave the company, or they will fire you. And the people who gave you that deadline will refer to you as "the guy who left that horrible mess of code".

I decided long ago that that's not how I want to live my life.

If someone gives me an unreasonable deadline, I negotiate it. Hard. By explaining the problems, and making sure everyone understands the tradeoffs being made.

And if the deadline is really immovable, I negotiate a period to refactor after the deadline is passed, and in which I am not assigned other tasks.

And if that is not possible, then I start looking for another job. Fortunately now it's a great time to be a programmer.

But hey, if that works for you, then great. To each his own.

Heard this argument a few times and mostly I do agree, but in certain scenarios I'm not willing to spend a whole day on some perfect code when I can do it in a hour with some comments explaining it.

My scenarios for this typically include: * Disposable project, eg prototyping an idea for a client * I have an impossible deadline and I'm on a fixed project rate, maybe I should have quoted more, who knows, it happens

Write comments that explain why a certain line is there.

Let's say you are parsing a standard tab delimited file. You find that the tab delimited file has some non-standard features, so you have to write some extra lines of code to handle it. For people who thinks the code just parses a standard tab delimited file, these lines will be confusing, so you comment these lines and say why you included them.

Or create a function to handle that case, name it appropriately, and call it. Thus, no comment is required. You can also test the additional method in isolation, if you wish.

I appreciate that this type of thing is language dependent.

Comments aren't necessary at all. If the code was difficult to write, it should be difficult to read. :-P