Comments? NO GOD PLS NO! šŸ„“

Felipe Ɓlvarez
Mercadona Tech
Published in
4 min readJul 17, 2024

šŸ‘‹ Hi everyone! Iā€™m Felipe Ɓlvarez, Backend Engineer at Mercadona Tech. Today, I want to talk about one of the basics of Clean Code: donā€™t comment.

This is one of the most common misconceptions in Software Development.

Perhaps you entered here because you use comments every day and think Iā€™m crazy. I canā€™t complain about you because I was in the same situation a few years ago. I used to comment on all my code (or at least the tricky parts) because I wanted everyone to understand it.

And here is the key: what type of code are you writing that needs some explanation with comments? As Robert Martin says in the awesome book ā€œClean Codeā€:

The proper use of comments is to compensate for our failure to express ourself in code

And here is the problem: comments are like documentation: they lie and become outdated as time goes by because you may change the code, but you will probably forget to change the comment.

Also, we spend more time reading code than writing it, and itā€™s more challenging to read complex code with explanations in comments rather than reading simple, clean, and self-explanatory code.

So, what can we do? How about caring about the readability of our code? How about trying to keep our code as clean as possible so it explains itself? šŸŒš

I know that there are many types of comments, and I know that in some really specific situations the use of comments could be justificated (for instance, inside a Jenkins Pipeline or in some config file), but Iā€™m going to talk about what I think are the 2 most used cases of comments during development:

  • The comments for ā€œWHAT?ā€
  • The comments for ā€œWHY?ā€

The comments for WHAT?

Iā€™m sure you have seen a lot of times things like this:

class SomeClass:
def some_method(self, some_object):
...
# If the state of the object is 1, it means that the previous process
# have failed, so we have to modify its values
if some_object.get_state() == 9:
some_object.set_some_value("a_value")
some_object.set_another_value("another_value")
...

Maybe this is not the best example but I think you can get me. If you notice, the comment says that the status of failure is 1, but in the code is 9. What happend here? Maybe some time ago that status was 1, but then it changed, and someone forgot to change the comment as well. What can we do? Remove the comment? Change the comment? Change the code? I think you can understand me.

The best way for getting rid of this type or comments is using methods. Letā€™s see this:

class SomeClass:
def some_method(self, some_object):
...
self._manage_state_after_some_process(some_object)
...

def _manage_state_after_some_process(self, some_object):
if not some_object.has_a_valid_state():
some_object.reset_state()

As you can see, removing the comment has greatly improved our code! Now, we use the rule of ā€œTell, donā€™t ask,ā€ we have better naming, and the comment explanations are now embedded in our code. Itā€™s easy to read and easy to maintain.

The comments for WHY?

The other type of comments usually are for explaining the reasons behind some block of code. Something like this:

class SomeClass:
def some_method(self, some_object):
...
# We need to store all datetimes as UTC in ddbb because blablabla
some_object.convert_some_date_to_UTC()
...

For these cases, the best way to attack them is by creating specific tests for those cases. As I said before, a comment probably gets outdated as time goes by, or someone would remove it.

But if there is a part of your code that needs to be done for whatever reason, the best way to assuring that is simple: having a test for that! A test would not get outdated, and if you or someone else accidentally remove that important part of code, the test will warn you.

Also, you can give the same context with a good naming in the test you gave in the comment. Letā€™s see this:

class SomeClass:
def some_method(self, some_object):
...
some_object.convert_some_date_to_UTC()
...
@pytest.mark.django_db
class TestSomeClass:
def test_some_object_date_is_saved_as_UTC_when_doing_some_use_case(self):
some_object = some_object_builder().build()

SomeClass().some_method(some_object)

assert some_database_object.objects[0].some_date.tzinfo == pytz.utc

As you can see, now we have all the necessary context within the name of the test, and we also have a way to ensure this code never stops doing what it is supposed to be doing šŸ˜‹

Last but not least, I know sometimes we need comments, or at least they are really useful, but I think that having a mindset of ā€œno commentsā€, can be really useful and can help us a lot to improve our codebase, make better decisions and build a much robust, readable and maintainable code.

Thanks for reading; keep it clean šŸ˜‰

--

--