A Comment Is An Invitation For Refactoring

Uncle Bob Martin has a pretty strict view on comments. He goes as far to say:

A comment is an apology for not choosing a more clear name, or a more reasonable set of parameters, or for the failure to use explanatory variables and explanatory functions. Apologies for making the code unmaintainable, apologies for not using well-known algorithms, apologies for writing 'clever' code, apologies for not having a good version control system, apologies for not having finished the job of writing the code, or for leaving vulnerabilities or flaws in the code.

A pretty purist view - but can we really go coding without comments? What about how code should tell you the how and comments should tell you the why?

The more code I read, the more I believe that most inline comments can be eliminated by refactoring the code itself (note the emphasis on most). Whenever you come across a comment in the code, ask yourself: could I refactor the code to remove this comment? The answer will be yes, in many cases.

And this is a great thing. Every comment that becomes part of the code will make refactoring more difficult - because when refactoring, not only the code, but the comment also needs to be changed. And we usually end up forgetting about them. In Clean Code the section on comments says:

The problem with comments is that they have no compile-time check and tend to be forgotten. It’s very easy to change your code but forget about the comments.

Almost all inline comments are ones that could be removed or moved while making the code more readable and easier to refactor. Let's look at 3 examples where comments are an indication that the code could be better organized.

1. Comments Inside (Too) Long Methods

I come across this pattern fairly often, where there are several comments splitting up parts of a long method:

override func viewDidLoad() {  
   super.viewDidLoad()

   // setup the navigation bar
   self.searchBar.searchBarStyle = .Minimal
   self.searchBar.translucent = true
   self.searchBar.placeholder = "Search"

   // setup table view
   self.tableView.delegate = self
   self.tableView.dataSource = self
   self.tableView.estimatedRowHeight = 150.0
}

This is an invitation to again extract the sections the comments refer to. The comments are explaining the "how" in this case, not the "why" - a no-brainer to move the parts into methods of their own:

override func viewDidLoad() {  
   super.viewDidLoad()
   self.setupNavigationBar()
   self.setupTableView()
}

Which version is easier to read? My vote goes for the second one - it's easier to read as the method is now shorter - and easier to refactor, as we no longer have to maintain the comment when changing the code.

2. The Bugfix Comment

Many comments I come across explain how a bug is eliminated by some otherwise hard to understand line(s) of code. Take this example:

func willPresentSearchController(searchController: UISearchController) {  
    // Fixing searchbar disappearing on iOS9 when search controller is active
    if let navigationController = self.navigationController {
        self.storedNavigationBarTranslucency = navigationController.navigationBar.translucent
        self.navigationController?.navigationBar.translucent = true
    }
}

This comment is an invite to extract the bugfix code in its own method:

func willPresentSearchController(searchController: UISearchController) {  
    self.preventSearchBarFromDisappearingWhenSearchControllerIsActive()
}

// Fixing searchbar disappearing on iOS9 when search controller is active    
func preventSearchBarFromDisappearingWhenSearchControllerIsActive() {  
    if let navigationController = self.navigationController {
        self.storedNavigationBarTranslucency = navigationController.navigationBar.translucent
        self.navigationController?.navigationBar.translucent = true
    }
}

The readability of the code is just as good - and the bugfix code is extracted in its own logical item, a method. It's fine to keep the comment in place - but now it's obvious that the bugfix method does one thing, providing the workaround.

3. The Commented Out Code Comment

Every now and then I come across comments addressing commented out code.

// NOTE: temporary removed until the calendar functionality is removed. Re-enable afterwards by uncommenting this line:
//self.setupNativeCalendarAccess()

Another invitation... to delete the whole comment altogether. Commented out code is dead code, and dead code rots your codebase. There should be no reason to keep the code in place - this is exactly what source control is there for - if someone will need the original code, they can find it in the commit logs.

Coding Without Comments?

Comments certainly have their use and place. A use case where they're invaluable are API documentation and explaining things that code just can't convey (or it would be too complex). Here's what Jeff Atwood says about coding without comments:

If your feel your code is too complex to understand without comments, your code is probably just bad. Rewrite it until it doesn't need comments anymore. If, at the end of that effort, you still feel comments are necessary, then by all means, add comments. Carefully.

Apart from documenting your public API, you should treat each comment as an opportunity to refactor your code, to make it even more readable, with or without the comment. Comments have their use and place - make sure its a valid one before using them.

comments powered by Disqus