Clean Code: The Role of Comments
May 24, 2024
I don't like most comments I see in code.
Comments are a code smell and are not needed.
If you need to comment, there is something wrong with your code.
Comments I see daily are either redundant or created due to poor naming and lousy code.
Why am I so against comments? Most comments are there. After all, the code stinks, or they were added as placeholders and never removed.
Have you ever seen a #todo in a multiyear project?
Now, I will tell you to use comments if your code has complex logic or odd business requirements. However, complex logic and business requirements must go through a clean code naming convention before adding a comment.
Clean Naming Convention
For example, you may see something like this:
# Grant access only to users older than 18 due to legal restrictions
if user.age > 18:
grant_access_to_party()
What is the first thing you see here? The comment helps explain the 18, which is the legal restriction to enter the party.
Ok, great comment!
Wait, hold on there. This is a nasty comment.
Why, you may ask? Isn't it funny how we know what every part of the code is doing except what the comment tells us? Can we improve this for readability so the code tells the story instead of the comment?
We can easily change this to:
if user.age > legal_restrictions_age:
grant_access_to_party()
Now we know that the legal_restrictions_age is what we compare to user.age. A comment no longer needs to be here. This is a win-win scenario.
Outdated or Incorrect Information
Incorrect information can confuse even the best programmers.
Imagine you are going through your code, and you stumble onto something like this:
# Check if x is positive
if x < 0:
print("Do something")
else:
print("Do something else")
Notice anything odd with this comment?
The comment says it is checking if x is positive; in reality, it is checking if x is negative.
Even more, this comment is not needed. Any developer can look at this code and understand what is happening. What I would change is the name x and change it to what you are actually looking for.
Perhaps to something a bit cleaner:
if net_worth < 0:
print("You're in debt!")
else:
print("You are not in debt!")
Stating the Obvious or too Much Information
We can sometimes get carried away with comments.
I have been in a coding interview where the individual interviewing started writing comments for every line of code.
I would highly avoid doing this. This did not make their solution any more clear. It made it less clear. Every time they went back to change the code, they redid their comment until they finally had enough and deleted all the comments.
You do not need to write a comment to explain every part of your code:
# Comment is redundant and unnecessary
x = x + 1 # Increment x by 1
Woah, way too many comments above.
Aligned with the same thought process, you do not need to over-explain your function.
I think of this as over-engineering but way worse.
# This function calculates the sum of two numbers, a and b. These # numbers are passed as parameters to the function. The function will. # add these two numbers together and return the result. The result is a # single number that represents # the sum of a and b.
def add(a, b):
return a + b
Ok, bad example, but you get the point.
Bad comments will make your code smell and make it hard to read for your future self and other developers.
However, only some comments are good, and there are great use cases for when to use them properly.
Lets explore.
Highlighting Workarounds and Temporary Solutions
You might have to implement a workaround or a temporary solution due to external constraints. In such cases, comments are crucial to explain the context and the reasoning behind temporary code.
When a piece of code doesn't follow the usual best practices or patterns due to specific constraints or limitations, we need to document the reasoning behind these deviations.
Here is an example of an API limitation to get cache settings:
# Using a hardcoded value due to API limitations.
# TTL for Redis Cache is 30 seconds.
default_timeout_TTL = 30
Warning of Consequences
In some cases, the code might have side effects or specific requirements that are not immediately obvious. A comment can serve as a warning or a cautionary note to other developers.
These comments act as vital signposts for future maintainers or collaborators, highlighting potential pitfalls or important considerations associated with specific code segments.
There are many ORMs that will throw an error if the call does not perfectly match the database.
Here's a deeper look into a 3rd party database dependency that may not have a correct primary key and has to be handled within logic.
# This calls 3rd party database, id is not unique in DB therefore
# to stop error we need to update_many. id is unique though within
# business logic
user = data.update_many({"id": 1, {"is_active": False})
TODO Comments
I am usually against TODOs in comments.
They are code smells that usually do not get deleted.
However, while tracking tasks outside the code is generally better, sometimes a TODO comment is necessary to mark temporary solutions.
# TODO: Replace this workaround with a permanent solution once the API
# is stable.
temporary_solution = fetch_data_with_workaround()
While comments are invaluable for explaining the why behind code, the goal should always be to write clear and understandable code that minimizes the need for extensive commentary.
Comments can significantly contribute to the code's long-term health and sustainability when used correctly.
Good luck on your coding journey friend!
Cheers,
Eric
Subscribe - Grow within your craft with less than 5 minutes a week.
We hate SPAM. We will never sell your information, for any reason.