I love to document my code. Am I doing it wrong?

José Clovis Ramírez de la Rosa on September 08, 2018

I've been saved countless of times by people who document their code, and also doomed by people who doesn't. At some point I just started to love c... [Read Full]
markdown guide
 

I strongly believe that a comment is never wrong, unless outdated or misleading.

// The age of the user.
int userAge;

That's a comment that is neither outdated nor misleading but is quite useless. If we go by your rule, we'll be duplicating our code with a 1:1 comment; violating the DRY principle.

 

Hey Alcher, thanks for the code sample.

I'm not too sure about it violating DRY principle since the code itself and the comment serves for different purposes.

You could argue that the code is already doing the job of documentation. Would you say that you get the idea faster by reading something camelCase like userAge than a well-versed English sentence The age of the user.? In my case at least, it takes me some extra seconds without the comment.

I don't encourage this type of comments, but I don't see how it is damaging you either. Would you remove this type of comment if you find it in a program that you're working with?

 

You could argue that the code is already doing the job of documentation. Would you say that you get the idea faster by reading something camelCase like userAge than a well-versed English sentence The age of the user?

Yes, indeed. A 30 line function with 15 lines of logic + 15 lines of comments will take up more cognitive load compared to the one with 0-2 lines of comments and good naming/structure.

I don't encourage this type of comments, but I don't see how it is damaging you either.

It's clutter and noise, IMO.

Would you remove this type of comment if you find it in a program that you're working with?

In a collaborative scenario? It's a point of discussion with the one who committed the snippet, that's for sure.

Yes, indeed. A 30 line function with 15 lines of logic + 15 lines of comments will take up more cognitive load compared to the one with 0-2 lines of comments and good naming/structure.

Hmmm I think that I get your point now. When looking at a function for documentation I always read the comment and skip the code (unless debugging/reviewing it, in which the comments are helpful to understand the intended behavior), so I don't feel this cognitive load (this is just me though).

In a collaborative scenario? It's a point of discussion with the one who committed the snippet, that's for sure.

I'm not too sure if this is worth taking even 3 minutes from someone else's times to discuss whenever the comment was needed or not. You must be really feeling the clutter/noise to consider it a point of discussion.

Perhaps if one member of my team is writing this type of comments and he/she had done it several times, I'd take 5-10 minutes to speak with that person about it (I still wouldn't ask the person to remove the comments..).

I'm not too sure if this is worth taking even 3 minutes from someone else's times to discuss whenever the comment was needed or not.

Setting up standards is an important point for a development team. If the guy that writes comments like these have a reason for doing so, he should discuss it with the team for standardization.

I agree that setting up standards is very important, thanks for your thoughts.

I totally agree with John, I think comments add much clutter to code and you have to use them carefully. Writing self explanatory code is not an easy task so sometimes comments can cover it.
But eventually it is up to the team culture. If your team likes to comment so go ahead and just do it

 

If the comment really helps you in this case, why don't you make the code more like the comment?


int age_of_user; or
int age_of_current_user;

That is the better way, in my opinion, since the comment is not necessary and therefore you cannot forget to change comment when the code changes.

"When you feel the need to write a comment, first try to refactor the code so that any comment becomes superflouus." - Martin Fowler

 

Expressive code tends to do well on explaining 'what' and sometimes even 'how', but generally fails at explaining 'why'. That's where a short comment now can save a lot of time later on.

That said, comments that are just repeating what the code itself said are even less than useless, because they reduce the visibility of truly useful comments.

 

Hey Alain,

I agree that expressive code generally fails at the "why". Seeing your comment about "comments that are just repeating what the code itself said", I'm curious if you would consider commenting code that takes an extra mental effort understanding what they do, for example:

[1, 2, 0, false, "foo", null, undefined].filter(Boolean)

or

return value | 0

I'm sure every language have something that, although they have a way to do it, it is not as expressive as in other languages. I generally tend to document when I'm using some wizardy code that can't be made expressive (e.g bit operators) and I don't expect the reader to be a master at the language that it's being used (I don't expect everybody to know bit operators). I write code for Junior Devs since I'm a Junior myself :) .

 

When doing something fancy, adding an explanatory comment is defintely a good thing (though I would generally advice against doing anything 'fancy'). For those specific cases, it all comes down to what is sufficiently idiomatic, and to only comment on the cases that aren't.

As a litmus test, I would suggest asking yourself the following question: would a developer that has 6 months of decent working experience with the language/framework/library/paradigm be expected to know about this approach or at the very least know how to easily look it up? That means that things like standards variable declarations, loops, typical pointer usage, filter vs reduce vs map vs flatMap all count as idiomatic.

There are some grey zones, such as default value variable declarations in JavaScript:

const foo = bar || "my default value";

For those, you could rely on an extension of the above principle: if these constructs are project/team conventions, they count as idiomatic within the project/team (i.e. if you've been working on the project/team for 6 months, there is no doubt that you know about and understand the construct).

As an example of something that definitely does not require comments, and where the comments do more harm than good:

// declare the counter and set it to the starting value
let count = 0;
// perform the loop
for (
    // declare the loop variable and set it to the starting value
    i = 0;
    // every loop, check whether we've exceeded the maximum value to loop over
    i < 20;
    // increment the loop variable by 1
    i++) { 
    // increment the counter with the loop variable
    count += i;
}

I trust you see that this kind of commenting would belong perfectly in a textbook for beginner JavaScript, but is utterly pointless in actual production code. Now imagine that you have code like this, but 10 times as long, and somewhere in the middle you have

// framework X has an internal bug in code segment Y (see <link>), which we have to correct for here, otherwise our code segment Z blows up
const correctionFactor = foo * 1.05;

Because of all the pointless comments, that comment will hardly be noticable, while if you remove all the pointless comments any reasonable IDE or syntax-highlighting editor will make it stand out.

As a final comment (pun very much intended), I'd like to add that this isn't a black or white thing: adding a poor comment doesn't damn you, it just makes the code slightly less maintainable. But given how much code most developers work with, the little things add up quite fast, so it pays to keep them in check.

Thanks for the examples, you're right that these type of comments makes the code noisy (perhaps I'd still be OK having them if they get reworded and moved somewhere where they're not as disruptive as in your examples).

 

I write code for Junior Devs since I'm a Junior myself :)

This is one of the reasons I love having access to less-experienced folks at work. When I find myself looking at some code I've written and questioning its clarity, I have often pinged it over to a junior or someone with a different context than I have and asked:

If you stumbled onto this logic in a file that does X, without further context - what would you expect it to do?

If I can make that clear to a second set of eyes without a plethora of comments, I consider that a big win and another step toward writing cleaner, easier-to-grok code.

 

I've always done development like so, take this inherited code:

import { UserAction, ProfileValidator } from '@internal-package/ui-workflow/tools/UserAccount';

class IsAdministrator extends UserAction {
    /** @rt.inject "UserProfile" **/
    private _validator: ProfileValidator = null;
    public validate(): boolean {
        return this.getValidator().getPermissionLevel(7777))
    }
}

export default IsAdministrator;

This is pretty self explanatory, but then take this example:

import { Action, FormElement } from '@internal-package/ui-workflow/tools/Actionables/Elements';

export default class UxEnhancementAction extends Action {
    private _v: FormElement = new FormElement( this );
    public set( n: Action.Node ): void {
        this._set( n.build() ).write( this._v.__setter.write, { props: true, val: !this._v.__getter._wv } );
    }
}

Obviously, the second code block is confusing. If we break it down by documenting, it looks like this:

/**
 * This is legacy code, it should be removed in Version 0.3.1
 */
import { Action, FormElement } from '@internal-package/ui-workflow/tools/Actionables/Elements';

/**
 * This class was used to enhance the button actions, we wanted nested button actions, now these are not required
 */
export default class UxEnhancementAction extends Action {
    /** This is a form element **/
    private _v: FormElement = new FormElement( this );
    /** Set the node, build the node's DOM tree (n.build), write it by passing in the FormElement's write function, and inherit the properties (props: true), then set the success value of the FormElement's write value (wv). REFACTOR NOTE: This should be renamed for clarity if we need to keep this method alive. - DEVNAME **/
    public set( n: Action.Node ): void {
        this._set( n.build() ).write( this._v.__setter.write, { props: true, val: !this._v.__getter._wv } );
    }
}

My attitude: If your code is self explanatory, you don't need long documentation. If it's confusing, write some longer docs. but, don't write no documentation, always document even if it's minimal

 

Using clear, descriptive names for variables and functions can go a long way. That said, I'll still use comments if I feel it's necessary for readability or to understand the code with less mental effort. Most of the time I end up using comments to leave notes for myself or the team, or if something might not be immediately apparent in the code like so...

