Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
July 25, 2014
arrowPress Releases
July 25, 2014
PR Newswire
View All





If you enjoy reading this site, you might also want to check out these UBM Tech sites:


Opinion: The elements of comment style
Opinion: The elements of comment style
September 24, 2012 | By Ted Spence

September 24, 2012 | By Ted Spence
Comments
    9 comments
More:



In this reprinted #altdevblogaday opinion piece, EEDAR's chief information officer Ted Spence explains the benefits of thoroughly commenting code, examining different comment types with examples.

Programming comments are a critical and often overlooked part of the development process. Comments may not be exciting enough to have certifications and training classes dedicated to them, but in many ways the difference between a good codebase and an excellent codebase can come down to the quality of the comments.

Comments increase the value of your code. Compared to comments, though, we often spend more time learning methodologies like Scrum and Agile; functional and object-oriented programming; test driven development and refactoring.

Yet comments are critical in ways that methodologies aren't. In the real world, we rarely spend years working on the same project; we often switch from one program to another multiple times in a week!

Each program has its own style, design patterns, and idiosyncracies; comments help us learn them. Each team has its own philosophy, development lifecycle, shared knowledge, and communication style; comments help us make progress even if senior engineers aren't available to explain something.

Comments vary widely. Unless you have interned for me, I'm pretty sure your style of comments doesn't match mine. Better known programmers than myself have written about comments, including perhaps most famously Donald Knuth's Literate Programming, Jef Raskin's description of how to write readable comments, Dennis Ritchie's stories about historical Unix comments of note, Jeff Atwood's fun rant about why comments, and Timothy King's explanation of how good and bad comments affect productivity.

Interestingly enough, the last time AltDev had an article on comments, the author put forth an argument against them. It's always worth reading about what other people think: we become better programmers, whether we use another person's ideas or not, simply by knowing about them and understanding their reasons.

The value of comments

The primary value of comments is their ability to teach us about our codebase. This kind of shared knowledge helps us avoid bugs that previous programmers anticipated. It helps us switch from one program to another rapidly. Really good quality comments can reduce the amount of meetings we have – by helping others get answers directly from reading the software rather than scheduling time on your calendar.

But I find the most incredible feature of comments is this: Writing lots of comments makes me think through my code. I embark on a project with the goal of writing one comment for every three lines of code, a level of detail that most people find silly, but a level that I find helps me better explain my software architecture both to myself and to someone reading through my work.

I often hear the objection, "I can't waste 25 percent of my time writing comments!" Of course, nobody will force you to write a specific number of comments. But in my experience, I spend only a fraction of my "programming" time actually writing statements; I spend more time staring at an algorithm mentally thinking through its consequences, or deciding to refactor.

When I work on code with fewer comments, this "staring" time takes longer. Revisiting an old program with no comments requires me to "re-do" the mental work I did when I looked at it the first time.

That said, let's think about the types of comments we write and how they help us.

Explanatory comments

Explanations are the most commonly used type of comments. An explanatory comment gives us a "reason" or a "justification" for a particular piece of code. If we write some logic that looks non-obvious, or if we're doing something that looks at first glance to be wrong or unnecessary, you should add an explanatory comment citing enough information to prove your logic is correct.

Another way in which an explanatory comment can help is illustrating pre-conditions or consequences for your logic. Imagine you're writing an extremely high performance inner loop function, and you discover that you can save some execution time by assuming a list has already been sorted. Before you make that assumption, write an assertion to verify the sort (put it in a "#ifdef DEBUG"), and write a comment explaining why it helps.

When writing an explanatory comment, you should feel free to write as much text as is required. Sometimes a four or five line comment is necessary to communicate the information to the reader. Don't stress out about rewriting or polishing the comment; focus on communicating everything that needs to be said.

