Don't Wait to Document - Part 1

Many books laying open
Photo by Tamara Gak / Unsplash

This is a long winded first post that will eventually explain why this blog exists in the first place so.. bear with me. I've broken this post into 2 parts: first some thoughts on comments in code and then on documentation in general.

Documentation in Code

The practice of writing comments in code is preached far and wide. There are many good articles on writing code comments, including Best practices for writing code comments from the Stack Overflow blog (which I highly recommend reading even if you think you are an expert code commenter). That blog post lists 9 rules for comments and I'd like to extend that to an even 10:

Rule 10: Don't wait.

There are a lot of valid reasons to postpone writing comments:

  • The code may not be final yet
  • I'm just adding a little bit to existing code
  • I'm on a deadline and I don't have time
  • I don't want to

My guess is that the people who know they should be documenting their code procrastinate it because code documentation is almost always taught as some form of "write the comments for the next person who has to read this code". That certainly has a lot of value, but I have learned other (maybe more selfish) reasons.

I'm sure by now you're expecting me to say something like "Don't wait to write the documentation later because most of the time you won't actually do it". Again not untrue but what I'm going to convince you of is actually writing some of your documentation before writing any code. Writing the comments before writing any code gives you a structure to fill out. You get a chance to think through your plan. Best of all - your code is already documented! Let's look at some examples:

private int AddTwoNumbers(int a, int b)
{
	return a + b;
}
Short, simple, well named functions don't require documentation

See? I'm not trying to say every line of code needs a comment. Programmers always have more to do than time to do it. So as with most things there is a tradeoff decision to be made and you as the expert get to make it. What about a real problem? Let's look at a common programming test question: implementing Fizz Buzz.

What I used to do is start with a stub of a method:

private IEnumerable<string> GenerateFizzBuzzSequence()
{
	// TODO implement FizzBuzz
}
Fizz Buzz stub

and then look back and forth between my method and the 2nd monitor that has the implementation rules. Now I would do something like this:

private IEnumerable<string> GenerateFizzBuzzSequence()
{
	// Infinitely loop to allow caller to determine how many items to take
    
	// For each number, output:
	// * "Fizz" if divisible by 3
	// * "Buzz" if divisible by 5
	// * "FizzBuzz" if divisble by both 3 and 5
	// * ToString otherwise
}

Now I have a template that needs filled out. I don't need to look at any external references for the implementation, except as needed for syntax or library calls.  My big task is now broken into smaller, more digestible tasks. The second benefit is that some subtle bugs are easier to spot in review by either you after you're done or by a teammate during a code review. Here's an example:

...
// Return 500 result on failure
if (externalResponse.IsSuccess)
{
	return new OkResult();
}
...

There are 2 bugs here according to the comment: the condition isn't negated so this code runs on success instead of failure and it returns an OkResult which web developers would know as a 200 result, not 500. Since those things together make sense as an implementation (as successes usually result in a 200 response) that would lead me to review the surrounding code/comments to determine if the code is wrong or if the comment is wrong. This is the kind of bug that with no comment may just blend in to the rest of the code and not flag any warnings during review. However it can also be way worse! Imagine you dutifully wrote comments after writing all the code but decided to take a coffee break first. You come back to the code and you write a comment for what you see rather than what you intended:

...
// Return 200 result on success
if (externalResponse.IsSuccess)
{
	return new OkResult();
}
...

Now the comment and the code match but this is the wrong code!

Hopefully now you can see the benefits of writing comments before writing code:

  1. It guides breaking down a large task into smaller tasks that are easier to parse
  2. The comments can point to subtle bugs
  3. Code is documented by default (though a pass to review the comments specifically after completing the task is still encouraged)