Are code comments really useless?

Lately I’ve seen and heard different people preaching code without comments. They say that if you write good, clean code that explains itself, there’s no need for comments. They go on to say that comments are useless once you use the right names for variables, functions, classes. They also say that it makes you write smaller functions, and split classes into smaller classes because their names have to say everything about them; and you can’t say much in a 20 character function name. Also they say that once you update the code, you may forget to update the comments. So it’s better to not write them at all.

Of course, this idea was adopted very rapidly by many people. We don’t have to write comments anymore! Yes! Everybody that never commented any code in their lives, suddenly has a reason for continuing to do so. If someone had to write both code and comments, and now only has to write code, it’s easier, right? It takes less time since you don’t have to write something extra. Another reason for the rapid adoption is that most programmers have good maths skills, but not so good English writing skills.  No wonder that many people have jumped aboard of that train, and started spreading the idea that comments are useless.

So, I’ve been reading about this, seen it in a couple of books, seen it a some articles, blogs, and have been listening to it from my coworkers. I’ve always avoided to argue on this one since I wasn’t directly affected.

But now it’s time to defend the comments. Somewhere along the road they’ve been reduced to a redundant, maybe outdated explanation of the code, an excuse for bad code that cannot explain itself. I’ll show you that they’re more than a redundant explanation of the code. Much more than that.

Now it’s time for me to stand up and preach a new idea – code with comments!

How things usually are

You see, we programmers usually write crappy code. Sometimes we make all the mistakes that the coding books tell us not to: long functions, functions that do many things instead of just one, variables called myVar1, hard-coded values, creating interfaces with useless methods, sometimes useless parameters. Sometimes our code is written as if we’re trying to win Obfuscated C Contest, in whatever language we’re coding.

We do all these things, no doubt about it. The idea is to see them somehow and fix them. How do we do this? How do we improve our code? Usually we run the code, and nothing works and there are a lot of bugs. We fix those bugs and change the code a bit. Then another person wants to use our code, but they discover hard-coded things, so we change the code a bit, making it more generic. And so on. After six months a simple function, as simple as printing ‘Hello world’, starts to look usable.

There has got to be another way to improve the code – and faster!

Improving existing code

Another way to improve code is to review it. We could review the code and change function names, split long functions, move generic functions out of specific classes, change interfaces, etc.

The thing is, most programmers do not ‘review’ the code. They write it, and if it works – perfect! They’re not going to re-read the code and make changes to variable names. That’s just time wasting.

So, how can you force a programmer to review the code? Well, in my case the answer is very clear – comment the code.

Once you start commenting the code you’ve written, something magical happens: you are forced to review the code, and write down what it actually does. Let’s meet Joe. Joe is a young smart programmer – and of course lazy. Joe has created a function that should save the details of a new user to the database, and which also sends an email to the admin. This is how his function would be called:

OtherModule → call saveUserDetails(arg)

Now, when Joe starts commenting that function he’s forced to write that down “this function does this but has also this side-effect of sending emails”. Also, one variable is called ‘arg’ but it should hold the user details, fully complete and valid. Joe would have to write that down too. Joe would have to write how the function behaves in case of errors: what if the database is down? What if the email system is down? Should he ignore the error from the email system? Joe is about to write a very, very long comment. He doesn’t really like writing.

There is another reason holding Joe from writing this comment. Joe has a strong ego and he wants that his peers think that his code is perfect. Should he say that in the comment, his peers would surely see the imperfections.

So, what does Joe do? Normally, he wouldn’t write any comments and let the function as it is. But since he has to write the comment, he starts writing it, mumbling about the injustice being made, having to write English words like in school. So, he starts writing the comment, but then realizes that instead of writing a very lengthy comment describing the side-effect and error handling, he can simply split the function in two and write a very shorter comment. This way he does what he likes: deals with code. He renames ‘arg’ to ‘userDetails’, moves out the code that sends an email to a different function. Now, he has two functions, each doing only one thing, short functions, and with clear parameter names.

This is how his functions would be called:

OtherModule → call saveUserDetails(userDetails)

OtherModule → call sendEmail(“New user”, “admin@example.com”)

Now, it’s very easy to write the comments for each function. In the end, everybody wins, as the code is clearer and more robust. And with comments, too!

Writing future code

Sometimes it’s easier to write the prototype of a function, and write the comments about what it should do before writing any code. Some say that they already know what it should do, and they can add the comments later, or not at all. However, sometimes things seem very clear, but once you start to analyze them you discover they’re actually very fuzzy. It’s like a dream – you think you remember it all, how you’ve been attacked by an animal while walking down the street; but when you start telling this dream to another person you can’t remember if you were attacked by a tiger or by a lion, or if you were on the street or actually at the seaside. The same thing happens with code – you think you can design the perfect function names and parameters, but when you write the code you discover lots and lots of missing parts. By writing the comment before, you can fix those parts without having to modify a lot of code.

This argument is similar to writing functional specifications for a product – the function comment, the class comment, even the comment inside a function that describes a smart algorithm – they all define what you’re going to do. It’s a contract between you and future you that writes the code. For example, you specify in the comment how the function should behave if the database is down, how people should use this function, potential limitations (not thread-safe, for example), etc.

Once you start writing the comment, you take the time to think about this function. And when you start thinking about something, that’s when you see other use-cases, that’s when you see simpler ways of accomplishing what you want to do, that’s when you see potential pitfalls, etc.

Then, after the comment is done, you write the code, which will be an easier job now. It’s similar to ‘Test driven design’ – call it ‘Comment driven design’ if you will. (Another name would be ‘Specification driven design’, since the comment actually acts as a specification, but ‘specification’ is a word that’s too generic).

How can comments improve reading code

Everybody in the industry knows it: code written by other people is crap and difficult to use. Why is it so? Because it’s hard to understand. Reading code is hard.

Sure, the name of the function can say something about what it is supposed to do. So do the names of the parameters. So does the name of the class. But they can only say as much, as they’re supposed to contain only few letters or words.

But! Suppose you had comments in English, using real sentences, with a subject, and a finite verb; comments that explain what a function does, how a clever algorithm is supposed to work, or why it does things in a peculiar manner. Now it’s easier to understand, right? Even if the comment is a bit outdated, you can still understand what the programmer was thinking when he wrote the code – what he assumed, what he missed.

Have you noticed how standard libraries are very documented, with comments for each function (even dumb comments, for setters and getters). How would you use use a library that’s missing comments? No way, right? It would be something along the lines of reverse-engineering. Yet some people do this every day, when it comes to using other code from their project, written by other people. Many developers understand the code that they’ve just written and they don’t feel the need to explain what it does. However when some other person wants to use that code, she will have questions such as: is it fine to send null values to this function? What is the third argument supposed to be? Does this function work for positive numbers only? What does it return? How does it handle errors? That’s where comments are really answers to all these questions.

Other benefits of writing comments

Avoiding premature optimization

Everyone has heard of premature optimization. It happens when smart programmers try to be smarter and write fast code. I won’t go into details, but we all know that premature optimization is bad for many reasons – wasted time, complex design, tightly coupled components, etc. Some British fellow called Hoare went as far as to say that premature optimization is the root of all evil.

Now, assuming that a programmer has to write comments, she will be eventually forced to comment her smart algorithm that optimizes searching through the list of someone’s pets. So, she has to write down all the steps of the complex algorithm, explain the hacks made for speedier operation, maybe even explain the limitations of her algorithm (“works only with cats”).

There are two options here:

a) she writes the code that does the premature optimization and the long comment.

In this case, ah well, at least a future person working on that code will understand it.

b) she quits writing the code that does the premature optimization.

This can happen because she realizes that it’s easier to write simple code which requires simple comments, or because she realizes that the limitations of her algorithm make it unusable, or because she realizes what a complex design she’s just created.

Improving writing skills

In time, if somebody keeps commenting code, his writing skills will improve, no doubt. Better writing skills means also better communication skills overall. This is useful because that person will be able to write better specifications, to write better emails requesting a bonus, to convey his ideas better when talking to his manager, or customers, or lover.

Conclusion

When writing a software program, the goal is to write code that’s easy to maintain, reuse, and extend. How do we do that? By making sure the code is easy to read. This implies a lot of tools, such as proper naming, short functions, avoiding magical numbers, etc, but it cannot exclude comments. When it comes to communicating our coding intentions, we need all the tools we can get! Not only code comments are not outdated, but they’re more and more badly needed, as the software we develop is increasingly complex.

What do you think?

Advertisements

3 thoughts on “Are code comments really useless?

  1. I completely disagree with your assertions here. You seem to be defending comments as a way of fixing bad practices. Putting lipstick on a pig doesn’t make it any less of a pig. The many people argue that writing comments is pointless are actually correct, when you know what you are doing. If you are a crap programmer, then you should absolutely be using comments, as well as remain at a junior level until you stop writing unreadable code. If you are using bad variable names, and your code isn’t readable then you end up with a piece of code that is unreadable and requires comments just to explain what exactly your poor logical choices of wording were attempting to convey. Now if you can write code that reads like english, which is what the experts that claim comments are useless do, then you don’t need comments peppered throughout. That doesn’t mean you shouldn’t write comments on your methods if the method name doesn’t immediately explain what the purpose of a method is. It just means that you shouldn’t need to write comments if you do your job well. I haven’t used comments outside of company mandated development by contract, because I write good code, and when other people look at the code it is readily apparent what that code does without any comments required. I know this because I’m an expert that has dozens of people a week read my code, and they all agree, no comments are necessary because my code easily reads like plain english. My suggestion, stop defending comments, and start advocating the programmers learn how to communicate with code in a concise and clear manner. Maybe developers should learn to write a paragraph of text that doesn’t leave the reader guessing. We all went through it at one point. The thing is if you aren’t lazy and don’t make poor choices, then comments aren’t necessary. If you regularly write code that no one else understands when they first look at it then you should work on that, because the truth is, that people who write unreadable code, also tend to write unreadable comments.

    Like

  2. Well… I think it’s very nice that you have a great experience writing code which reads easily. That means you pay attention and give good names to variables, methods, classes. Not everybody does that.

    I read a lot of code and usually it’s not really easy to understand. Sometimes not at all. I’m just trying to make people write code which is easier to understand. Make the world a better place 🙂 I think that’s what you want too.

    One of the ideas in this article (which may not be that clear since the article has gotten quite big) was to use comments as an intermediate step, to really write down what a method is supposed to do. And then based on the new findings, rename the method, rename the parameters, variables, or even more, split the method into smaller ones. If after the changes, the comments are redundant, then, sure, delete them.

    Let’s say LEVEL0 (pig)
    int doIt(int m, int leap)

    LEVEL1 (pig with lipstick) =
    /* Get the last day of a month.
    m = month (from 1 to 12)
    int = if the year is leap (1) or not (0)
    */
    int doIt(int m, int leap)

    LEVEL2 (not pig)
    int getLastDayOfMonth(Month month, boolean isLeapYear)

    When reading code, I prefer nice self-explaining code, with no comments. Of course I do. But if that’s not the case, I do prefer a pig with lipstick than a pig. Maybe that’s me.

    The other idea was that sometimes, comments are really necessary. I fully agree with you that ‘sometimes’ should be in rare cases. For instance, is it fine to send null values to a method? For Java, you can of course use the @NotNull annotation. But maybe the method accepts null values based on the value of another parameter. That cannot be easily put into code.

    For instance, if I look at the TreeSet class in Java, to the documentation of two constructors:

    It says:
    TreeSet(Collection c)
    Constructs a new tree set containing the elements in the specified collection, sorted according to the natural ordering of its elements.

    TreeSet(SortedSet s)
    Constructs a new tree set containing the same elements and using the same ordering as the specified sorted set.

    Well, I find value in those two comments.

    Like

  3. It’s generally been my experience that if code is completely unreadable, it is either incredibly generic and warrants an appropriate contract describing the purpose of the code, or it’s written with a lack of clarity, whether that be in poor variable name choices, or poor method name choice, or whatever it may be. In the first instance you are forced to deal with writing something that explains what it is doing, in the latter instance, I would think advocating that you redo your work and make it readable is a much better suggestion than asking for a comment, which is likely to be as terse, incomplete and unreadable as the code it’s describing. I think we both have the same goal, but have different opinions on how to get there. You say comments, but you provided the first crucial step to writing any piece of code, which is using pseudocode to describe the problem in a way that loosely mixes code and plain english. From there it should be incredibly easy to create a method that doesn’t need any comments, and as such, with most of the great programmers I’ve met, the pseudocode does indeed disappear once the code block is complete.

    In the instance of the TreeSet I would advocate that their use of contracts is 100% good practice, since the code is far too abstract to make sense from a quick reading. In this case the contracts on the methods give clarity to the purpose of the abstractions within, and how they are handled. Same thing goes for methods with constraints like @NotNull, that should be contracted in so that the constraints are placed on the method. My general rule of thumb is that in terms of documentation, if a methods functionality or constraints cannot be easily determined by the method name, which can and does often happen, then that method should get a short and sweet contract defining the limitations and/or purpose. There’s a difference though in my opinion between writing comments that are needed for anyone else to even use the work and comments that are there as a means of attempting to explain something that should be easily defined. In my experience, the people who write code that is unreadable should be held accountable for their transgression and asked to fix it. This is why code reviews exist in companies, and if you are doing it on your own…then you should probably care enough about your craft to do it well enough that others understand. If not for others do it for your own sanity. After a couple weeks when you forgot why you did something and you are forced to read your own unreadable nonsense, you will either give up immediately, or hate yourself for being so lazy that what should be simple is now incredibly difficult because you can’t even read your own logic. So, I say, let’s not advocate that people should comment their code, instead that people should strive to make their code so readable that there is no doubt what it does when you read it. Comments should be used sparingly, and only when it is absolutely necessary. Clean code should be the goal, and all people in programming should strive toward it, not make excuses that it’s common so let’s comment more. Because let’s be honest if you can’t write code that makes sense, you probably can’t write a properly descriptive comment either.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s