Here's an example of an explanatory comment for a very obvious test – checking if a variable is null. But this comment tells us who should have populated the variable ("loaded in ValidationStep"), which could help us track down problems with the object's configuration. It also says that the variable must be set at this point in the code, and that we can't just throw an exception for a missing parameter.
//loaded in ValidationStep; if null, then we need to create a new one
if (operationContext.Worksheet == null) {

Documentation Comments

These comments are generally designed by your language or development environment. Many code editors will automatically provide popup help to a user when they hover their mouse over a function call or code statement; and this type of documentation can be extremely useful as a development and debugging aid.

In many ways, documentation comments are similar to explanatory comments – except that they often use a slightly more formal writing style. When writing documentation, take the time to polish your text, especially for functions that are called often. Shorter text is often better; but don't eliminate critical information.

This example below is the function header for a CSV output function from my open source CSV library. The text is short and designed to be readable through Visual Studio's context sensitive help; hopefully with enough detail to answer the obvious questions a user might have when calling this function.
/// <summary>
/// Write the data table to a stream in CSV format
/// </summary>
/// <param name="dt">The data table to write</param>
/// <param name="sw">The stream where the CSV text will be written</param>
/// <param name="save_column_names">True if you wish the first line of the
file to have column names</param>
/// <param name="delim">The delimiter (comma, tab, pipe, etc) to separate
fields</param>
/// <param name="qual">The text qualifier (double-quote) that encapsulates
fields that include delimiters</param>
public static void WriteToStream(this DataTable dt, StreamWriter sw, bool
save_column_names, char delim = DEFAULT_DELIMITER, char qual = DEFAULT_QUALIFIER)

Narrative comments

Some comments are there to hand-hold the reader through the program's thought process. Rather than explaining complex logic, the narrative comment ties together lots of simple logic with a story that helps make the code easy to browse. Narrative comments don't have lots of detailed technical explanations, but they can be very helpful when you pick up a program for the first time (or return to it after a long absence).

By writing good narrative comments, you can show visually when a function has grown to need refactoring. If your story grows unreadable, often your logic needs to be rethought and simplified. If you write lots and lots of narrative comments explaining boilerplate work, perhaps that overhead can be moved to a shared class or initialization function.

These story-style comments can be very verbose, but they can also help you work in a manner reminiscent of "test-driven development." Rather than writing your logic first, you can write your comments first – this is why all of my comments come before the code, not the other way around. I write by explaining what I'm going to do, then doing it; and my comments always come with a line before them to make it easy to skim.

For example, here's a series of "narrative" comments I wrote for a data publishing program. I had snippets that already did most of the heavy lifting, and I wanted to refactor it into an automatable program. I started by writing a narrative of how I wanted the program to work; after each of these comments, I left space to fill in with calls to existing snippets of code:
// Did the customer want us to compile the MDB database?
if (BuildMDB) {

// Next generate SQL statements to update the file

// Next execute the SQL strings onto the MDB file
}

// Does the customer want us to deploy the MDB database?

Blame comments

We frequently are forced to write code by circumstances we don't fully understand or business decisions that may seem irrelevant or arbitrary. When we're forced to fix someone else's bad logic, or when we receive a trouble ticket to make a requested change, it is helpful to blame someone. 

Because of this, the difference between a "blame" comment and an "explanatory" comment is that the "blame" comment refers to something outside of the code – maybe a person, a bug number, a business case, or a project design document change.

The blame comment helps a programmer track down an external justification for our logic. If our program does something unexpected or random, and we can't look into the code to see the reason why, we may need to go to an external source, talk to someone, or find a design doc (why haven't you posted your design docs on an internal wiki?).

Blaming is not always a negative – in many ways, they can be virtually indistinguishable from a "credit" comment. I would encourage you to write your "blame" comments in a language-neutral fashion: don't let your anger or frustration seep through, just reference the decision. A future programmer may see your justification and craft a better fix that solves the same problem, or they can go to the right source be able to challenge the decision.

Rich Skorski notes that it's useful to "blame" someone clearly in the comment, and especially to datestamp the comment. When you either blame or credit someone, that enables people reviewing the code to make decisions on the logic or past experience with the author.

In some cases, it can show whether assumptions may have changed since the comment was written, and in other cases, as Bruce Dawson notes, the compiler, language, or toolset may have changed. Labeling the blame allows the reader to determine whether the original assumptions should be revisited.

Some examples of "blame" comments from myself and Bruce Dawson:
DbUtils.CommandTimeOut = 10 * 60; //10 minutes: Ticket #19267:
increase timeout to handle large volumes of data
// Work around bug in VC++ 6.0
#pragma optimize("", off);

Wrong comments

If you write as many comments as I do, you'll often discover that a comment is incorrect. There are a few different kinds of "wrong," though. Some comments are wrong because the logic that they explain is flawed. Sometimes the comment is wrong because the business decision used as the source of the logic has been changed since it was written. Other times, the comment is simply mismatched with the code – it doesn't accurately represent the work the code is doing.

Almost a decade ago, Jeff Atwood wrote a concise article about the problems that lead to comments being wrong or useless – and his guidelines are a good way to learn about how to avoid "wrong" comments.

Still, I find that "wrong" comments can be useful in learning a program. You may want to write a unit test to verify that the code is in fact doing something wrong before you fix it. You can write "blame" comments to attach more detailed justification to the code. Or if the comment writer is simply wrong, you can improve the code's documentation by fixing the comment.

