Our new topic in clean code practices is comments. If you haven’t read it yet, we recommend reading our first practice on naming. Because the two complement each other.

Ideally, well-explained code should not need comments, and this is what we all wish for in our work. However, in practice, this is often not possible. No matter how technically clean the code is, we may need to add comments due to the complexity of the task or algorithm it performs. The person who developed the code might understand it, but our goal is for others to be able to understand and modify the code if necessary. In this sense, comments serve as a means of communication.

So, how do we write clean comments?

1) Comments should explain why the code is written, not what the code does. Suppose we have a list, and we start traversing it from 1, even though, as we know, indices in many languages start at 0:

cpp

// Start traversing from 1.

for (int i = 1; i < parameters.length(); i++) {

// codes

}

 

This comment is meaningless because it merely repeats what the code does. Instead, the reason for starting the index at 1 should be specified. For example, “start traversing from 1 because the first parameter is a system parameter assigned automatically.”

2) Before writing a comment, review the code. If the code can be improved to be more understandable without needing a comment, try that first. Similarly, if you are struggling to write a comment, it may indicate a problem with the code.

3) When you make changes to the code, existing comments may become outdated or redundant. If you don’t address this at the time, it will confuse developers who come after you due to inconsistency. Continuing with the example above; suppose after a refactor, we can now start our loop from the first element:

cpp

// Start traversing from 1 because the first parameter is a system parameter assigned automatically.

for (int i = 0; i < parameters.length(); i++) {

// codes

}

 

In this case, the comment should be removed.

4) Especially in low-level languages like C++, where different DLLs can call each other’s methods, it’s beneficial to specify dependencies at the beginning of a method if changes are made to the method (especially changes to the method name, parameters, or other parts of the signature) or if it’s removed, as the calling DLL can become invalid. Here’s an example:

cpp

//—————————————————————————–

// Name: ConvertByteArraytoString

//

// Description:

// Converts byte array to null-terminated string. The method is used by customermanagement.dll as well. Be careful when you move or remove the method.

//

// Parameters:

// pbValue – [in] byte array value

//

wchar_t* ConvertByteArraytoString(

BYTE *pbValue)

{

// codes

}

 

5) If you copied your code from somewhere or referenced it, adding a link to the comments can be helpful.

Let’s conclude our article with a quote from Jeff Atwood’s Effective Programming: More Than Writing Code: