Clean Code Chapter 4: Comments Are Not a Substitute for Clean Code
My key learnings from Chapter 4 of Clean Code by Robert C. Martin. This chapter changed how I think about comments and taught me why writing self-explanatory code is often better than explaining code with comments.

Clean Code Chapter 4: Comments Are Not a Substitute for Clean Code
When I first started programming, I believed that good developers wrote lots of comments.
Whenever I encountered a piece of code that looked complicated, I would add comments to explain what it was doing. If a method became too large, I would separate sections with comments. I thought comments made code easier to understand.
After reading Chapter 4 of Clean Code by Robert C. Martin, I realized that I had been approaching comments the wrong way.
The biggest lesson from this chapter is:
Comments are not a substitute for clean code.
In many cases, if a comment is needed to explain what the code does, the code itself may not be clear enough.
Why Comments Can Be Dangerous
Comments do not execute.
Code changes.
Comments often don't.
Over time, this creates a situation where the comment no longer matches the implementation.
Consider this example:
// Returns active users
public IEnumerable<User> GetUsers()
{
return _repository.GetAllUsers();
}
A future developer might modify the method to return all users and forget to update the comment.
Now the comment is incorrect.
An inaccurate comment can be more harmful than no comment at all because it misleads future readers.
Good Code Should Explain Itself
Instead of writing comments, we should focus on writing code that communicates intent clearly.
Consider this example:
// Check if user is active
if (user.Status == 1)
{
}
The comment exists because the code is not expressive enough.
A better approach would be:
if (user.IsActive)
{
}
Now the code explains itself.
No comment is required.
This reinforces one of the core ideas of the book:
Use meaningful names and clean structure so readers can understand the code without additional explanations.
Comments Cannot Fix Bad Design
One of the most important lessons from this chapter is that comments should never be used to justify poor design.
For example:
// Validate user,
// save user,
// send email,
// generate report,
// and write logs.
public void ProcessUser()
{
}
This comment describes a method that is doing too many things.
Instead of documenting the problem, we should solve it.
A cleaner design would look like this:
ValidateUser();
SaveUser();
SendWelcomeEmail();
GenerateReport();
LogActivity();
The code now tells the story itself.
No comment required.
When Comments Are Useful
Although the chapter criticizes excessive comments, it does not claim that all comments are bad.
Some comments provide valuable information that cannot easily be expressed in code.
Legal Comments
License and copyright information often belongs in comments.
/*
* Copyright 2026
* Licensed under MIT
*/
Explaining Intent
Sometimes the reason behind a piece of code is not obvious.
// Retry three times because the payment provider
// occasionally experiences temporary network failures.
This comment explains why the code exists.
That information is valuable.
Warning Comments
Certain parts of a system may have important constraints.
// Do not remove.
// Required for backward compatibility.
These comments help future developers avoid mistakes.
TODO Comments
TODO comments can be useful reminders.
// TODO: Move caching implementation to Redis.
However, they should eventually be addressed rather than ignored.
Comments I Should Avoid
After reading this chapter, I realized that many comments I have written in the past add little value.
Redundant Comments
// Increment count
count++;
The code already explains itself.
Noise Comments
// Constructor
public UserService()
{
}
This comment adds no useful information.
Commented-Out Code
// var result = CalculateOldSalary();
Dead code should be deleted.
Version control systems already preserve history.
Journal Comments
// 01-Jan-2026: Added validation
// 10-Feb-2026: Fixed bug
Git already tracks changes.
These comments eventually become clutter.
My Biggest Takeaway
Before reading this chapter, I thought comments improved code quality.
Now I see them differently.
The goal should not be:
Write code and then explain it with comments.
The goal should be:
Write code that explains itself.
Comments should be reserved for situations where code alone cannot communicate important context, intent, or warnings.
As developers, we should first focus on:
- Better naming
- Smaller functions
- Clear structure
- Single responsibility
Only then should we consider adding comments.
Final Thoughts
Chapter 4 completely changed how I think about comments.
I used to see comments as documentation.
Now I see them as a last resort.
If a comment explains what the code is doing, there is a good chance the code can be improved.
If a comment explains why the code exists, it is probably valuable.
Going forward, I will try to write code that communicates intent through its design rather than relying on comments to explain it afterward.
Share this article

Dabananda Mitra
Software Engineer specializing in scalable backend systems and minimal, effective API design.
More Writings
Clean Code Chapter 1: The Lesson That Changed How I Think About Writing Software
After reading Chapter 1 of Clean Code by Robert C. Martin, I realized that writing code isn't just about making it work. It's about making it readable, maintainable, and easy for future developers—including yourself—to understand.
Read Article →BooksClean Code Chapter 2: Why Naming Is One of the Hardest Parts of Programming
My key learnings from Chapter 2 of Clean Code by Robert C. Martin. This chapter taught me that good names can make code self-explanatory, while poor names can make even simple code difficult to understand.
Read Article →BooksClean Code Chapter 3: Functions Should Do One Thing, and Do It Well
My key learnings from Chapter 3 of Clean Code by Robert C. Martin. This chapter taught me that small, focused functions are easier to read, test, maintain, and understand than large functions that try to do everything.
Read Article →