DEV Community

Cover image for I love to document my code. Am I doing it wrong?
José Clovis Ramírez de la Rosa
José Clovis Ramírez de la Rosa

Posted on

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

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 comments, even the most redundant ones. I strongly believe that a comment is never wrong, unless outdated or misleading.

Sadly not much people seems to like this stance. Instead of documenting our functions, we rely on the naming convention and writing expressive code to figure out the what and the why of any code. Sometimes we even have aesthetic troubles with it, as if the comments were distracting us from the code itself.

I like to write expressive code, but I don't see it as a replacement of proper documentation.

Am I doing it wrong?

Top comments (34)

Collapse
 
alchermd profile image
John Alcher • Edited

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.

Collapse
 
clovis1122 profile image
José Clovis Ramírez de la Rosa • Edited

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?

Collapse
 
alchermd profile image
John Alcher

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.

Thread Thread
 
clovis1122 profile image
José Clovis Ramírez de la Rosa

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..).

Thread Thread
 
alchermd profile image
John Alcher

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.

Thread Thread
 
clovis1122 profile image
José Clovis Ramírez de la Rosa

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

Thread Thread
 
idoshamun profile image
Ido Shamun

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

Collapse
 
afuerstenau profile image
Alex Fürstenau

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

Thread Thread
 
alchermd profile image
John Alcher

That's a good quote!

Collapse
 
alainvanhout profile image
Alain Van Hout

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.

Collapse
 
clovis1122 profile image
José Clovis Ramírez de la Rosa • Edited

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 :) .

Collapse
 
alainvanhout profile image
Alain Van Hout

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.

Thread Thread
 
clovis1122 profile image
José Clovis Ramírez de la Rosa • Edited

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).

Collapse
 
annarankin profile image
Anna Rankin

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.

Collapse
 
michaelgv profile image
Mike

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

Collapse
 
terrancecorley profile image
Terrance Corley • Edited

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
};
Collapse
 
clovis1122 profile image
José Clovis Ramírez de la Rosa

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.

Collapse
 
terrancecorley profile image
Terrance Corley

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.

Collapse
 
ferricoxide profile image
Thomas H Jones II

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.

Collapse
 
clovis1122 profile image
José Clovis Ramírez de la Rosa

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 :').

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited

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.

Collapse
 
scottishross profile image
Ross Henderson

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.

Collapse
 
stiv_ml profile image
Stiv Marcano

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.

Collapse
 
clovis1122 profile image
José Clovis Ramírez de la Rosa • Edited

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).

Collapse
 
tomazfernandes profile image
Tomaz Lemos

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.

Collapse
 
rlxdprogrammer profile image
Marcell Lipp

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.

Collapse
 
clovis1122 profile image
José Clovis Ramírez de la Rosa

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?

Collapse
 
rlxdprogrammer profile image
Marcell Lipp

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.