// TODO: Fix this function that is breaking item checkout
const breakingCodeFunction = () => {
  randomFunction();
};

// Add function to generate monies
const monies = () => {
  // money generating code will go here
};
 

Good stance Corley!

Inside functions I also tend to leave code for readability, hacks, todos and even something like moment(date, 'MM/DD/YYYY').format('YYYY-MM-DD') to explain "why" that was done. People argue that comments can hurt readability but I haven't found such case yet.

 

Thanks!

Yeah I agree. If it makes it easier to understand the "why" behind the code at a quick glance- especially if it's an older project you're coming back to after some period of time, I don't see any issue with it. As some others have already said, just don't go crazy with the comments.

 

Much like blogging, I comment code for my own benefit: it's rare that I never have to go back and tweak code I've written. If it's been more than a few weeks since I touched my own code, I often won't really recognize what I did without those reminder-anchors.

 

Yup! In some of the projects where I worked a long time alone, I always thanks myself everytime that I need to make a change and I've completely no idea what to do with the code or I even forgot some basic things from the programming language. Then there's a comment there explaining me what and why :').

 

First, don't let anyone discourage you: you're doing it right. My company follows the Commenting Showing Intent standard, which literally formalizes the idea of commenting "why" on every logical statement.

Some people would say that this is redundant, but code rarely expresses its own intent. If an obvious intent gets restated in a comment now and then, it's not really much of a loss, since things obvious to us might not be obvious to others. Most of the time, the intent isn't expressed by even the best code.

Yes, it may well mean you have a 1:1 comments-to-logic ratio, but this is actually more useful than some would have you believe. Good commenting will allow the entire program logic to be recreated in any language, using the comments alone! Implementation varies by language, but the intent and logic are generally the same (with some exceptions). In practice, this actually means the cognitive load is less - we're not sitting here trying to imagine what the programmer (or our past selves) meant. We read the comment, skim the code, grok the idea, and move on. It takes less time, not more, to understand 1:1 CSI'd code.

Others complain that "comments fall out of sync with the code," but that's only true if we let it. When incorporated into a review policy (which every 2+ person project should have), discrepancies between CSI comments and the code generally indicate mislogic, which should be fixed!

In practice, we've been using CSI for a few years, with fantastic return on investment: faster code learning times, less bugs, and better reviews.

This is, however, distinct from documentation, as you pointed out. Comments express "why" to the developers, documentation expresses "what" and "how" to the end-users. Anyhow, most API documentation is like teaching someone how to use a toaster by explaining the electrical specifications of the heating element.

 

I'm of the view that in large bodies of code, a little comment giving a brief explanation of what the code does can be very helpful. If my colleague writes a massive package that does something, I don't want to have to spend hours breaking it down so I can understand it. You can nearly always half that time by adding a little comment like this:

-- Working Day 01: 1st Email/Message
begin PKG_LOCK_CHASE.FIRE; end;
/

-- Working Day 02: 1st Email/Message + 1
update TBL_LOCK_CHASE set CREATED_ON = CREATED_ON - 1;
delete TBL_LOCK_SFTP where DEVICE_IMEI in (select DEVICE_IMEI from TBL_LOCK_SFTP where rownum <= 5);
begin PKG_LOCK_CHASE.FIRE; end;
/

I know exactly what those blocks are doing without having to go into each package and work it out.

 

IMHO, the only reason you should document all of your code is because you're making a public API where people is not going to be able to read your code. In that case, it's a must. But commenting self explanatory things, like a property called 'name' in a 'Person' object, it's not worth and just adds noise to your code.

 

The API example makes sense! Inside my own code (we're using typescript here) I tend to prefer documenting public methods and not private methods (sometimes i even leave their signature out).

 

I think comments are important to explain business rules. These are not self explanatory. Eg: Why something needs to increment 10 instead of 2, why something needs to go left and not to the right, etc.

 

Commenting code isn't "wrong" per se but (the following applies to per-line comments; API doc is a different matter entirely):

  • ... you may be better off spending your time in finding good variable and function names, and keeping your control flow and APIs clean. You will get a much better return on your time investment.

  • ... they go out of sync with the code extremely fast. Especially when multiple people work on the same code base. Comments rarely ever get updated.

  • ... they add a lot of visual noise, in particular if they just repeat in "natural language" what the code is doing and should be expressing on its own anyways. It's just like with tests: having a super-huge test suite won't add any value if the contents are useless. Having each line commented won't help if the comments don't add any info.

When I'm writing a particularly challenging piece of code, I find myself writing more line-by-line comments than usual. I try to put my reasoning in there for why I did things the way they are, such that I (or a coworker) can pick up this piece of code more easily in the future in case a modification needs to be made to it.

As stated earlier, API docs are a different matter entirely. I'm convinced that every public API member (method, class, constant...) should be documented rigorously and without exceptions. In practice, this corner is often cut due to time constraints - which makes proper naming and a clean API all the more important, because often times that is all you have to go by.

 

First of all, thanks for bringing this subject up, as it’s a very nice opportunity for all of us to learn with each other.

I’ve encountered a fair share of times when I needed to reuse some legacy functionality only to find out that it had so many long methods it would be better to rewrite or copy the code than mess with it and risk breaking it.

I think OO and agile principles are tools made to handle the assumption that the requisites will always change in the most unpredictable way, so breaking the code in small, coherent, reusable methods/ classes pays of most of the times, even if you can’t see it when you first write the code.

On the other hand, there’s no better time to refactor your code than when you’re writing it, with everything fresh in mind.

As for the comments itself, I think if you have to explain the code most probably you haven’t written it clear enough... You can extract hard coded numbers and strings to well named constants, “if” conditions to methods, and so much more.

That being said, of course there’s no silver bullet and it always depends on common sense.

 

They call them programming languages for a reason. You learn how to read and write in them. I'm in favor of less comments, more readable code.

Over time the code will change, and to my knowledge there aren't many tools that can ensure your comments match your code.

And if the code you're writing or reading needs to be commented so heavily, I'd question if it couldn't be rewritten.

Can you share with us an example method with comments?

 

Too many comments can make your code unreadable, it can make changes more difficult (since you need to update to comments as well). On the other hand with correct naming and coding style a lot of comments are totally unnecessary. You can read more about this topic in the Clean Code book of Robert C. Martin.

 

Hey,

I've hear about the book and expected it to come up here. Although I generally love Uncle Bob books I'm a bit demotivated to read Clean Code. I kinda agree with what's explained in this article: whatheco.de/2010/12/07/function-hell/

I always liked the idea to create functions and assign them a responsibility since it makes it much easier to reason about. I also tend to create functions that I know that will be reused, but I don't like much the idea of creating functions that I know for sure that will only be used 1 time.

I'm curious, when you say that it is unnecessary, do you mean that it is bad and should be removed as a consequence?

 

Hey,

First of all: I think this topic is quite subjective, there's not absolute truth. And I would not suggest to follow the Clean Code book blindly, there are several situations when it doesn't worth.

If think you are talking about two topics, however they are connecting to each other I would suggest to discuss them separately:

  1. Comments

What are the "bad" comment, which are not really necessary:
During my carrier I quite often met with such code:
speed = 30 //Setting speed to 40
What happened here? Someone set first to 40, and added a comment, which had totally no added value. Later on the software was not working as it should and an other colleague had to task to fix the behavior. He realized that the value of speed need to be changed at this point, but missed to change the comment (basically just avoided double work). Right now you have a totally inconsistent comment in your code base and most likely it never will be fixed.
It was just an example, but what I mean here: if you have "redundant" comments, then later on with time it can easily become a "misleading" comment, that's my experience with them. So I always try to write code, which is easily modifiable, so I'm avoiding all duplication and for me it belongs to the same category.

  1. Splitting functions: It really depends on the environment, for example in embedded environment introduction of new function can go against run time and it should be avoided. But in high level object oriented development the compilers are optimizing your code well and by the usage of private functions you are not messing up your public interface. Here I don't really see any point against splitting functions. But of course splitting down everything into 2 line long functions is not a good strategy. Here really my only point next to smaller and well-named functions is readability. Try to understand a function with 120 lines and multiple responsibility and try to understand the same functionality with broken down functions. Based on my experiences the second will be much faster and easier.
 

Relying on comments will make it easier for developers to write bad code since they can always explain in comments how it works. With practices like this, developers will not even notice that their code is badly designed.
Avoiding comments will push the developer to rethink and improve his code rather than explaining why the code is complicated.

 

Amen to that. This thing that comments are supreme evil has gone too much beyond.

 

I'm going a different way with my code in the last months: instead of commenting the code at the specific line, I'll wrap it in a debug-log call. This is a two birds with one stone thing for me.

code of conduct - report abuse