DEV Community

Cover image for "Do not comment on your code, it should be self-documented". Well... I don't agree.

"Do not comment on your code, it should be self-documented". Well... I don't agree.

Jean Santana on April 17, 2022

Since I started write my first block of code, I heard from many developers that commenting is useless and it's a type of apology to write a bad cod...
Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

It's never 'useless', but it can be overkill.

If code is written well (good variable & function names, clear logic), then it should be fairly obvious from reading it what it does. In cases where the logic is a little hard to follow then some comments can be very helpful. It can be a tricky balance - you don't want absolutely no comments ever, but at the same time, commenting absolutely everything just to try and cater for every possible skill level is also not a good idea.

If code is written well, and is uncommented - then it is probably the assumption of the team (as presumably the code has passed code review) that it is already understandable enough. If a new developer comes to this code and does not understand it, the best solution would be to consult a team member who does, and get them to explain it. This will have the dual benefit of increasing the junior developer's understanding, and making the team aware that there may be an issue with the code being too impenetrable in places.

Collapse
 
klausdonnert profile image
Klaus Donnert

And that's just it: Everybody thinks their code is well written. But most of the time it isn't near as good as the writer thinks it is. When I look at code that I wrote just 6 months ago I can see that it's not as good as the code I write today. I'm always learning improving.

Collapse
 
chasm profile image
Charles F. Munat

If they can't write clean and readable code, why would you think that they can write clear and understandable comments?

Thread Thread
 
klausdonnert profile image
Klaus Donnert

I wish people wrote clean and readable code. Most of the code I read is crap. I must admit I don't have much experience reading comments.

Thread Thread
 
chasm profile image
Charles F. Munat • Edited

Sadly, most devs aren't very good. Just like most doctors, lawyers, bricklayers, actors, barbers, politicians. Most people are mediocre at what they do. By definition, actually. Mediocre means average. Average isn't very good, usually.

But if a person can't even write decent code, I find it unlikely that they are going to write understandable comments in a natural language (much harder -- ask any writer), or, more importantly, that they are going to be diligent enough to keep that comment in sync with the code.

And my experience -- closing in on three decades -- bears that out. If you think code is bad, read the comments. They are almost always awful.

What's needed, really, is not comments but good code reviews by talented leaders who ensure that code is clean and readable before it goes into production. Which would also help to teach coders to write readable code in the first place.

But that might take time, right? We never have time to do it right. We only have time to write comments that we wouldn't have needed if we'd done it right, and then pay a bigger penalty down the road when the comments and code are incompatible and everything is a mess. Ever seen any code like that?

/*
 * Adds two arguments together. It will be gooder if the arguments
 * are numbers. You should put in two numbers. Then you will get
 * back the number you get when you take two numbers and add
 * them together. That's what will come out.
 */
const f = (arg1, arg2) => arg1 * arg2
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
klausdonnert profile image
Klaus Donnert

You made that up. Nobody is that bad. I did get a chuckle out of it.

Thread Thread
 
chasm profile image
Charles F. Munat

It was a joke. But it's not as far off as you might think. :-)

Thread Thread
 
klausdonnert profile image
Klaus Donnert

I consider comments as documentation. If a programmer does not document their code... I don't have energy to finish that sentence.

Thread Thread
 
chasm profile image
Charles F. Munat

Comments are a shit way to document code. The best way is in the code itself. So if your code is self-documenting, then you have documented your code. The only excuse for comments is that you had to do something in the code that you can't figure out how to make clear without a comment.

Maybe it's a workaround. Maybe you're just not that good. That's why we have teams -- so they can show you how to write better code.

In short, comments are generally where mediocre coders document their failure to write understandable code. It's either that, or the comments are redundant and probably just get out of sync.

So one could say that the more you comment your code, the more you're willing to admit that you don't write very good code. And if that's the case, then I guess comments are better than nothing. But why not learn to be a better coder or take up a different profession?

But hey, black and white condemnations like yours are all the rage these days. Maybe see a doctor, though, about your anemia?

It is always surprising how many devs confuse their personal preferences and pet peeves as scientific arguments and absolute judgements. And then boast about it.

Thread Thread
 
klausdonnert profile image
Klaus Donnert

Apologies. Sir, I do not condemn self documenting code. Most of the code I write is self documenting. We agree that bad code is bad code. You make a solid argument that comments don't improve bad code.
I generally use comments in a couple of ways. One is when I am writing a function or method, I write the steps out in plain English as comments before I implement them. Then I remove redundant comments. Some comments I leave because some things are nuanced and not obvious.
The second way is explaining, usually to my future self, why I did something a particular way, not what the code is doing, because well, I'm not as smart as I think I am. Even then, most of those comments are from my future self to my future future self to save time the next time I have to modify it.
Third, is explaining somebody else's code for instance, where they used a variable or parameter named "id" where id could be the column of one of 6 tables, and refactoring is not an option because it's spaghetti code in a huge legacy codebase.

I'm interested in your work flow. You're a teacher. I'm a student. How do you do it?

Thread Thread
 
chasm profile image
Charles F. Munat

Sorry, I misread your last comment as saying that all code had to be commented. I rarely comment my code.