Wrong comments can be teachable moments too. Imagine that you're investigating a "wrong" comment, only to discover that the comment is, in fact, correct! Along the way, of course, you probably developed your understanding of a key business process. In this case, you may want to add to the comment, appending your new knowledge to what was already there.

This example below shows a code fragment doing something questionable. The function itself isn't time sensitive, so there's no reason for a "sleep" statement. But when you read the comment, you realize why there's a sleep statement – and this realization should help us fix the function so that the sleep statement isn't needed!
Thread.Sleep(1001); //because our ack file names are time based,
we have to make sure they are unique (by seconds)

Placeholder comments

Similar to a "wrong comment" is a placeholder comment, designating something not yet known: when you don't yet understand something and want to remind the reader of a potential problem. These questions are particularly useful when you're maintaining an existing program, and you need to start understanding a complex codebase.

When you read through some logic and nearly understand it, it's worth adding a "placeholder" to indicate what knowledge has yet to be demonstrated. If you don't know for sure that a condition will be satisfied, or if you need further research to make sure a specific edge case won't occur, write it in a comment. Some authors find it very useful to label placeholders specifically, with text patterns like "TODO" or "NYI" that one can find easily with a global search.

In this example, the author has decided to expose a member variable, but isn't certain that the solution is ideal:
// Does it make sense to expose the child objects here if the
application needs to retrieve both parent and children?
public IWorksheetBucketCollection Buckets;
However, I often find myself writing a narrative that includes rhetorical questions. In this case, I know what I'm doing, but my narrative comment is in the form of a question. I do this simply because it's a more readable way of understanding what condition an "IF" statement tests:
// Does this location have a tax authority?
if (location.TaxAuthorityId > 0) {

Superfluous comments

Beyond all these other types of comments lie the completely unnecessary. The purest form of unnecessary comments is the archetypal "add one" comment:
// Add one to X
X
= X + 1;
It's very hard to defend this kind of comment, but let's stop for a moment to understand why it's pointless. First, it's documenting a task (addition) that is eminently readable; the comment adds no information beyond what is already in the code. Second, the comment does not increase the value of the narrative documentation in the code, since it adds no narrative to the variable.

If either of those two conditions change, the comment might be valuable. If someone was to obscure the increment operation by wrapping it in a subsidiary class whose method name wasn't obvious, the comment might help you understand the function call without having to step into it.
// This wrapper adds one to X
X = TaskFactory.AdvanceWorkflowStage(X)
In another situation, perhaps the variable "X" is the thing that needs documenting. If we position this line of code in a location where adding one seems out of place or duplicative, we should ensure that our narrative explains why it was needed. For example, consider this hypothetical comment on a loop where we maintain two parallel counters:
// Filter the database records we retrieved; when displaying, X is the actual rowcount
int X = 0;
for (int i = 0; i < a.length; i++) {
if (!ShouldSkipRow(a[i])) {
PrintRow(a[i]);

// add one to the displayed rowcount
X = X + 1;
}
}
But we should all acknowledge that the harm caused by an unnecessary comment is forgettable. If you don't need to read the comment to understand the code, you can happily overlook it. On the other hand, if you get into the habit of imagining that all your code is obvious, you'll stop writing comments and the codebase will become less readable.

Summary

We should all strive to write useful comments in a way that improves our programs. Yet, silly comments exist. They were the topic of an excellent Stack Overflow question which is filled with wonderful and hilarious examples of narrative comments, culminating in this swear-word-filled-gem (not safe for work, in some workplaces): a series of comments so noxious the programmer who wrote it had to issue a full explanation.

How is your code commented?

[This piece was reprinted from #AltDevBlogADay, a shared blog initiative started by @mike_acton devoted to giving game developers of all disciplines a place to motivate each other to write regularly about their personal game development passions.]


Related Jobs

Blizzard Entertainment
Blizzard Entertainment — Irvine, California, United States
[07.25.14]

Test Engineer
Blizzard Entertainment
Blizzard Entertainment — Irvine, California, United States
[07.25.14]

Quality Assurance Analyst
Blizzard Entertainment
Blizzard Entertainment — Irvine, California, United States
[07.25.14]

Test Manager, Quality Assurance
Blizzard Entertainment
Blizzard Entertainment — Irvine, California, United States
[07.25.14]

Software Engineering Manager










Comments


TC Weidner
profile image
umm, where I come from comments are not used or are used in personal and unique ways because of a little thing called job security.

Kelvin Bonilla
profile image
I know exactly what you mean... It sucks for society, but at least in my world, I'd rather fire someone who doesn't comment their code, than to keep him employed for his arcane knowledge.
Of course, that's only my opinion...

I believe any programmer is far from expendable, but I also know that sometimes, programmers are needed to be transfered to other projects or new ones need to move into your project.

Not only does one person teaching 10 other programmers form a bottleneck, but it also poses a danger that the workforce is going to get screwed if/when that person decides to take another job, leave the company, or has some fatal accident.

I believe that lack of comments in code is not only ineffective job security in my book, but also completely inconsiderate to everyone around you.

Chris Lynn
profile image
Great article. I didn't know there was so much material regarding comments floating around, very informative.

I find comments useful for some other reason too, that could be part of the explanatory portion. One is making search-friendly terms for me to look for later, which is specially helpful when I look at my older games bloated with code and I just want to take a small piece out (function and variable names usually are not search-friendly in my case). The other way to use comments is in a sort of "future ideas" way. I can write in the comment different ways I could use it in future projects, writing down ideas that come to mind during the coding process that I might forget about later on. This helps out in the creative process of coding, that, as the article stated, is one of the more time consuming tasks of the job (but also the fun one, in my oppinion).

Jonathan Jennings
profile image
i am notorious for forgetting to remove my placeholder comments. I am definitely going to have to do more double-takes in terms of making i remove those unnecessary comments after i have finished a script or class

k s
profile image
We all know good commenting is a really good idea but it's easy to forget to add them without a strongly enforced coding standard.

Ted Spence
profile image
Agreed. I like pair-programming style code reviews, where two programmers sit in front of the same monitor and review the code together. The one who wrote the code must explain the logic to the other: and I find that a person who didn't write good comments gets embarrassed often by realizing how hard they have to work to understand their own logic. So that was one way we helped to enforce comment authoring.

Kyle Jansen
profile image
Another type of comment I find useful are "signpost " comments. This is best explained by example:

if (mode == MULTITHREAD_RENDERING){

[snip 30 lines of code]

} else { // mode != MULTITHREAD_RENDERING

[snip another 20 lines of code]

} // endif mode == MULTITHREAD_RENDERING



The signpost comments are there to basically remind you where you are. I tend to use them whenever a block of code is too long to view on one screen, or if there's a lot of nesting (eg. // end inner for loop, // end outer for loop). There's obviously no need to do that for two-line conditionals, but it's helpful when code gets longer.

You should arguably break up blocks of code into multiple functions, but I find that often just makes things more confusing, as you have to track the logic through multiple function calls. So sometimes the signposts come in handy.


I've also found a convention that's useful: using some fixed string to denote things that should be changed before release. At work (non-gaming, unfortunately) we mark it with five at-signs, eg. "// @@@@@ This should check whether the input is in bounds". In my personal projects, I use more complex // TODO:, // BUG:, and so on. Either way, it's easy to search through the entire project to find them. It's not quite as good as a proper tracking system, but it's good for programmers to leave little notes in. It's especially good to put next to quick, dirty debug code, eg. (in PHP) "var_dump($foo); // @@@@@". That way we remember to take it out eventually. I think of those in particular like the little orange tags used in military aircraft - remove before use.

Ted Spence
profile image
That's a good point. I definitely overlooked these kinds of comments, probably because I don't write many of them myself. I will have to add more information about these types of comments in the future. I'm quite on board with the idea of using "tags" in your comments to make searching easier.

Thinking about long "if" statements, I notice that I tend to address the issue with a "narrative" more than a signpost. I believe that's because the narrative is less likely to change than the particulars of an "IF" statement. Let's say, hypothetically, in your example I make a change in the future by making the renderer polymorphic. In that case, an "if statement signpost" would have to be updated, but a narrative might still be correct.

For example, maybe a narrative would explain my reasons why a multithreaded environment requires that this particular bit of code be different than if it was run in a non-multithreaded environment:

// If we're rendering multithreaded, let's set up thread local storage for each one
if (renderer.IsMultithreaded()) {

[snip 30 lines of code]

// We're not multithreaded, so let's store all the texture data in the GPU
} else {

[snip another 20 lines of code]

}

I do agree that signposts are a perfectly valid way of overcoming terse compiler and language syntax. Many of our modern languages were designed for situations where verbose language constructs were counterproductive, and many compilers are very forgiving of awkward and inconsistent indentation and code formatting, so such comments are very useful in some cases.

Do you think "forced reformatting" helps? I have experienced some compilers and editors that will automatically reformat code to make this kind of relationship visible. I know it doesn't solve everything though.

Thanks for sharing!

Titi Naburu
profile image
Thanks for writing this list. I write comments every few lines, but they are usually descriptions. So it's cool to find other uses.


none
 
Comment: