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 code, but after working in a big projects with a big team, the only thing I can say is: Not commenting your code is narcisist and excludes beginners, by the way, who said your code is so good and obvious as you think it is? Yeah, your mind.
During your work, probably you faced a function that you asked yourself: "-What the hell is even that?". Many of us experienced this situation, even with our own code after some weeks far from the project. Now, imagine if instead of you have to waste your time, searching through the houndreds of files for the right function you need to put hands on, you could have just comment your code telling the function purpose, its params and what it should return. Life could be a dream, right?
Also, we cannot asume the everybody think like us and we are being so obvious. People have different ways to analyze things, we have people that are less experienced or even have mental health conditions like, anxiety and ADDH, and that makes the process of understand some pieces of code even harder. Should we just exclude them because we can't use one single minute to comment our complexity? I think we shouldn't.
The question is not about if you should comment your code or not, but is what you need to comment in your code and how it should be done.
Write a clean and easily readable code is unegotiable, and you get better on this with experience, but you can also write clean and good comments, so it can be used as a reference for you and the others, and it do not make you a bad programmer, on the contrary!, It makes you a better professional,your code will be easily maintainable, plus, you're ensuring that no matter the level of who enters on your team, they'll get it faster and start working on the project, and if you have to leave your job, the devs that comes after you will be grateful and thanks you everyday before they going to bed. (okay, I'm not so sure about this last part).
βPrograms must be written for people to read and only incidentally for machines to execute.β - Hal Abelson - MIT Professor.
Recommended reads:
Best practices for writing code comments
Top comments (98)
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.
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.
If they can't write clean and readable code, why would you think that they can write clear and understandable comments?
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.
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?
You made that up. Nobody is that bad. I did get a chuckle out of it.
It was a joke. But it's not as far off as you might think. :-)
I consider comments as documentation. If a programmer does not document their code... I don't have energy to finish that sentence.
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.
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?
Sorry, I misread your last comment as saying that all code had to be commented. I rarely comment my code.
Instead I:
function returnFalse() { return false }
this
, typically in callback functions (anywhere you might useconst self = this
)any
type
notinterface
-- interfaces are mutableunknown
in production codeAlso:
index.ts(x)
ormod.ts(x)
import not from "~utilities/not"
not
function and use thatimport type
for type imports, it's cleanerapps
folderutilities
folder (for generic utilities such asnot
,pipe
,identity
)services
folder for any bespoke services (i.e., not in an npm or deno module) such as authenticationmodules
folder for any reusable modules (e.g., generic components, icons)import doIt from "~apps/TicTacToe/utilities/doIt"
rather thanimport 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 returnsquery
andmutation
functions. So the actual URL, query, variables, etc. are provided where they are used. None of this is hard coded in theuseGraphQL
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:The benefit of this is that:
.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)<TicTacToe />
) elsewhere in the appI 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:That is the entire file! Three lines. Here is a somewhat longer one:
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:
Other than a few polyfills for
Intl
andTemporal
,fetch
, anduuid
, my app uses only React, XState, and, sadly, Auth0.js (not my choice).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 oftenmap
,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.
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
@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!
+1 I couldn't have said it better myself
thanks
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?
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.
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.
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.
Yep fully agree. It isn't harming anyone, but more so creating an inclusion to new people and beginners.
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()
. ButcalculateSingularityProbability()
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.
I have to say, I disagree.
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 don't you wrap the double
array.pop()
in a function namedremoveEmptyArraysAtTheEnd()
? 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".
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. π
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?
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.
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 :).
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.
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.
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).
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) ... :/
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:
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.
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.
I'm so happy to see so rich discussion here in my article! Thank you so much devs.
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?