There are a lot of arguments that have gone on over the years around comments. Many are adamant that "good code comments itself", while others favor including good comments in their code and argue they should be required. When I read and hear these arguments going on, I've noticed they're frequently focussed on the What and How of the code...ie. What the code does, and How it does it. But very rarely does the concept of the Why enter the discussion...ie. Why was this code needed, or Why was it written this way. While there are valid arguments on either side, it can be difficult to know which direction to go. This lead me to create 3 rules I believe not only help to bridge the 2 sides, but also encourage better code to be written. I'd like to share my 3 rules with you in the hopes that they might help you as much as they have me.
Rule 1: Names should explain What
The name of a variable, parameter, interface, function, class, method, or some other thing in your code should provide sufficient information to clearly describe What that thing does or What value it holds. Another dev should be able to read the name of the thing weeks or months later and know exactly What it does or What it holds without needing to ask, look through additional code, or read additional documentation. If they do, the name should be changed to be more clear.
To add some clarity here, it's important to note that the name is not responsible for describing what something is used for. The name is only responsible for describing What the thing does, or What value the thing holds.
Let's have a look at some examples I've personally encountered to help clarify this:
const derivatives = [];
Only knowing this name, are you able to tell what kind of data will be held in this array? Clearly it holds something that's copied or adapted from something else...but is that enough information? Try to step back and think about what kinds of questions you'd be asking yourself or others if you came across this in some code you were working on.
function name(user) {
// ...
}
Here we have a function that's doing something related to the name of a user...now, without having to read other code, or ask someone for more context, would you be able to tell what this function does?
When I came across this, I had to look through more code to figure out what it did...before that I was asking "Does this return a name?", "Does this update a name?", or "Does this construct a name from some other data?"
Hopefully you can see the above examples are not good names, and would need to be changed because they don't meet the requirements of this rule. You would have to look at more code or ask someone else to figure out What they do or hold. So what would have been some better names? Obviously there are TONS of different names we could go with, but here are a couple of examples:
const derivativeUsers = [];
With this updated name, we're now able to tell that this array will hold some number of users that are copied or adapted from others. No need to read additional code or ask someone else. Hazzah!
function getFullName(user) {
// ...
}
Here we changed the name of the function to more clearly state What this function does. With this simple update, we now know this function returns the full name of the user passed to it.
So to sum up the first rule, anything you give a name to in your code should clearly describe What that thing does, or What value if holds. This might make your names a little more verbose, but in my personal opinion, being a little more verbose is a worthy cost if it means the code is more readable and maintainable for you and the team.
Rule 2: Code should explain How
While the name of a thing tells What it does, the code inside it should describe How it does it. Now, that might sound a bit obvious, but it brings with it a few things you have to consider.
In order for others to understand How the code does something, it has to be readable and understandable. It serves much less benefit if no one can comprehend the code that does the thing. Part of this comes from the naming of the various pieces that make up the code. But other things that contribute to readable and understandable code are it's simplicity, organization and structure, and formatting and styling, just to name a few.
This is a massive topic, and there are many articles, books, and courses on it, so I won't go into too much detail here. Just know that writing clean code is a very important piece of writing readable and understandable code that will let the rest of the team know How something does what it does.
Another piece of the puzzle is modularity. It's a lot easier to understand how something does what it does if it's small and does just one thing. You've probably heard this concept in some form throughout your career. Maybe you're familiar with the Single Responsibility Principle, which is the "S" in the SOLID principles. If you're not already familiar, I HIGHLY recommend you look into it, because it's an important concept in the world of software development. But back to the point. If a function, class, method, component, or whatever, does more than one thing, the complexity of the code increases drastically, and it becomes much harder to not only identify How it does it, but also maintain it over time.
So, in order for your code to meet the second rule, it must be understandable by you months later, or the rest of the team. They should be able to look at the code of some thing and be able to easily identify How it does what it does. To make this possible, we must write clean, readable, understandable code.
Rule 3: Comments should explain Why
Lastly, when more information is needed, when we need understanding beyond the What and How, we need the Why...and this is where comments come to save the day. When we're writing code, there are times when we need to pass on more information, like Why a decision was made, Why a piece of code was needed, or some additional context that's relevant to it. These are are the kinds of things that should be commented.
Maybe there's some obscure use-case that needs to be considered when editing a particular chunk of code that isn't immediately obvious. This should be commented clearly so when the next developer returns to this piece of code next week, next month, or even next year, they'll take that information into consideration as well and not re-introduce some bug, or break some other piece of functionality.
Perhaps something out of the "normal" had to be done in a particular area of the code because of how some third party dependency works. Rather than expecting the rest of the team to run into the same issue and have to solve it themselves, a comment explaining the situation would save them time later (potentially hours or even days).
Understanding Why something was done the way it was provides tremendous insight, especially when there were multiple paths to choose from, or if there was indirect context that influenced the decision. In my personal opinion, commenting that Why is not just a "nice to have" in your code, it's vital. It's vital for maintainability, for knowledge sharing, and most importantly for setting other members of the team up for success.
Knowing when the Why should be included can be tough sometimes. Most people, myself included, forget that we have knowledge and understanding of things that others don't. We move through our lives assuming or expecting others to either know that stuff, or to easily figure it out...even if it took us months of collecting different pieces of information to gain that knowledge. So when you're writing that next piece of code, really step back and think to yourself, what information are you assuming the next developer will have in order to understand it? Then, write that stuff down in a comment.
Conclusion
Well that's it...3 simple rules for keeping code well documented. So the next time you're in the flow, coding out that next big feature, try to remember...
- Naming should explain What your code does.
- The code itself should be readable and understandable so you and others can easily identify How it's doing what it's doing.
- And use comments to provide all that extra information so everyone knows Why the code was written the way it was.
I hope these 3 rules help you as you move forward in your careers! Until next time, Happy Hacking!
Top comments (22)
Excellent guidelines - clear, easy to remember, and perfectly logical. And let me just say that naming something to indicate what it is or does can be easier said than done. As a beginning coder, I'm often feeling my way through a problem and not quite sure what variables or functions or objects I need. I'm often sharpening my understanding of what different parts will accomplish as I go along. That means I'm often going back and re-naming things to better reflect their purpose. I might tweak a name several times to get it just right. But it's totally worth the effort. I need to be able to understand my own code as I expand on it later! And someday when I'm part of a team, I know these good habits will make me an easier person to work with.
Thanks @montyharper!
First, let me give you a high five ✋ for making an effort to go back and update your code after gaining a better understanding. That's such an essential piece of maintaining code that too often I see getting ignored. Keep that up!
In regard to naming being difficult...when I encounter something that's difficult to name it's usually because I didn't break things out in the best way. In fact, I like to use naming as a personal "flag" to indicate if I'm on the right track or not. If I can't come up with a good name that clearly defines what my code is doing, it's almost always a sign that I need to rethink my approach.
Have you noticed something similar? Or have you experienced something different?
Well, yes... but then I'm at a stage where I'm still mostly coding things that are a bit beyond my current ability, so I'm usually on the wrong track, until I get it right. I will definitely keep what you're saying in mind, though, because it sounds spot-on. I'm also a songwriter, and I've experienced this with song titles; if I'm not sure what to call a song then it probably isn't the title that's the problem. It probably means the song has a weak chorus or an unclear focus, and I need to spend some time re-thinking what the song is really about.
Great comparison! 😄
Great tips. I really enjoyed reading your advice because is practical and I believe they definitely improve code readability. I have a suggestion and a question.
My suggestion is that, because functions are actions, their names should contain a verb as a prefix, example: sumTotal. When their main function is to return something without changing it, the name should start with GET: getName. And when they return a boolean, their name should start with IS: isCold.
My question is: what do you think about using comments to warn colleagues about parts of code that shouldn't be modified? Sometimes is not obvious when certain functions affect other parts of the codebase
Thanks @valeriahhdez 😃
This is a great suggestion! What you're describing is generally how I personally like to handle naming. With that said, the specific patterns used in naming will need to be decided per team based on needs and preferences. It will also depend on the kind of programming being done.
For example, in functional programming, you may want to prefix functions that return a boolean with the name of the subject being tested. So rather than
isEnabled
, if we were testing a feature flag, the function might need to befeatureIsEnabled
. But in Object Oriented Programming, since the method is already on an instance of a class (or the class itself if it's static), the method could beisEnabled
because the subject is clear when calling it (ie.someFeature.isEnabled
).So in general, I agree with your suggestion, but there will always be nuances to look out for.
In regard to your question, I absolutely think comments should be used to warn other developers of things. If there's a known use case that isn't obvious they need to account for, or some solution was tested and it didn't work for whatever reason, things like this should definitely be commented so the same mistakes aren't made in the future.
I would like to call out one thing though...you specifically mention, "parts of code that shouldn't be modified". In general, I wouldn't recommend documenting something as "DO NOT MODIFY" or similar. Instead, I would suggest documenting the things that need to be taken into account if the code IS modified. The reason being is that none of us can predict the future. It's possible there will come a time when that code must be modified (due to a bug, changing requirements, a needed optimization, etc). When that happens, it would be beneficial to have a list of things that could be impacted. I'd be curious to know if you (or others) have different perspectives on the subject though.
I couldn't agree more with this nuanced perspective on my comment. You put it in better words than I could.
This is awesome. A great and balanced mix between "always write comments everywhere" and "no comments required in really clean code". And you explained it in very intuitive way. This should be taught in schools and programming courses.
Wow, thank you @aloisseckar! I'm honored to get such a compliment 😍
Thank you for this guidelines. I found good naming (WHAT) leads to better code (HOW) and I think focus on WHY with the comments is a very good idea because there is no need to redundancy of explain WHAT, if naming is good, or HOW, if code is legible.
I agree with all this. I find comments that just repeat exactly what the code does distract from trying to understand the code
I agree @kehoecj
Very frequently when I see this being done, I notice it stems from 1 of 3 issues:
Obviously there are other reasons, these are just the common one's I see most frequently. But in all these cases, the solution is education. Whether that's teaching an individual or an organization, educating people on what documentation provides benefits is essential.
What's been your experience on the subject? Do you see this happening for other reasons than the ones I mentioned above? How do you address it?
Love this! To boil writing clean code down to these three rules is really practical. In the end what you need when you read code is exactly that: What? How? and Why?.
Taking more time to write descriptive code saves so much time in the future!
😍 I couldn't agree more!
AGREE AGREE AGREE. My code about 5 years ago was SO much messier than it is today.
Also, notice the fact that Google, in their Bard updates, lists “what” and “why” for each update. They know.
Thanks for sharing ! I share your feelings about what is the purpose of a name in source code (telling what it is), and what is making comments useful (explaining why this piece of code exists). Thank you for putting words on these concepts, I'm going to share your article with my dev team.
There is one more point I would like to mention about writing comments, that is also valid for any text you have to write : you have to think about who is going to read your comment. If it's the future you, you'll probably write barely no comment, or specific keywords to remind you why you did it that way. If you are working on closed-source code, with French speaking people only, it's probably better to write comments in French language. If you have many junior devs in your team, you can give some tips to maintain this piece of code or name the design pattern you used.
But most of all, you have to think about what the reader might be looking for. Yes, most of the time it would be a dev tasked to develop a new feature. But at one point someone would have to fix this code : so you may add a link to a relevant test to execute, that would help this future bug hunter to figure out what is going on. If it's an API meant to a specific purpose, like adapting some legacy code, you can warn the user in your comment "if you aim to write a new component from scratch, please prefer this ".
This is a practical example of a link in a javadoc comment (tip :
Ctrl
+Click
with a modern IDE brings you to the referenced method) :You have to think also of the location of your helpful text. For example, some IDE show doctrings as a tooltip when your mouse hovers a class name, that makes your comment visible in every place the class is used. Last but not least : your VCS (git) commit message can be seen as a comment of a change, and imho, it's even more important to write that why for this change.
Thanks again, and happy hacking too !
These are good general guidelines, but I think one other important (sub) category is a why not. Whenever I find myself removing the obvious one line fix (that didn't work) and replacing it with more involved code I track the obvious code in a comment and explain why it did not work. This saves time in the near term (for code reviewers) and long term maintenance, when you or someone else may be tempted to revert to the obvious (wrong) code.
Other things to add are to minimize external references and explaining from the perspective of the current code, not the caller. If you must reference how the code is called it should be done generically ("if a caller needs X, they can do Y" etc). "This fixes issue 12345" is meaningless if the code has outlived the issue db or moved to a different project, and callers can change over time.