This post marks the beginning of a series on good programming practices and the concept of "clean code." It focuses on a crucial aspect of our code - comments.
By reading this post, you can assess whether you are adhering to the principles of clean code when it comes to using comments.
You will learn when and why you should avoid using comments, as well as when they are appropriate or even recommended.
It’s commonly said that good code doesn’t need them. Everyone should agree wholeheartedly with this thesis and stick to it. Of course, there are exceptions that I’ll tell you about, but in most cases, comments are bad mainly because the use of them means that we wrote a code that could have been better written. Also, instead of adding a comment that explains the incomprehensibly written code, let’s take better to correct it.
First, let’s start with these. There will be only a few examples because most of them landed below the “Bad comments” headline ???? Despite that, adding a comment is sometimes a must or just a good idea.
They are notes left by the programmer for a particular reason. He writes it when he thinks that something should be added, changed, or deleted and when that couldn’t be done at the time of writing this note. It can be a reminder, a request, or a proposition, e.g. of thinking about a better name for a written method that we don’t quite like. Below is an example of // TODO as a reminder about removing lowerCase()
when EmailNotification
is ready.
public void sendConfirmationEmail(final Confirmation confirmation, final Map<String, Object> additionalFields) {
final EmailNotification emailNotification = new EmailNotification(confirmation.getEmail(),
//TODO remove lowerCase when EmailNotification become case insensitive
confirmation.getLanguage().toLowerCase(), additionalFields);
emailSender.send(emailNotification);
}
Of course, keep in mind that the // TODO comment can never be an excuse for not finishing or writing the code carelessly. You must also keep an eye on them and not forget about their existence.
Sometimes writing a warning is a good idea. If the use of our code in some extraordinary situations will cause e.g. a decrease in performance of the program, it’s worth leaving a line of commentary informing other developers about it. Like here:
// Should not take more than 10000 logs due to performance issue
public File createLogsFile(final String filePath, final int logs) {
final File file = new File(filePath);
return adjustFile(file, FileType.LOGS, logs);
}
You can say that there’s something wrong with this code if there’s such a risk. This is, of course, true, although things happen. In addition, since this code has been created and at the moment there is no possibility of correcting it, this warning can save other programmer’s time and nerves.
Occasionally, excuses can find these comments which indicate the importance of some line of code or the execution of a certain operation occurrence. Of course, you should always justify why what we point at is so important. Let’s look at the example below. It’s written in Java again and it has a comment that explains why remembering to close the sender is critical:
/**
* Closing the emailSender is really important because of the need
* to release resources on destruction of the Singleton
* which this service is
*/
@Override
public void destroy() throws Exception {
emailSender.close();
}
As I said before comments are in general a bad idea and their existence means that our code isn’t good enough. Here are some examples of what you shouldn’t do.
First of all, there are some comments that their usage could be rational, but the way how they’re written is only making the reader more confused. A programmer who has to deal with our code with such a comment has a difficult task. Regardless of whether he only needs to use our method or make a refactor, he won’t start working without understanding our commentary. So if it’s written vaguely, we make it harder for him to work. He must devote his time to understanding. Moreover, what if he misunderstands? This may affect the quality of his code due to misinterpretation. Look at this example of mumbling:
private BigDecimal calculateGrossPrice(final BigDecimal item, final BigDecimal charge) {
try {
return PriceUtils.calculateGrossPrice(item, charge);
} catch (IOException e) {
// Null charge means that price is calculated with default charge
}
}
In the above example, we don’t know what the programmer meant and what reasons he have to put this code in the catch block. If the charge variable is null then the calculateGrossPrice
method will throw an Exception or will it calculate the price using the default charge? If the first one, then when will this price be calculated? Maybe it has already been calculated somewhere before calling this method, or maybe we have to do it ourselves. As you can see, this type of comment can make it difficult so much.
Sometimes I come across some unnecessary comments because they could be replaced by a well-written code without a problem. It gets even worse when such comments are repeated. Below is an example of a domain class, which has well-described fields and so many unnecessary comments that look very similar. They’re explaining what’s already visible thanks to correctly named fields and a context.
public class Offer {
// offer id
private UUID id;
// offer creation timestamp
private Instant creationTimestamp;
// offer expiration timestamp
private Instant expirationTimestamp;
// offer completed timestamp
private Instant completedTimestamp;
// offer price
private BigDecimal price;
// success callback url
private String successCallbackUrl;
// failure callback url
private String failureCallbackUrl;
// notifications url
private String notificationsUrl;
// offer address
private String address;
// offer status
private OfferStatus status;
}
It’s equally common to write bad code in terms of naming variables and methods and rescuing its intelligibility by adding comments. It’s worth spending some time thinking about nomenclature rather than wasting bits on unnecessary comments that obscure the code. In addition, what if the comment is removed by someone, and the name of, e.g. the method, will not be refreshed? Houston we have a problem.
// Method for creating a logs file
public File create(final String filePath, final int logs) {
final File file = new File(filePath);
return adjustFile(file, FileType.LOGS, logs);
}
Take a look at the example above. Almost identical code has already appeared here. The only difference is the name of the method. The name create
forced the developer to write a comment explaining what this method does, although you can deduce from parameters, body, and what it returns. This comment is certainly unnecessary, all you have to do is to name this method e.g. createLogsFile
.
One of the worst things is leaving the commented code. It’s very unprofessional. The author of the commented code knows why he left it, but no other programmer who comes across this code will have the courage to remove it for a simple reason – how should he know for what purpose this code is commented and left alone? Maybe it was left here for a purpose and it’s too important to be removed like this one:
private OfferResultDto enrichOffer(final OfferResultDto dto, final Descripton descripton) {
dto = enrichWithDescription(dto, descripton);
/*dto.setCreationTimestamp = Instant.now();
dto.setNotificationsUrl(this.notificationsUrl);*/
return dto;
}
Remember that comments should be avoided and used only in specific cases like //TODOs, warnings, or strengthening the importance of our block of code. If your code requires frequent comments, it means it could be better written. The software that we make will be much better if we use comments more carefully. By writing “better” I mean that its code will be much more accessible and understandable for us after some time and for other developers. This fact implies that the final quality of the software for the end-user will be much higher because it will be a pleasure for developers to work with a nice code that has as few comments as possible, so they can show off their programming skills rather than spending much time understanding someone’s comments.
That’s all. I have presented examples of both bad and good applications of comments in our code. I was inspired by Robert C. Martin’s Clean Code: A Handbook of Agile Software Craftsmanship. So if you want to read more about the comments and in general about the clean code, I encourage you to buy it.