Instead I:

  • Keep functions short -- 10 to 20 lines max, if possible
  • Limit functions to doing one thing only (though that thing might involve conditional outputs)
  • Name the function by what it does; name length is much less important than clarity
  • Keep my functions pure and referentially transparent
    • Hence, a function with zero parameters is a constant (e.g., function returnFalse() { return false }
  • Use options parameters
    • If the number of parameters will exceed 3
    • If I want to avoid positional parameters
  • Return tuples or objects if I need to return more than one thing
  • Always use a return statement (unless an arrow function)
  • Prefer named functions; arrow functions are for:
    • Passing an anonymous function in the parentheses of a function call
    • Controlling the this, typically in callback functions (anywhere you might use const self = this)
  • Use TypeScript (waiting for a better type system) for static typing
    • No any
    • type not interface -- interfaces are mutable
    • Avoid unknown in production code

Also:

  • I never use classes: I use modules (ESM)
  • One function (or component) per file
  • Name of the function or component (camelCase or PascalCase, respectively) is the name of the folder
  • Filename is either index.ts(x) or mod.ts(x)
  • All files associated with that function/component/module go in that folder, e.g.:
StringField/
  index.module.css
  index.stories.tsx
  index.tsx
  index.test.tsx
  README.md   -> the exception
utilities/
  not/
    index.test.ts
    index.ts
Enter fullscreen mode Exit fullscreen mode
  • I typically use module aliases so I can import from the top down: import not from "~utilities/not"
  • I don't use the bang (!) because it is too easy to miss; instead, I always write a generic not function and use that
  • I use double quotations because they are easier to see (I'm writing TypeScript)
  • I don't use semicolons because they just add noise -- in a decade of leaving them out, ASI has never once let me down, and now with the TSC compiler and using deno_lint to lint...
  • I use tabs for indentation
    • They use fewer characters
    • Everyone can set their own damn tab width
    • I'm using Dprint anyway
  • I prefer and use almost exclusively the default export option (exceptions: types, constants)
  • I always use import type for type imports, it's cleaner
  • I like one import per line where possible and I use an import sorter
  • I use VSCode currently, so I can easily collapse the imports
  • I put the default export function at the top of the file just below the imports so it is immediately visible
  • Using named functions means I can put helper functions below the default function as they're hoisted
    • But I generally put helper functions in their own folders
  • If a type declaration might be reused, I add it to a types file at the top of the module with like types, otherwise I keep it below the function/component but export it as a named export just in case
  • I deeply nest folders (remember: all names are on folders, not files)
    • At the top of the app (I do front end apps), I generally have:
      • An apps folder
      • A utilities folder (for generic utilities such as not, pipe, identity)
      • A services folder for any bespoke services (i.e., not in an npm or deno module) such as authentication
      • A modules folder for any reusable modules (e.g., generic components, icons)
  • IMPORTANT: If I have a function used only in one folder, then its folder goes in that folder (as a child folder), but if I then begin using that function in some other branch of the folder hierarchy, then I move its folder to the node where those two branches meet
    • In short, imports can go up the folder hierarchy, but they don't go back down.
    • And, often, I just do all imports not in a descendent folder from the top down, e.g., import doIt from "~apps/TicTacToe/utilities/doIt" rather than import doIt from "../../utilities/doIt"

In the apps folder, I have "micro-apps". These are standalone apps. Everything bespoke to that app is in that folder. Everything outside of that folder is generic and reusable.

So, for example, I may have a services/useGraphQL folder that provides a hook for using GraphQL, but it takes a config and returns query and mutation functions. So the actual URL, query, variables, etc. are provided where they are used. None of this is hard coded in the useGraphQL hook. (And I don't bother with Apollo -- a simple POST request returning JSON works fine.)

Inside the apps folder, I might have a micro-app called, I dunno, TicTacToe. The hierarchy of that folder and its subcomponents would follow the hierarchy of the components, for example:

apps/
  TicTacToe/
    Board/
      Square/
        index.tsx
      index.tsx
    index.tsx
Enter fullscreen mode Exit fullscreen mode

The benefit of this is that:

  • I can close up folders and see clearly the structure of the app
  • The structure of the folders matches that of the app, reducing cognitive load
  • PascalCase or camelCase tells me immediately what is a component and what is a function, repectively
  • The .tsx ending tells me it is using JSX (I am forced to use React usually, though I prefer SolidJS or even plain vanilla TS -- deno gives me JSX for free)
  • Most importantly, if I want to remove TicTacToe, I just delete this folder (or move it elsewhere) and remove the typically one reference to it (<TicTacToe />) elsewhere in the app
  • The TicTacToe micro-app can import from any of the other apps (using aliases), but other apps do not import from the micro-app (except to use it as an app, e.g., in a route)
  • I keep all the business logic and bespoke bits in the micro-app

I do not care how short a file is. Why would I? For some reason, many devs fear files. I don't get it. Why would I make a 1000-line file full of named exports when I could make a well organized folder tree with maybe 20 files, each of which contains a single function? If I need to view multiple functions at once, I can open them in side-by-side tabs.

Here is an example of the not function I mentioned, from production code:

export default function not<T>(value: T): boolean {
  return !value
}
Enter fullscreen mode Exit fullscreen mode

That is the entire file! Three lines. Here is a somewhat longer one:

export default function concatenateCssClasses(classNames: {
  [className: string]: boolean | undefined
}): string {
  return Object.entries(classNames)
    .reduce(
      (classList: Array<string>, [className, include]) => [...classList, ...(include ? [className] : [])],
      [],
    )
    .join(" ")
}
Enter fullscreen mode Exit fullscreen mode

That replaces an entire dependency (on "classnames")! You can see pretty easily, I think, that it takes an object with CSS class names as the keys and booleans as the values, and then includes only those that are true, concatenating them into a space-separated string. And if that's not enough to be clear, then in the very same folder is the test:

import { expect, test } from "vitest"
import concatenateCssClasses from "./"

const classNames = {
  red: true,
  green: false,
  blue: true,
  "burnt-sienna": true,
}

test("[concatenateCssClasses] creates a space-separated string of class names for className keys with truthy values", () => {
  expect(concatenateCssClasses(classNames)).toBe("red blue burnt-sienna")
})
Enter fullscreen mode Exit fullscreen mode

Other than a few polyfills for Intl and Temporal, fetch, and uuid, my app uses only React, XState, and, sadly, Auth0.js (not my choice).

"dependencies": {
  "@formatjs/intl-getcanonicallocales": "^1.9.2",
  "@formatjs/intl-listformat": "^6.5.3",
  "@formatjs/intl-locale": "^2.4.47",
  "@js-temporal/polyfill": "^0.4.1",
  "@xstate/react": "^3.0.0",
  "auth0-js": "^9.19.0",
  "cross-fetch": "^3.1.5",
  "react": "^18.0.0",
  "react-dom": "^18.0.0",
  "uuid": "^8.3.2",
  "xstate": "^4.31.0"
}
Enter fullscreen mode Exit fullscreen mode

I write my own code, including utility functions, and reuse it from app to app, improving it as I get better (and the language improves). So yes, I write my own pipe function, and often map, filter, find, reduce and more (wrapping the JS methods where appropriate).

That means that I know practically my whole code base (an argument for vanilla TS). It means that to the greatest extent possible, no one else has code in my code base, which means better security, better reliability, etc.

It means that when things break, I know where they broke and why they broke, and I can fix them rather than waiting for the owners to get around to fixing them and releasing a patch.

It means that I am highly motivated to keep my code base simple, not to bulk it up with unnecessary and bloated dependencies.

It means that most of my files can be seen in full without scrolling.

And if my code needs further documentation, I try to put it in those README.md files right in the folder (README means GitHub will automatically display them).

That's just a start, but I hope it answers your question at least a little.

Lots of devs violently disagree with one or another of the above, and I have done all of these things differently over the years, but this is the methodology that has stood the test of time. I'm sure it can be improved still further, and significant changes in language, framework, or library might make adaptations necessary, but I can say that of the many people I've taught this too, none have gone back to their old ways. It's simple, and it works.

YMMV.

Thread Thread
 
klausdonnert profile image
Klaus Donnert

Good answer. That's more than I expected. It will take me some time to digest it all.
I struggle keeping my functions short. 50 - 100 lines is not unusual for me. Three line functions always make me second guess myself, "Should I inline this"?
Earlier, I was thinking to myself "I bet he uses readme files".
Your use of utilities is fascinating. I have some functions that I seem to redefine over and over in different projects. This a good way to organize then and not redefine them.
I've used the folder/index.* naming convention in one project. It confuses me a bit and make my tabs too wide when I get several files open at once.
The temporal polyfill is interesting.
I like writing vanilla js for much the same reasons you use vanilla TS.

Good Night

Thread Thread
 
flutterclutter profile image
flutter-clutter

@chasm
Just wanted to say that I agree with almost every statement. I have made very similar experiences during my time as a software developer and have come to very similar conclusions. Most of the things are in line with Uncle Bob's Clean Code. Thank you for the detailed elaboration!

Collapse
 
ana1337 profile image
Ana

+1 I couldn't have said it better myself

Collapse
 
oribellove profile image
Love Oribel

thanks

Collapse
 
tmchuynh profile image
Tina Huynh

I've never in my years of education been told (except from that student who doesn't want to comment their code) that commenting/documenting code is "useless". Oh my! Documenting your code teaches beginners what you're doing. Not documenting at all excludes them because....how are they supposed to understand if you don't explain it in plain english? I bet the developer himself/herself won't even remember what the program he or she wrote does five or six months down the line without documentation. Who is it harming? True productivity, team work, and efficiency? Or just their ego and arrogance?

Collapse
 
rafo profile image
Rafael Osipov

If you keep naming your classes, methods, parameters and variables consistently and their names express their purpose, your code without comments is easy to understand even for beginners.

Sometimes comments are necessary to describe and point to code that does not work in an expected way, and you have implemented strange looking workaround. For example some libraries, used in your project may have side-effects and wrong behavior and to overcome these problems, you have to write strange-looking code. And in this case comment helps to understand what is going on.

Collapse
 
dinhanhx profile image
dinhanhx • Edited

Oh my! Documenting your code teaches beginners what you're doing

I totally agree on this. I write and read mostly deep learning Python code. Therefore, I understand the pain when reading undocumented inputs. Documenting these code not only teaches the beginners SOTA but also save time of running the code again just to determine what is the correct shape of a Tensor.

Collapse
 
curiousdev profile image
CuriousDev

But if you have beginners in a project, you can not rely a decision on this, which affects how the whole project and code is build. Again, just to provide an example, you would need to maintain the comments, if you do not, these will rather harm the process of understanding.
It is possibly a better approach to on-board and support beginners well. Allow them to contact and ask you whenever they need help. Be their mentor and teach them to work with the code like an experienced developer, do not create "code for the beginners" with comments all over the place.

Collapse
 
maxwebbnz profile image
Max Webb

Yep fully agree. It isn't harming anyone, but more so creating an inclusion to new people and beginners.

Collapse
 
paratron profile image
Christian Engel • Edited

My golden rules:

Add a summary at the top of a function about what it does.

This way I do not have to read and mentally parse your functions code to understand what it does.
This does not apply to very simple functions where the function name can describe everything like removeLastCharacter(). But calculateSingularityProbability() might win by some description.

Add comments to reduce mental work

If some line(s) are really complicated, add a short comment above describing what it does.

Add comments to explain hidden knowledge

Why are you doing array.pop() twice here without any appearant reason? Well, because I do know that the array always contains two empty entries at the end, which we don't want.
If you write the code, you have that knowledge at hand. Your team member might not. And you, looking at that code in 2 month wont remember either.

Collapse
 
flutterclutter profile image
flutter-clutter

I have to say, I disagree.

This does not apply to very simple functions where the function name can describe everything like removeLastCharacter(). But calculateSingularityProbability() might win by some description.

calculateSingularityProbability() is already a pretty good summary, isn't it? It shouldn't be necessary to describe formally what the function does exactly because, well, that's exactly what code is: a formal description of behavior.
If you write code that you think is hard to read and needs a comment then why don't you change the code instead of adding a comment? This is like creating a product with a crappy UX and then writing a descriptive manual instead of fixing the UX.

Why are you doing array.pop() twice here without any appearant reason? Well, because I do know that the array always contains two empty entries at the end, which we don't want.

Why don't you wrap the double array.pop() in a function named removeEmptyArraysAtTheEnd()? Shorter functions, single responsibility maintained and description inside the function title. No risk of "changing the function but forgetting to change the comment".

In my opinion, writing comments is the last resort and should almost never be done. Instead, keep functions very short (10 -30 LOC) and parameter count low. I recommend reading Uncle Bob's "Clean Code".

Collapse
 
paratron profile image
Christian Engel

I prefer reading one line of comment in human language than having to read 10 - 30 lines of machine language and parse it in my head to figure out whats going on.

I read that book. Also many others. 👍

Thread Thread
 
flutterclutter profile image
flutter-clutter

Don't you prefer to read one function title that describes on a high level in human readable language what's inside the function? Basically the same that would be in the one comment line?

Thread Thread
 
paratron profile image
Christian Engel

We went full circle to my initial comment. Yes, there are simple function where all they do fits into the function name.

Since functions are composed from other functions no matter how much you break things up, you will end up with something more complex. And the case will be even worse since I now have to scan all over the place nd go down rabbit holes to understand whats going on inside.

I also mentioned that its depending on the cases. You cannot generalize the topic.

Thread Thread
 
flutterclutter profile image
flutter-clutter

I understand what you're saying. I would argue, though, that only because you add a layer of abstraction to something, it doesn't mean that you need to understand every detail of the layer below to understand the abstraction. I would even say that's the purpose of abstraction.

So when you compose 5 functions in a new function, you don't need to read the code of the 5 child functions if they have a descriptive name.

If I wrap five HTTP requests in a repository, I don't need to understand the HTTP request logic to refactor the repository. I can stay in this layer of abstraction because I separated all the logic into smaller pieces.

I would argue that if a function does more than fits in the function name, the function does too much. If it's only one responsibility, it can be usually described in a short title.

But we may have made different experiences and we will possibly not come together and agree here and this is fine :).

Collapse
 
mindstormer619 profile image
Siddarth Iyer

I intend to write a full post about this sometime, but here are my thoughts in summary.

Self-documenting code doesn't exist because the purpose of documentation is different from what clean code gives you. Cleanly written code makes it trivial to understand how the code functions — nothing surprises you, the code isn't hard to follow or constructed of spaghetti, chunks of it fit neatly in your memory and it doesn't require you to go back-and-forth too often. You understand both the implementation and the abstraction quickly and cleanly. It exposes all of the how and most of the what, but what it doesn't necessarily do is explain all of the why.

Sure, well-written clean code with properly named functions and properties etc. can help expose the why, but it still requires you to do several iterative readings in any sizeable codebase to grasp the original business intent — namely, why does this code exist at all? What purpose does it serve?

That's where documentation steps in. Documentation should expose as much of the why as possible, and some of the what, without focusing at all on the how, since how it is implemented is quite literally implementation detail, and is subject to change even without the original business intent changing. The why changes very rarely, and also requires the least comprehensive documentation (the type of documentation that Agile tries to avoid) which is quick to read and grasp.

In my experience, pretty much every programmer I've met who has clamored for "don't write documentation, write self-documenting code" has parroted this statement because they didn't want to spend the time it takes to write documentation in the first place, not because they genuinely believe trawling through the code trying to tenuously grasp the intent of its writing is better than reading a short document about it.

Collapse
 
eslammahgoub profile image
eslam mahgoub

Agreed big, and so few developers know that I always hear those words and I can't argue.
Best line ever:
"Not commenting on your code is narcissist and excludes beginners, btw."

"Who said your code is as good and obvious as you think it is? Yeah, your mind." Yes Yes Yes a lot of developers say it and yes it's only good in your mind even the seniors will struggle with undocumented code.

Collapse
 
polterguy profile image
Thomas Hansen

Although I do see your point, and I myself tend to "over comment" my own code, there is a valid argument to the code being self documented. Interestingly, with a "meta programming" language, such as our Hyperlambda, the code literally is self documented, due to the abilities of the programming language to extract meta data from the code, being able to intelligently understand what each snippet of code does, to the point where you can write stuff that's logically similar to the following (pseudo code).

select c.filename from codebase c where c.code invokes(log)
Enter fullscreen mode Exit fullscreen mode

Of course the above is pseudo code, but still a perfectly example of something easily achieved with a "meta programming language", resulting in that your "comments" literally becomes its code, and information about what the code does can be dynamically extracted using automated processes, allowing you to easily understand everything your code actually does, without having a single comment in your code base.

Still, kind of out of fear from possibly being wrong, I tend to document my code (too much) ... :/

Collapse
 
jackmellis profile image
Jack

I've always found this to be a pretty egotist attitude. "My code is so good you shouldn't need help to understand it".
I've learnt there's a balance in commenting. There are really 3 use cases:

  • you need to explain the "why" of a function or a piece of code. Not the "how" or the "what", which should be clear from the code
  • a function has very complex or business-specific logic and it's 100x easier to talk the reader through what is happening than to just hope they can follow all the branches and call chains
  • you need to explain/excuse something stupid of illogical with how a 3rd party library or api works. If I find myself in this situation I often consider whether I'm using the best library for the job...
Collapse
 
flutterclutter profile image
flutter-clutter

And what is not egoist about thinking that a comment is so good that every reader should get what the corresponding code does? If you know by yourself that your code might be hard to read, then why don't you refactor it instead of adding an explanation? Reminds me of products with manuals that nobody reads. Always asked myself why they don't make the product of intuitive usage instead of writing a manual. Apple was the first big company to understand this.

  • The "why" is an artefact from the business domain and not from the implementation domain. The stake holder should know why he wants things this way. This is nothing that should be explained in the code.
  • Is it, though? If a business-specific logic is complex then it needs to be documented outside of the code. If the code itself is well-written but describes a complicated and ugly business-logic then why would you describe the code?
  • If a library has a complex logic then you need to wrap the library calls in your own class and make the wrapper as understandable as possible. You should also make an interface from it so you can easily switch to a different library when you get the hang of it. The caller of the interface shouldn't care about ugly 3rd party libs.
 
flutterclutter profile image
flutter-clutter

If it's really a matter of performance, then I agree. However, in today's web applications, performance on such a low level is almost never a concern. From what I've learnt, it almost always boils down to IO in a loop or other nested loops with cubic complexity.

Apart from that: readability > performance. Unless you're working in game industry or doing other low level stuff.

Collapse
 
jsantanadev profile image
Jean Santana

I'm so happy to see so rich discussion here in my article! Thank you so much devs.

Collapse
 
moopet profile image
Ben Sinclair

During your work, probably you faced a function that you asked yourself: "-What the hell is even that?"

Yes, but that's not so much because I didn't comment the code, as that I didn't write clean, readable code in the first place. If the bit of my wetware that needed to light up at the time to tell me to comment it had actually been doing its job I'd have written it better anyway!

Mostly, I'm on your side in this. I like commenting things. I like having a standard doc comment at the top of every function, even if it's "obvious".

However, I've had colleagues who don't, and their arguments are usually something like, "now you have to update two things", i.e. whenever you make a code change you need to make sure the comments and documentation match, and it's way too easy to forget. In fact, how many times have you seen the same comment repeated because someone's copied a component from one file to another to use as a kind of boilerplate, even though it has an entirely new purpose now?

Collapse
 
pinotattari profile image
Riccardo Bernardini • Edited

I guess that it is necessary some context, but to make it short:

  • High-level comments explaining what (not how) a specific function/package/class does is useful since allows the reader to orient itself in the code. Also, that is the kind of information that does not change frequently, so the probability that the comment gets stale is minimal
  • Comments to explain a non-trivial algorithm (e.g., the Euclidean GCD) can be useful, also to keep track of the conditions that are true at every point. Here assertions, loop invariant and similar stuff are your friend since they allow you to document what is going on in a way that the compiler can check, minimizing the probability of getting stale
  • Comments that explain why something is done. This is quite uncommon, in my experience, but it happens every now and then. Maybe there is a counter-intuitive way to do the things or maybe there is a strange check that seems useless and you would be tempted to "optimize it away," but it actually takes care of some borderline case that it is not easy to imagine.
  • The kind of comments that are wrong are maybe the most common ones that try to clarify what would had been clear if the code were written nicely. For example, instead of writing this
int d;
int c;      /* total cost */
int e[7];  /* daily expense */

for (d=0; d<7; d++) // Loop over the week
{ c = c + e[d];}
Enter fullscreen mode Exit fullscreen mode

better this

int week_day;
int total_cost;
int daily_expense[7];

for (week_day=0; week_day < 7; week_day++)
{  total_cost = total_cost + daily_expense[week_day]; }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
tqbit profile image
tq-bit • Edited

I don't think leaving out comments excludes beginners. Quite the opposite. Writing too much waste into your code sets a bad example. And I've seen more redundant comments than useful ones in codebases I worked on (including my own).

My favourite to this day is:

// Initial request to vendor API
// ... 3 uninformative lines explaining what's going on
// TODO: If fails, figure something out. First request should never fail
function getStuffFirstTime() { ... }
Enter fullscreen mode Exit fullscreen mode

Does this look beginner friendly to you?

If you do want to comment stuff, please write proper JavaDoc / JSDoc / whatever-Doc. That's what it's there for.

  • Use @desc, @property/s and @returns.
  • Give a 2-liner about what your code does if you must
  • If you must use a comment inline, you will probably be better off refactoring your function or method anyway

And if you want to go bonkers, at least be so kind and do so in your automated test suites. You can even use @see in your production code base. And everybody wins.

Collapse
 
adrvnc profile image
Adrian Carter

Great article! Writing comments about what your code does can be helpful. But, I've learned that writing too many comments can be excessive.

Collapse
 
lexlohr profile image
Alex Lohr • Edited

I use comments in the code very sparingly and only to tell the story about the reasoning behind the code if that should not be obvious even to a beginner.

I'm very liberal with elaborate JSDoc blocks above my API interfaces, though.

Collapse
 
darthbob88 profile image
Raymond Price

The line I always take with students I mentor is that I don't need a comment to tell me what the code is doing, because I can read the code just fine, and most of that can be encoded in variable and function names, like frobnicate_the_input_array() and input_array_to_frobnicate. I need comments to tell me why it's doing that, and particularly why you're not doing it a different way.

"But requirements and statements of purpose don't belong in the code! They should be in other requirements documents." As a developer, I have ready access to the code I'm working on, not the requirements docs, and I especially don't have anything to connect frobnicate_the_input_array to a requirements doc saying that the input array needs to be frobnicated, or to a later decision saying that it needs to be frobbed in reverse order. That's what I need a comment for.

Collapse
 
chasm profile image
Charles F. Munat

This is a straw man argument. I don't know a single developer who never writes a comment. The argument is over whether you should comment everything, or just when a comment is needed, which is inversely proportional to the amount of clean, readable, and easily understandable code you write. The argument is not that you should never comment your code.

If you have to make up a straw man argument, then your credibility as an authority is undermined.

Collapse
 
sinewalker profile image
Mike Lockhart

"There are two hard problems in computing: cache invalidation, and naming things".

Naming things is hard, which sometimes leads to comments. For the longest time I was a proponent of comments, and it is what was drilled into me growing up. I never heard about them being "useless" or that they should be avoided until the mid 2010s. Now I try to be pragmatic about them: and always consider "does this comment bring value?" "If so, could the code be changed to make the comment unnecessary?"

My reasoning about this, including some pet peeves and "uselessness" is in one of my old blog posts. The counter argument (use docstrings / doc-comments if your language has them) is in another.

Meta:- I should clean these up a bit and post on DEV...

Collapse
 
eelstork profile image
Tea

Guy who write the code usually don't have enough distance (and often not enough skill where, documenting is an animal in its own right!) to document the same.
I encourage devs to ask questions, and document code they come across when they don't get it (hopefully, after they figure it out). This means that, the meandering effort you refer, of figuring what it really does... Somebody, in my experience, have to do this at least once.

Most, "horse did, horse mouth documented" code I come across - the docs in there paraphrase the code - dead weight which I promptly delete in a separate commit (sneering is not productive, removing dead weight is)

Good comments often signal bad code. Guy suddenly realized some danger with their code, wrote a comment and moved on cause no time to fix. Which is perfectly fine. They save somebody else the trouble of falling into a trap, and boost the confidence of the time-endowed person who are going to fix the code, and delete the signpost.

I'd much rather a // bad code comment than nothing - because I respect my co-workers. If something looks twisted and isn't labeled bad/clumsy I'll assume its crooked for a reason, whereas sometimes it's not.

Part of being an API designer (and much code isn't "API" just grease) is having a knack for roleplaying as a beginner, and adopt the TLDR mentality of somebody who need to understand something, but are lacking the time and dedication to do verbose let alone code.

Not all code that needs documenting is bad, but writing code that people just get without much effort (and if possible reading signatures NOT the code) is a good smell.

Collapse
 
joelbonetr profile image
JoelBonetR 🥇 • Edited

Ok so there are like 100 comments that I honestly won't read (I was eager to read the first 10 but got tired at 5).

What whas that? It's honesty. We all should practice it when coding, because we know what we are doing at the time of coding whatever but we should be honest and think that "My future me will love to see comments on this code".

"Yeah but there are functions that are SOLID and don't need comments because blah blah"

I had the exact same conversation with a colleague the other day so let's mimic it:

const getUserById = async (id) =>  await User.findOne( { where: { id: id } } );
Enter fullscreen mode Exit fullscreen mode

Is it straightforward, isn't it?
But how do you know what it returns?

"But Joel, it returns a user, A USER!"

Nope, it returns a Promise that hopefully will retrieve a user (as long as it exists in the DB).
And me and you, and the rest of the team will love having this information without the need of Ctrl+Click over the function name to see what is doing behind the scenes.

/**
* Retrieves a user from the DB based on the ID
* @param {number} id 
* @returns {Promise<Object>} User
*/
const getUserById = async (id) =>  await User.findOne( { where: { id: id } } );
Enter fullscreen mode Exit fullscreen mode

So when you are about to use this function you get:

Here it is! Inference! Beloved inference.

Moreover if you use TS pragma

// @ts-check
Enter fullscreen mode Exit fullscreen mode

at the top of your JS file it will use TS when it's important, in dev time.
Without adding TS as project dependency plus without the extra bundle time of compiling/transpiling TS into JS.
It will use JSDoc to type-check your functions and variables. VSCode will handle it out of the box.

So if you try to do something like passing a string it will correctly complain like that:

Look how cool it looks like!

// @ts-check
import { User } from '../db/models/users';

/**
 * Retrieves a user from the DB based on the ID
 * @param {number} id
 * @returns {Promise<Object>} User
 */
const getUserById = async (id) => await User.findOne({ where: { id: id } });

/**
 * Gets a cookie value by name
 * @param {string} name
 * @returns {string}
 */
export const getCookie = (name) => {
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return parts.pop().split(';').shift();
};

/**
 * Retrieves the user ID from the browser cookies
 * @returns {number}
 */
const getUserFromContext = () => parseInt(getCookie('uid'));

/** @type {User} */
const currentUser = getUserById(getUserFromContext());
Enter fullscreen mode Exit fullscreen mode

It looks even cooler in VSCode as it changes the color for the JSDoc when properly written:

Sooner or later I receive either a "you are right" or a "you were right" about that.
I had been in enough projects to say that this is a must.

Collapse
 
flutterclutter profile image
flutter-clutter • Edited

"Why" is a question that has nothing to do with the implementation. It has something to do with the requirements. These come from the stake holders. They should document the requirements somewhere else, not in the code. If the code is the single source of truth for the requirements of your software, then you're doing something wrong.

Collapse
 
jcolag profile image
John Colagioia (he/him)

I've been ignoring this, because I'm tired of the "conventional wisdom (or a straw-man version) says X, but I oppose that" genre of article. However, there are a couple of points to make.

First, as I hinted, nobody really says not to document your code. No (serious) programming language lacks a way to write comments, and several try to shift the focus to the comments, so-called literate programming.

That said, comments are almost universally an admission of failure---the "I don't actually know how this works, so don't touch it" style---or vapid descriptions that have nothing to offer beyond repeating what the code does...or, rather, they repeat what the code did when it was first written, but haven't received an update since then. How much time in your career has reading a comment saved you?

The problem is that "comment your code" implies the latter, inserting comments that follow the code. "This assigns the current total to the total variable." "Loop over the array indices." "Increment i by one." Not only are those comments useless, but they make maintenance more difficult, because someone needs to always double-check to make sure that the comments reflect the code...but you already have the code.

Rather, you want to comment the project, from within the code. For some examples.

  • Why did you write this passage? Specifically, if business conditions change, what changes would lead me to delete the code?
  • Does the code implement some standard, such as an algorithm, a design pattern, or an RFC?
  • What trade-offs did you make in this design? What technical debt did you accrue to meet the deadline? We all need to make expedient choices, sometimes.
  • Did you adapt the code from another source? Does that code require crediting the author?
  • Are there edge cases that the code deliberately doesn't bother to cover? Why?
  • Is there a passage in a design document describing the need for this feature? Other than a ticket, I mean, which your commit message should reference, instead...

If, instead of covering that kind of ground, your comment explains the syntax, though, then you should rewrite the code instead of writing the comment. If the comment explains what the variable name means, rename the variable, instead. Those comment the code, and no developer should be forced to read them...

Collapse
 
codefinity profile image
Manav Misra

It's a balance. If creating code for demos/illustrative purposes, definitely need more comments. Otherwise, think 2x before putting long comments. Usually, I will add a comment if I found that I screwed up more than a couple of times b/c I forgot the same thing. That's a good spot to put a warning comment or something like that.
Also, add comments when there is a better approach, like a refactor, but we are not doing now b/c of time shortage, for instance. Like a: // TODO. You can even do comments that kind of assign for someone else like: // TODO{john.smith} They can search for their name, etc. Probably can connect to some type of workflow that will automatically generate assigned issues using the comment in GitHub.

Collapse
 
koire profile image
Koire • Edited

I always argue for documentation comments, and against random comments.
*Doc, if it's written well is always welcome. One line comments before a function call of the same name are generally terrible!

#publish post
self.publishPost(post)
Enter fullscreen mode Exit fullscreen mode
Collapse
 
curiousdev profile image
CuriousDev

First, if you start using comments to explain your code, you will have to maintain these as well. Guess what, this likely will not happen everytime, because people need to always keep in mind to do this whenever something in code changes.
Second, code can be self-explaining without the need to look for a certain function. Usually the naming and how you build the whole project helps a lot and maybe sometimes it is necessary to see, what other functions are called, too. But if you cannot understand it without looking for many other places in the project, maybe something different is wrong and the issue is not missing comments. These would rather patch the issues, not solve them.
I am not asking for to not comment, but usually there are only a few special cases, which actually need comments and this can be very specific to the technologies chosen.
Is it just me or feels the "mental health" and "inclusion" part again just following a trend? I would not say it is wrong (I am totally with you in sense of, that not everybody is the same and we need to respect and support each other), but I do not see, how the commenting part has to be necessarily connected to this.

Collapse
 
hugozap profile image
Hugo Zapata

You can have high quality comments and that helps a lot navigating codebases.
There's usually a lot of context behind the decisions for some routing and for code that has to be read a lot (99% of it) they help.

For enterprise apps that have been touched by lots of people (most of them already gone), comments are valuable. I've found important warnings/explanations and it's saved me hours that are spent in better ways.

Comments are async communication and expand context beyond the mere computer instructions.

Collapse
 
leob profile image
leob

Write comments if you need "external" context to understand "what the heck" this piece of code is doing - by "external context" I mean knowledge/info that can't be derived from that piece of code (function, method, class, module) itself.

Collapse
 
blackscorp profile image
Vitalij Mik

I do not agree in some parts, your code is changes, the comments often not. once you found several times a comment which lied to you, you start to ignore them. then you have often autognerated code for your linter and pipelines and setter etc which often is also teaches you "just ignore it". if your code has many stuffs which is just boilerplate or self explained you start to ignore even more the comments. so if you have code parts which is ignored by others, then people will do not take care of it since noone relies on it.

if you have a code which usually has no comments but then you find here and there one line with a comment which describes why it is there, then this is very usefull. you need sometimes comments, describing a regular expression or a method which do nothing or something weird but in general for most cases your code should be readable and understable enough. i changed in my editor the comment color to red or even pink. and if i see too many of this color which is useless, i just delete it because it hurts to look at it. and if i find a comment which is required, the bright pink color reminds me to read it because it is an important part there

and if you leave your job, make sure have ENOUGH, unit, implementation and e2e tests (also more unit tests than impl. and more than e2e follow the pyramide) which runs FAST and can tell you RELIBALE that your project or at least the critical parts of it are running without failure.

Collapse
 
matthewsalerno profile image
matthew-salerno

I have seen code with too many comments. Something like five lines of code having 5 lines of comments each, which really breaks the flow of reading code for such a simple function. That being said, I think it's important to describe the purpose of each block of code with some standard format. It also helps some IDEs provide you with infirmatiomnon mouse over, which is incredibly helpful. So that being said, I try (and usually fail) to use my comments like so:

  • 1 comment all functions, classes, blocks, etc with a brief description. Even if its something dumb like "this add function adds two numbers", it can help for the IDE
  • 2 if logic of implementation isn't obvious, and can't be made obvious, describe it as best you can either by pointing out subtleties on certain lines, or a full explainer before hand if it's really that bad. Most of my projects have been independent though, so I'm slightly ashamed to say I don't write as many comments as I'd like.
Collapse
 
davinderpalrehal profile image
Davinderpal Singh Rehal

There are certainly scenarios where writing comments can be useful, though I would also argue that you should not use comments as a cruch. Anywhere your logic is complicated by all means write a comment, but if your logic is not complicated you should focus on giving the write name to your function. For example.

/**
* Applies filters in the following order if they are set
* Date -> Category -> Sub-Category
* @param filterObj {
*    date: asc | dsc,
*.    cat: asc | dsc,
*.    subCat: asc | dsc
*.    }
*. @return filteredList
*/
function applyFilters(filterObj = null)
Enter fullscreen mode Exit fullscreen mode

But comments don't make much sense in the following example

function filterListByDate(isAscending = true)
Enter fullscreen mode Exit fullscreen mode

First preference in my opinion should be to name things properly, use the single responsibility principle as much as possible and then if logic is still complicated then add comment.

Collapse
 
jankapunkt profile image
Jan Küster

Good variable names indicate what concepts are involved. Clean code can document the execution model (what the code is and how it functions) but code itself can not explain "why" a certain routine had been chosen in favour of others.

From an engineering perspective the "why" is important to reason about the code on a higher level than just the few lines in front of the eyes.

From my experience with reading many many open source project code I can only say: the more comments explain what's going on, including well written jsDoc, the better it was to create a PR to that code.

Collapse
 
michael_shobowale profile image
Michael Shobowale

I think if you have to make comments to say what your code is doing, then it probably wasn’t written to be readable.

Comments are good as long as they aren’t unnecessary comments like commented out code.

Generally I don’t like having comments at all, because they sort of keep the code looking messy.

Collapse
 
lorenzotrojan1 profile image
Lorenzo Trojan • Edited

Too many comments are not just useless, they're detrimental to legibility, and are a typical feature of poorly designed code

As a rule of thumb:

  1. (90% of comments - docstring) Clarify function signatures, in particular types
  2. (9% of comments - docstring) Occasionally provide a code snippet on how to use the function
  3. (0.9% of comments - docstring) Occasionally refer to one or two other related functions, especially when the other functions are not totally independent (for example when function calls should follow a given sequence)
  4. (0.1% left everywhere) these comments are used to explain complex lines of code and may consists of references to whitepapers and documentation elsewhere and should be used primarily in functions implementing a complex/new algorithm

Feeling completely lost in someone else's code is not at all correlated with amount of comments, it's associated with poorly designed code

Collapse
 
js_bits_bill profile image
JS Bits Bill

The types of comments you should write and the amount, like everything, depends on context. Here's my perspective on this I wrote here: dev.to/js_bits_bill/happy-medium-c...

Collapse
 
russellbateman profile image
Russell Bateman

There are only two disadvantages to writing comments. First, and least important, is the column inches it may take up. Annoying, at best. Decent IDEs will collapse such a comment if asked.

Second, however, is that, like code, comments can become stale and therefore misleading or unhelpful. This is very serious. Comments must be updated as part of the code they describe should that code ever change. Because comments are code.

Not writing and maintaining comments is narcissistic and brazenly hostile to a) others who read your code trying to figure out what you meant to do and b) yourself down the road a few years should you have to do the same thing as (a).

By the way, not writing unit tests is also unforgivable and an "armed assault" on others just as is (a) above.

Collapse
 
klausdonnert profile image
Klaus Donnert

Most of my comments are for me 6 months from now when I will be asked to debug or modify the code again, and I surely will ask myself "what the heck was I thinking when I wrote this"? It happens to me all the time.
I'm dealing with 20 years worth of legacy code - some methods have 20 - 30 optional parameters and almost no comments anywhere - it takes hours to make even minor changes because the person who wrote it thought it was so obvious what their code does. And then on top of that, single and 2 letter variables names all over the place... Refactoring that mess is a nightmare of technical debt.
If you don't comment your code you are some combination of lazy, narcissist, and noob or someone who just thinks that they are smarter than everybody else, and you may well be. But the people that wrote the mess I'm fixing weren't that smart - but they thought they were.

Collapse
 
aminmansuri profile image
hidden_dude

Sometimes people say comments are "distracting". But I've always made the syntax highlighter make them light grey so I can tune them out visually if I want to focus just on the code.

That being said.. I've been through enough nightmares to know the value of good comments. I'd definitely say any comment is better than none. But in my experience code very rarely has comments (when not written by my team).

Collapse
 
rishabh570 profile image
Rishabh Rawat

I believe there needs to be a balance. It's hard for me to believe that one can achieve the highest standards of readability in a production-level application with no comments. If written well, code will explain everything related to how stuff is happening. But based on my experience, there's always a need to document "why". And code often fails to achieve that without comments.

I think it's a quite known fact that real-world apps need to sometimes take paths that aren't intuitive, you would insert if-else in your function possibly destroying the single responsibility principle, because of business needs.

A comment explaining the purpose of what your code is doing is always welcomed.

Here's a talk by Sarah Drasner on Code comments, can check out if interested.

Collapse
 
leandroskounadis profile image
JsRocks • Edited

First please don't promote wrong things!
I honestly didnt know where to start arguing so i won't and I will give you another perspective.
Being in a real world project with multiple teams or devs working on it is complex enough. If for whatever function or line you need to comment might as well change jobs. This is not scalable at all. We have all sorts of tools at are disposal. Typescript, unit tests, automation tests, documentation of features (not blocks of code) function complexity tools.
Commenting means one of the two things when code isn't self explanatory that you are doing too many things or you aren't giving correct variable, class, function names so things needs to be explained. Again this isn't ok. This needs to be corrected. Leaving a comment will solve the situation at that moment. What about when someone refactors that piece of code. The chances of the comments being updated accordingly are slim to none

When you read code you need to understand it. Having comments negates the purpose of readable code and allows windows of badly written code because "well it was difficult so i have added a comment". but then another dev comes to enhance the functionality and will either read the comment and understand nothing because most likely it's an essay which makes no sense so he starts reading the code and again makes no sense of it so he starts debugging line by line till he understands it. If you can write good comments and bad code then ask someone to help you write in a way that's readable. If your content is short and still have to write it, seriously look at your code and find out why you need to comment it. Something so wrong. Sit and think plan or what you want. Finally and most importantly unit tests are your documentation of your class or module. If you don't understand the code in place read the unit tests which should have good description of functionality not a comment which will be deprecated in the first iteration.

Don't use comments as an excuse to write tens or even hundreds of lines code cause the only thing that you are adding to is complexity for the next developer to have to read through and try and change which will most likely lead to a refactoring.

If what whatever reason you meant documentation in your topic this is completely different and i couldn't agree more with you but i don't think you do.

Please don't promote bad practices cause if others adopt what you suggest repos will double in size :p

Collapse
 
tojacob profile image
Jacob Samuel G.

Good practices and conventions are what allow self-documenting code. Not your mind. I wouldn't advise a newbie to avoid comments. Naturally someone who starts out doesn't know anything about architecture. There is already a structure and pattern for everything we want to do.

Collapse
 
mosbat profile image
mosbat • Edited

I think that people missed a point in Uncle Bob's book about this topic. He did say that writing comments is an excuse for bad code, but he did mention somewhere that it's OK to add a comment if a certain function or block wouldn't be obvious to others if for example there is no way to make it better.

Collapse
 
brense profile image
Rense Bakker

The function name should convey its purpose. Same for the params. When I see a docblock above a function it usually means one of 2 things. 1. The comment is entirely redundant or 2. The function doesnt have single responsibility.

Except in config files I've never seen a comment that told me more than the code itself. The inverse however is true. I've seen a lot of outdated comments that no longer convey the purpose of the code, or even comments that flat out lied, because they were copy pasted from somewhere else and not updated properly.

IMHO docblocks make devs lazy. Focus on writing good clean code (there are books about that if you're interested) don't waste everyone's time writing comments ;p

Collapse
 
escapeboy profile image
Nikola Katsarov

One problem with the commenting code I see is that when you write "what" code does then you are gonna use commenting as excuse to write bad code. Like "Hey, that code smells", "Ya, but I have comment which explains all". And you don't feel the need to write better code.

Collapse
 
the_one profile image
Roland Doda

Well... I don't agree!

I respect your opinion and I believe that if is a team standard you should follow that.

But in my opinion, if you write clean code you don't need to write comments. In fact, it makes the code unreadable.

Of course, comments are allowed when you think the code it's not selfexplanatory and writing a comment is a better solution to explain some code.

I usually add comments when I fix a bug and there is no way that my code can explain why that code is added. So I only add a comment with a link reference to the issue. Or sometimes when I add a utility function that needs some small comments and why the code is written in that way.

You have to keep in mind, that writing comments, means that you have to maintain them too! And that means, whenever you change the code, you have to update the comment too which is tricky if you write many comments because usually code have dependencies on other parts of the code and then you will end-up maintaining a comment that is written elsewhere which might have no relation to the code you changed.

Another reason is that adding many comments makes the code verbose and sometimes you will think that removing all the comments makes it easier to follow the flow of the code and/or read the code.

I have worked on a project which was full of comments and was the worst experience ever for me.

Personally, I always try to avoid writing comments, and if I see that a component is way too complex, I prefer writing a "component.readme" file explaining the complex topics that need to be explained for that component.

Another important part of not having comments, is Git. If I fail to understand something in a file, I simply look at the histofy of that file. Many times it has helped me understand what I was looking for.

Collapse
 
assertnotnull profile image
Patrice Gauthier • Edited

More often I have seen comments that led me to spend time wondering what it means and in the end find out I've just wasted my time because it was outdated. Comments are used when it's too complex to read.. then the real problem is that it's too complex and should be simplified. Comments should be rarely seen and explain the "why" it was done this way. Explain why you had write this exotic solution.

 
flutterclutter profile image
flutter-clutter

Okay, maybe I am viewing it too much from a business perspective. It seems like there are a lot more specs from a non-technical view there. This somehow eliminates the need for specs inside code.

Thread Thread
 
flutterclutter profile image
flutter-clutter

If you use comments as way to communicate with other developers working on the same code base and have no real communication channel outside of that, then I can better understand the necessity!

Collapse
 
rodelta profile image
Ro De la Rivera • Edited

After thinking and experimenting with this a lot, I'm convinced the rules are simple.

  • Inline comments only answer "why". What, where, who and how should be represented in the code by correct encapsulation and naming.

  • Comment external interfaces so they show in the editor. For example, a function should have the parameters commented, a class needs the constructor commented. This comment should never contain the name of the variable/parameter.

  • Comment after a bug fix, to avoid falling in the same error again.

That's it. Excessive commenting is lies waiting to happen.

Collapse
 
flutterclutter profile image
flutter-clutter

For me, the necessity to add comments to code is a smell. If you realize, your code might be hard to understand, then why don't you refactor the code instead of adding a manual? And what makes you think that the manual is understandable if you're incapable of writing understandable code?
Do you think Apple would ever give out a bloated manual for their products? Or do they just create products that are intuitive?

Also, I don't agree that code is more maintainable if it's commented. What if there are changes to the code and/or the comment and suddenly the code and the comment have contradictory statements. Which do you trust - the code or the comment. And when people realize something like this happens, they stop trusting the comments inside the code and it becomes a mess all over the place.

There is a reason why we can name classes, functions and variable. Because they are supposed to be descriptive. Why don't we use this opportunity to write self-documenting code instead of relying on a meta layer like comments?

Collapse
 
elwanderero profile image
Daniel Zavala Svensson

I think a lot of this whole "code should be self-documenting" critique of comments implicitly assumes that comments are used to document WHAT the code does.

But I find generally find the most useful comments talk about WHY the code does what it does. Which the code does not do, no matter how good the variable names or the structure is. Especially in enterprise code bases with hundred of thousands of lines och code.

It is completely obvious what deleteLastRowInTableIfSecureFlagIsSet() does. But why? If the system is re-architected to no longer use secureFlag, what should happen here? If there is a bug related to the function, what is actually the correct behaviour? If we switch from SQL to a key-value store that doesn't have a "last row" what should happen?

So IMO a rule of thumb is that good code comments explain WHY, not WHAT. And in that light this whole debate misses the point.

Collapse
 
gosukiwi profile image
Federico Ramirez

I think people is just taking things literally. The people who told you comments = bad were just parroting what they read online and didn't fully understand.

There is a place and time for comments. IMO, they should be the exception and not the rule though, or at least the coding standards should aim for that.

It's much better to have a small, self-documenting method, but it's also very damn important to have a good, descriptive, multiline comment in a chunk of complex, messy code.

Just use your brain people, there is no silver bullet.

Collapse
 
varanauskasd profile image
Varnas

An emphasis on self-explanatory code should still be the key.

Writing out params is verbose and possibly trivial, unless they are not clearly defined. For Javascript, Typescript is really helpful in achieving this, but it shouldn't come at a cost of adopting poor naming conventions. More likely, code's context and purpose is more useful as a comment, rather than a technical explanation of individual variables.

Ultimately, it's up to the team to agree on maintainable code practices, adhere to them, and ensure code readability.

Collapse
 
spo0q profile image
spO0q 🐒 • Edited

You have pretty strong points in your article. I noticed popular programming languages such as PHP are evolving on this point, though. For example, named parameters self-document the code. Union types allow skipping verbose PHPDoc annotations.

IDE can map such features and auto-complete parameters. Probably more efficient than multiple lines of description.

However, nothing is magic, and IT likes catchy slogans and bold statements like "Do not comment your code, it should be self-documentated."

I think it's misleading. The right statement would be "write your comments carefully" or "use comments with caution."

I really appreciate comments that explain the dev's point of view or specific constrainsts that leaded to particular choices. There are always pros and cons, and it's easy to judge someone else's code without the context.

Collapse
 
dezbrown profile image
deZbrown

When you run into a function that is hard to read, after you get the job of understanding it, do a refactor in such a way that the next time you come across that function, it's easy to read. No, need to do comments if you invest in code improvement. And code improvment is investment as comment writing is debth.

Collapse
 
garyfuhr profile image
garyfuhr

I think comments are valuable, but only if the comments come first. Outline what you plan to code first will give you focus to ensure a better outcome than the other way around.

I found when devs comment after, the comments tend to describe what the code does instead of what is the intent or the "big picture".

Collapse
 
kashanshah profile image
Syed Kashan Ali Shah

Well, in my opinion, your code should be as readable as any english paragraph. Which, at times, is not achieved, so you can add some not-so-obvious comments for that. But the focus should be writing clean and readable code.

Collapse
 
panditapan profile image
Pandita

We need a hemingway app for code so a lot of those "I write clean, readable code so I don't need to add comments" devs will ACTUALLY have something to back up their claims XD

Like a "yes, your code can be read by a recently woken up and without coffee junior/senior dev". With "congrats!!! your code can be read by your non techie parent" being the ULTIMATE score.

/#DontStealMyIdea 😎

Collapse
 
codbugs profile image
Coding Bugs

Having read almost all the comments, there are none that indicate how the content of the comments should be as it is the most important thing.

In my case, I try to avoid commenting whenever I can to force myself to make the code readable by itself. This way, I make sure that any colleague and even myself are able to understand the reason for that lines of code.

Comments are useful when explaining the reasons for the code and not telling what it does or does not do. For example, if you have followed the "Proxy" pattern, it is convenient to explain what each of the classes represents and the reason for creating them.

Collapse
 
hugozap profile image
Hugo Zapata

Comments are a way to communicate with your future self or other developers about the intention of the code, potential pitfalls, warnings, etc. Having comments in code means there's additional context information directly related to the source code.

I see comments as good etiquete and feel grateful for whoever took the time to write them, they have been valuable to help navigate codebases. Sure you could do it without code but why waste valuable mental bandwidth trying to figure out stuff that can be easily put in comments?

They are good, use them!

Collapse
 
norton120 profile image
Ethan Knox

A piece of the perpetual "self documenting vs commenting" argument that I don't see surfaced often is when you mix logging into the equation. Especially if you have a mature logging strategy with comprehensive debug log events, the same code that serves to improve observability also acts as a form of human-readable documentation

Collapse
 
birdtho profile image
Christopher Thomas

Comments are useful to me when:

  • You're telling someone why this is being done, in the general sense
  • You're explaining an algorithm that isn't clear
  • You're explaining a business decision / business logic
  • You're leaving a TODO for yourself to implement later or fix or come back to finish
Collapse
 
emdebarros profile image
Em De Barros • Edited

It's so important that you mentioned people who live with different conditions, like ADHD. This can, indeed, make the process of analyzing and understanding code even harder.

I don't think comments are the nemesis of good, reusable, and maintainable software. However, I do believe that your code should be self-documenting (to a certain extent). What I mean by that is that comments should be your last option. Let me explain.

The issue with leaving comments in the codebase is that they often are used as a simple fix for non-descriptive variable names or inflexible design that violates principles like the SOLID principles. Comments also tend to become technical debt, since they are rarely updated when the code evolves. So, here's my thought process when I feel that I have to leave a comment in the codebase:

  1. The best form of documentation is self-descriptive, easy-to-understand code. With that in mind, I ask myself if I violated any software design principle. If yes, I try my best to refactor my code so that it is as clear as possible.

  2. If refactoring is not enough, another great way of supporting and documenting your code is with... documentation! There is so much to be said about documenting that I wrote an article on how to document your work as a software engineer and why it's such an important skill to master. Check it out 👉🏻 Conquer Your Fear of Documenting in 9 Simple Steps

  3. If, refactoring and technical documentation are still not enough, that's when I allow myself to insert comments in the codebase. Depending on the programming language that you use or the IDE, there are different standard approaches and formats you can use so that your comments don't end up being tech debts down the road.

Bottom line, comments can be very useful to visually help you understand each and every step of your code, especially when implementing new features. However, when you're collaborating and/or when you're working on a prod environment, there are several guidelines to adhere to in order to maintain good, readable, and clean code that is scalable and easily maintainable. These guidelines put a bit of order in the chaos that can arise when coding in a shared codebase.

# outro
With that in mind, you can turn tech debts into powerful assets!

Collapse
 
tonyknibbmakarahealth profile image
TonyTheTonyToneTone

I tend to comment my code in blocks, so I can find blocks that do stuff, without having to digest each and every line of code. I know what the code does when I read it but... why would I want to read it if I don't have to?

I do agree that you shouldn't need to comment every single line. That would be ludicrous.

Commenting functions/classes/methods and blocks of code is just good practice imo. Six months from now I don't want to have to strain my brain, reading 50,000 lines of code, to find a block of code that needs updating. ¯_(ツ)_/¯

Collapse
 
cjw profile image
Clifford Watson

Glad I found this

Collapse
 
smpnjn profile image
Johnny Simpson

I have never ever heard anyone say you shouldn't comment your code. I'm sure no one is expecting a novel in your code, but commenting your code is simply best practice.

Collapse
 
sabbakilam profile image
SabbaKilam

Wow. This article provoked a lot of comments. Maybe they all should have been written in self-commenting code.

Collapse
 
polterguy profile image
Thomas Hansen

Good point, but I was speaking of the ability to runtime extract semantic data about what the code does, not reading the code itself ...

But you've got a very good point ...

Collapse
 
davelapchuk profile image
Dave Lapchuk

I try to make code as readable and self-documenting as possible, but add comments wherever it makes sense for outside context (i.e. the why as opposed to the how).

Collapse
 
vladi160 profile image
vladi160

Sure, there should be no poverty, suffering, wars, but there are, because not everything depends on us or/and something depends on us ;)

Collapse
 
save profile image
MegaYT14

Personally I comment my code, but for me.

So I leave my old note's

This is my opinion but ok.

Collapse
 
rajeshroyal profile image
Rajesh Royal

Agreed.

Collapse
 
kbaylonh profile image
Kevin William Baylón Huerta

There are situations where the name of the function, method or variable cannot explain by itself what it does. I think that in that case, it is necessary to write a comment.

Collapse
 
mxdpeep profile image
Filip Oščádal

I hope for the best comments and an average code below them - comments express the intention, the code itself is the transformation of the intent

Collapse
 
sebbdk profile image
Sebastian Vargr • Edited

When you only have a hammer, everything looks like a nail. :)

Collapse
 
themmako profile image
notsoavailablemako

yes it's true i just looked into my older js projects and i didnt remember anything thankfully i putted comments in it