You should write comments

This statement appears to be mandatory content for anyone writing any computer science study materials for schools and universities. It appears in most beginners programming books (or at least used to) and it is advice that is most often given to new developers.

Once you become more proficient and meet more experienced developers (especially within certain language communities) they'll most likely tell you the exact opposite: "Comments are a code smell" and that you shouldn't write them.

So what's going on? and who's right? I think both parties are both right and wrong. And I do think you should write comments*

Arguments for commenting

We're told we should comment our code so we can clearly communicate to our fellow developers what a piece of code does and possibly why it works.

It can also help you understand the code you are writing better by having to explain it. It can be used to document the previous authors and a change log.

Problems with commenting

The arguments for commenting your code sound pretty good. So why am I then told not to do it?

Let's have a look at some types of comments

Useless comments

This is right up there in my list of pet peeves and instantly puts me in a bad mood when I open a file and see this:

class UsersController < ApplicationController

  # Initializes a new user and assigns it to a ivar @user
  def new
    @user = User.new
  end

end  

Really?!

It takes me longer to read your comment than it does to read the piece of code. Are you going to forget what this does? Are you explaining this to someone who's never written any Rails but needs to work on this piece of code?

In short; who is this for?

Comments that lie

Most often comments lie to me because they are out of date. The code was changed at somepoint, maybe in a hurry but the comment wasn't updated to reflect the change:

class UserDecorator < SimpleDelegator

  # Returns users first name and last name
  def full_name
    [first_name, middle_initial, last_name].compact.join(' ')
  end

end  

Nope! I've read your comment and had I believed it I would have been very confused and started hunting for another decorator as what I can see on my page is Jane H Doe.

Version Control Comments

You are either not using a version control system, in which case commenting is probably way down on your list of problems or you are duplicating what it does for you but really poorly:

/* --------------------------
  Author(s): Eugene Belford (the_plague@gibson)
  Version: 1.1
  --------------------------
  09-13-1995: Improved tanker control code
  09-01-1995: Initial implementation
*/
void davinci()  
{
  ...
}

Just use a version control system.

Comments that "fix" bad code

Otherwise known as lazy comments. These comments attempt to fix the poorly written code by explaining the poor practises:

/*
a is the item to be sold,  
c is the base cost of the item,  
u is the user buying the item  
s is the user selling the item  
/*
function sell_item(a, c, u, s) {  
  // calculate total cost with tax and comission
  var t = (a.multip * c) * 0.25 + 0.1;
  // deduct money from buyer
  u.creds(false, t);
  // credit the seller
  s.creds(true, a.multip * c);
  ...
}

I couldn't agree more, you definitely need comments here to try and figure out what is going on.

The problem is that you're fixing/hiding poor coding practises by littering the code with comments. Not only that it's hard to read what is going on when every other line needs to be a comment.

Also falling into this category of comments are the comments that lets you be lazy and not refactor a method or a class by explaining away the complexity:

## Resolve the users name and perform a DNS lookup with the results,
## parse the found email addresses and compose an email to all
## subscribed users and export the results to the monthly reports
## and notify the sales team by SMS
def process_user(user)  
  ... omitted 1000+ lines
end  

Again commenting isn't the fix. There's a problem here, your method is doing waaaaaaay too much stuff and you should just refactor it to smaller methods and/or objects with meaningful names so it makes sense without the giant comment.

The funny comments

// Magic. Do not touch.

or

<!-- Here be dragons  -->  

You've done something bad and you know it but you're hoping the funny will stop the next person having to look at this from hunting you down. Good luck.

You can find these fine examples and other funnies in this stack overflow thread.

So don't write comments then?

We've pretty much argued away all the initial arguments for writing comments now.

Except the arguments against weren't against writing them, they were against committing them and them becoming a permanent fixture in the code base.

So actually what I'm trying to say is

* You should write comments but never commit them

Wait! What's the point in writing comments if you're not going to commit them?

They can help you write better code! After you've written a piece of code, try and write a comment explaining what the class or method does and then identify the type of comment it is.

Is it a useless comment? Good! Delete it.

Is it explaining something that isn't clear? Refactor the code until the comment becomes useless. Delete it.

How many instances of the word "and" does it have? Are you following the single responsibility principle? Can this be split into smaller parts each with a useless comment. Delete them.

Are you doing something naughty? Should you take a bit of extra time and not leave a turd for the next developer? Do it properly and then delete the comment.

Explaining the input parameters? Either name them to be more descriptive, reduce the amount or maybe use a data transfer object instead which in itself is more descriptive. Is it that your method or class is suffering from feature envy? Fix it and delete the comment.

So actually what writing a comment allows you to do is; reflect on the piece of code you've just written to identify problems with it. It helps your own understanding to explain things, but it doesn't mean you have to leave that litter behind.

Conclusion

So write comments but keep improving your code till you can delete all of them and commit nice and clutter free.

Now there's always exceptions, from the top of my head it's ok if you are:

  • Working around a bug in a framework or library that you can't fix and wan't to save your colleagues the headache of trying to optimize it
  • Doing some performance optimization that requires you to write code that is more complex than it appears it needs to be
  • Writing a public facing API and automatically generating your documentation from the comments

What do you think? Do you think doing this could help you identify problems in your code? Let me know on Twitter @efexen