How to Write Effective Comments

julo
The Startup
Published in
4 min readSep 19, 2020

One question has come up several times in my career as a software developer:

How do you decide when to write a comment? How often should I write comments?

It’s a tricky thing to get right. I’ve got some thoughts to share on the matter that I think will help y’all out!

Well-named entities eliminate the need for comments

Let’s start with the basics — and a super trivial example at that :). Let’s take a look at a theoretical snippet of production code:

// Set the title text
titleTextView.text = "Toronto Raptors vs Boston Celtics"
// Set the description text
descriptionTextView.text = "Final Score: TOR 104, BOS 100"
// Set the background color to grey
containerView.background = COLOR_GREY

Here, because the lines of code are self explanatory, the comments aren’t adding any value. They have simply tripled the number of lines of code without any real benefit. (This would also set an inefficient precedent that other developers might see and follow: typing out tons of unnecessary comments! How much dev time would get wasted by others in this codebase if they followed this example?)

A key question to ask, though, is: why are the comments unnecessary here? They are unnecessary because the names of the views are self-explanatory.

  • titleTextView is clearly the text view that the title should go into.
  • descriptionTextView is clearly the text view that the description should go into.

So, this is a simple example of the power of good naming: well-named entities eliminate the need for comments.

Establish strong patterns throughout the codebase so you don’t have to comment most of it

I’m currently working on the Android version of Nike’s Athlete Studio app. My team is all onboard with following Google’s MVVM guidance: utilizing view models, repositories, LiveData, view binding, and all of that jazz.

This has resulted in most of our code following a small set of effective patterns. Take, for instance, our Activities. They all follow the same following pattern:

class FooActivity : AppCompatActivity() {
private lateinit var binding: ActivityFooBinding
private val fooViewModel: FooViewModel by viewModels {
FooVMFactory
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityFooBinding.inflate(layoutInflater)
initializeSecondThingView() observeFirstThing()
observeSecondThing()
...
}
private fun observeFirstThing() {
fooViewModel.firstThing.observe(this) { firstThing ->
// do whatever it takes to show firstThing in the view
}
}
...
}

The commonality we have across all of our activities includes:

  • All of them use layout files and their auto-generatedViewBinding instances
  • All of them use view models that take care of the heavy-lifting of implementing business logic and exposing LiveData objects that the activity needs to trivially connect to the view. (In a lot of cases, we don’t even need to involve the activity to connect the data to the view; we can use data binding to get the layout file to read from the view model directly!)
  • All of them follow the same pattern in onCreate of first initializing any view that needs to be initialized (for example, a recycler view would need to have its layout manager set), then observing on view model LiveData objects.

Because all activities follow this same pattern, there is no need to add comments on these lines of code. Instead, all developers on the project should study and understand the pattern being used, and then utilize it ad infinitum.

(Note that this is predicated on having patterns that truly work in solving the problems that need to be solved for the project. The architecture of your project needs to chosen appropriately for this to work.)

It is important for all devs on a project to share the same coding style and naming conventions. If everyone is doing things the same way, there is no opportunity for confusion in the implementation of solutions to commonly encountered problems. (That was a mouthful, I realize!) “Oh, she is just loading up an activity and wiring it up to the view model. Cool, nothing to see here, let’s move on.” This frees time up to be spent on the harder problems in your application.

This also makes code reviews so, so much easier. Your senior developers will thank you.

Be vigilant about commenting code that breaks or avoids the established patterns

With the simple stuff handled, it is important that the harder/weirder stuff always contains comments.

  • If you need to break a pattern that is used, it is on you to explain yourself to the devs of the future* why you didn’t do things in the normal way. Were you being a jerk and doing things your own way for the hell of it? Or did you have a good, really hard to see reason to do things differently?
  • If a particular scenario needs to do something very complex and/or unique and/or subtle, comments are going to be helpful to explain what is happening.

Ultimately, the goal should be to make sure devs have faith in the quality and honesty of the code. Comments can acknowledge that certain lines of code are weird/not ideal/gross, and that acknowledgement is a very reassuring thing.

Note: The “dev of the future”, who is looking for an explanation on why the f*** something was implemented in some bizarre way, is usually yourself 1+ months after you originally wrote the code.

Conclusion

I hope this gave some insight/perspective on how to write better comments. Feel free to leave any comments on your experiences with.. well, comments. Ciao!

--

--