Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Like
0Likes
Dislike

The Art of Code Documentation

By Drew Sikora | Published Oct 18 2000 01:15 PM in General Programming

code function comments program comment person commenting game name
If you find this article contains errors or problems rendering it unreadable (missing images or files, mangled code, improper text formatting, etc) please contact the editor so corrections can be made. Thank you for helping us improve this resource

Introduction

You know, one day at work I was handed a program by my boss. He said, "Drew, see if you and Mike can figure out what this does and if it will be of any use to us." I said "Okay" and took it. The program was from two other employees in the small start-up company I work for who had quit a day or two ago. My boss had asked for what they had accomplished so far and the small stack of papers on my desk was the result. I took the main program file printout and started to look through it. After the first page, my heart rate began to quicken. A few more pages and I began to simmer. When I finally reached the last of the 15 pages I wanted to scream.

I walked into my boss’s office and asked if the two guys were gone for good. He nodded an affirmative. I showed him the paper and explained to him that this job could take a few weeks of work. He looked at me, puzzled. He hadn’t noticed. I handed him the paper and let him look through it. Nothing wrong, he said. I finally pointed it out myself:

"There aren’t any comments, Chief."

This is a good example of what happens to team players when the other team members don’t do their job correctly. In essence, I was handed a program filled with lines of code that had absolutely no meaning to me at all. This scenario only happened a week ago, but I’m still busy at my desk tracing routines, finding functions, tracking variables – and adding in my own comments. Luckily for me, my boss had been a programmer of old and lessened our other task loads so we could better focus on our current project. Can we do this? Yes. It will just take a lot more time than if the code were properly documented.

The purpose of this article is to show programmers, experienced and inexperienced alike, how code should be documented. It’s not just about you; it’s about the other members of your team. It’s about being nice to them and letting them be able to understand your code. It’s about keeping them from having to hunt you down so they can kidnap you, strap you to a chair, and have you divulge the secrets to your program. You wouldn’t want that, right? Didn’t think so.

NOTE: All commenting in this article is done using only C++-style comments (i.e. // and not /* ... */).


Documentation??

Wait a minute, wait a minute – what in the world is this documentation stuff? We don’t document, we comment. What is this? To me, commenting and documenting are two different things, so allow me to explain.

Commentation

Commenting code is the simple part. A comment resides near the line of code that you wish to explain. For example:

// Increment x to a value of 10
x += 10;

Of course, the previous code would assume x had a value of zero, but that’s irrelevant for this example. Simply put, you comment to explain a line or two of code, nothing more. Something like this does not help at all:

// fill in the structure
struct.name  = SNAME;
struct.player  = P1;
struct.pFlag  = NODIE;
FillUp(&struct, 0, INDEX);

Whoa. While the first three lines do not need any extra comments thanks to descriptive variable names (covered later), what’s that last line do? Obviously, thanks to the comment, it has to do with filling the structure. But fill it with what? That line, although related to the last comment, still deserves a comment of its own:

// fill in the structure
struct.name	= SNAME;
struct.player  = P1;
struct.pFlag   = NODIE;

// the other fields are not needed, so fill them with zeros for now
FillUp(&struct, 0, INDEX);

That’s much better! Could we have guessed that? Probably. But why bother take the time to guess when you can be told outright what it does?

Commenting, as shown above, is a term best used when describing single or multiple lines of related code. Again, not too many lines of code should be described by one single comment.

Documentation

When you document code, you take on a wider view. I refer mainly to documenting in this article because it is a term that assimilates commenting into it. A commentation can be referred to as a documentation, but not vice-versa. Why? Because while the scope of a comment is only a few lines, documentation encompasses a whole function, or list of functions, or list of variables, or even a whole program. Here is an example of documentation and commenting put together:

///////////////////////////////////////////////////////////////////////////////////
//---------------------------------ChangeState()---------------------------------//
//                                                                           	//
// this function will change the current state of the game. The current state	//
// defines whether or not the game still runs or if the game has ended. We use a //
// variable along with two #define values to determine the game state.       	//
//                                                                           	//
//-----------------------------------Variables-----------------------------------//
//                                                                           	//
// current_state	- the current state of the game, on or off               	//
// change_state 	- decides whether or not we have to end or continue the game //
//                                                                           	//
STATE ChangeState(int current_state, int change_state)/////////////////////////////
{
  // use a switch statement to decide whether or not to end the game
  switch(change_state)
  {
  case DEAD:
	{
  	// change the current state so that the game is over
  	current_state = GAME_END;
	} break;
  case ALIVE:
	{
  	// change the current state so that the game goes on
  	current_state = GAME_CONT;
	} break;
  }

  // return the new game state
  return(current_state);

} // end ChangeState()

This is what a documented function should look like. It has a header explaining the purpose of the function as well as what each variable is used for. Inside the function body there are comments telling you what everything does.

Now, look at the function and pick from below what statements describe it correctly:
  • The function is documented
  • The function is commented
  • The function is documented and commented
First, scroll up and reread the definition I gave you on documentation. Then decide. If you chose A and C, then you’re correct. Give yourself a pat on the back. Could you get away with B? Maybe, but then you get the picture of a few measly lines of comments, not a whole header. Throughout the article I’ll change between commenting and documenting. Just remember that anything I say about commenting can be applied to documenting, but don’t try to switch that around. Things could get ugly.

Now that we cleared that up, let’s move on so I can start to show you how to comment and then expand upon that and document.


Why Comment?

Before we really begin, I’d like to take a moment and tell you why you should comment. As I have seen it, most people think commenting is a waste of time and resources. I’ve heard things like "you should be able to read code like English" or, "I don’t want people to know how my program works". Yeah – industrial spies are in your high school computer science class. Other people don’t even have reasons; they’re just too lazy to do it in the first place.

Commenting has many pluses. Not only does it let you track your work over a period of months and let you come back and remember what a certain function does; it can help you point out mistakes. For example, here’s a post off of GameDev.net message boards in the thread I started "Do You Comment?":

What’s wrong with the following pieces of code?

1) widgetCnt = widgetCnt + 1;

2) for (widgetCnt = 0; widgetCnt < NUMBER_OF_WIDGETS; ++widgetCnt)

3) if (widgetCnt < NUMBER_OF_WIDGETS)

Now here they are commented:

1) a typo

// create 100 more widgets

widgetCnt = widgetCnt + 1;

2) a cut and paste error

// loop through the widgets in reverse order

for (widgetCnt = 0; widgetCnt < NUMBER_OF_WIDGETS; ++widgetCnt)

3) used < when meant >=

// have we exceeded the maximum number of widgets yet?

if (widgetCnt < NUMBER_OF_WIDGETS)

If that example doesn’t give you enough reason to start commenting, then just don’t waste your time reading the rest of this article. If you don’t want to comment, that’s fine with me. Just don’t complain when you have your co-worker knocking on your door every five seconds to ask you yet another question: "What is this supposed to do?"


Commenting Code

The basic idea of commenting is to explain little snippets of code. To start, I’m sure you all know how to write a comment:

// this is a comment

Things to notice are a space after the two slashes "//" which start a comment, no capitalization is needed and no punctuation is needed. Now, if you had more than one sentence:

// sentence number one. Sentence number two. Sentence number three

It’s generally a good idea to follow normal punctuation up to the end. This is simply for clarity, as it makes it easier to read and understand if you can tell where a sentence stops and another begins. Notice I didn’t bother including a period at the end, since you really don’t need it.

The next important thing is a little gem known as white space. Because all spaces and comments are wiped out for compilation of the actual executable, white space is an extremely simple way to make your commented code easier to read. Here is a piece of code lacking white space:

// initialize the variable so it’s not full of garbage
int var1 = 0;
// set it to 10 for starters
var1 = 10;
// now add on an additional five so we can begins a loop
var1 += 5;

Very bundled up, and during late night coding sessions, I can guarantee you the comments and the code will blur together into an unreadable mess J. But add in the magical white space and:

// initialize the variable so it’s not full of garbage
int var1 = 0;

// set it to 10 for starters
var1 = 10;

// now add on an additional five so we can begin a loop
var1 += 5;

Viola! So much easier on the eyes as well as making individual statements easier to pick out, which is good.

I also like to tell people not to explain more than two unrelated lines of code with one comment. This is a good example.

// here we are going to call the first function, GetName() to get the name of the currently
// selected person, as defined by the variable name. Then we will call SetAge() in order
// give that person an age chosen by the user. Next comes SetGender, which also takes
// user input and sets the gender of the person. Finally we create the person with
// CreatePerson() and assign it to an instance of type PERSON
GetName(name);
SetAge(age);
SetGender(gender);
npc1 = CreatePerson(person.name, person.age, person.gender);

The problem with this is that by the time you’re done reading the comments, you get hit with the code all at once and say, "Wait – what was this for again?" And then you have to look back up and search the comments for the description you want. Yuck. But by commenting each function and throwing in some good ‘ol white space:

// get the name of the person we are using
GetName(name);

// set the age with a user selected age
SetAge(age);

// Set the gender with a user selected gender
SetGender(gender);

// create the person and assign it to the slot npc1, an instance of struct PERSON
npc1 = CreatePerson(person.name, person.age, person.gender);

Now that’s a smooth read. As soon as you finish the comment, you can check out the code, and then move on to the next line. If you ever have a question about the code, the comment is right there. Of course, the opposite would be a few related lines of code. It would be really stupid to do this:

// set x to zero
int x = 0;

// set y to zero
int y = 0;

// set z to zero
int z = 0;

Not only is it a huge waste of time, it’s repetitive! Repetitive comments are the worst things you could possibly do. If you find yourself repeating… yourself (errr….) then it’s best to just group the lines of code under one general comment like this:

// initialize the counters by setting them to zero
int x = 0;
int y = 0;
int z = 0;

This is allowable because all three variables are counters, and they’re all doing the same thing, so you only need to say it once.

The last little trick I like to use is the Tab key. It’s great for ordering your code and comments in a legible way. Take, for example, this section of code:

// define the states
#define GAME_END 1 // game is over
#define GAME_CONT 2 // person is still alive
#define GAME_PAUSE 3 // game is paused

// define the structure
typedef struct PERSON
{
  char name[50]; // the name of the person
  char gender; // male or female?
  int age; // how old they are
}

Aw man – my fingers were itching to press that Tab key while writing that. What a mess. The declarations flow right into the variables, which flow right into the values, which flow right into the comments. Wonderful if you want to read the code like a book instead of line by line but who has reason to do that? With the Tab key, referencing becomes much easier:

// define the states
#define GAME_END	1   // game is over
#define GAME_CONT   2   // person is still alive
#define GAME_PAUSE  3   // game is paused

// define the structure
typedef struct PERSON
{
  char  name[50];   // the name of the person
  char  gender; 	// male or female?
  int   age;    	// how old they are
}

Ta da! Now we can fully distinguish between the definitions, the variables, the values and the comments. Sure, color coding helps but if you ever get blurry vision (late night or anything else) the un-tabbed code will be a pain to read.


Documenting Code

When you document code, you take what you know of commenting and apply it on a broader scale. A simple, commented program will have a comment for every other line of code that needs explaining. That’s good for the developers – it doesn’t clutter it up and it takes less time to scroll through it and change things. But once you complete a project and go to store it away, rudimentary comments aren’t going to cut it. When you document, you explain things in greater detail so that anyone who comes to continue your work in some fashion months or years later can understand what you did.

We’ll start off with program headers. In the program header the person reading the file gets a quick overview on what they program is supposed to do. It is important to get the person in the right mindset so he or she can understand why you coded the way you did. The description should be short, yet detailed. After the description comes the name of the creator and then the date. After that you can add a little section for notes – any oddities you may have thrown in at the last minute or any incomplete areas of the program. Here’s an example of a program header I use:

///////////////////////////////////////////////////////////////////////////////////
//-----------------------------------WinSock.cpp---------------------------------//
//                                  	v 1.2                                	//
//                                                                           	//
// This program will initialize WinSock and then attempt to open a socket and	//
// send info  to the other computer. This is the client portion of the client-   //
// server model. After the data has been sent, the program will close the socket //
// and save the data to a file                                               	//
//                                                                           	//
// Created by: Drew Sikora                                                   	//
// Created on: 9.24.00                                                       	//
//                                                                           	//
//--------------------------------------Notes------------------------------------//
//                                                                           	//
// The file save feature has not yet been implemented in this version. Also, we  //
// are trying to trace a bug in the send/receive section. Sometimes the packets  //
// are dropped for no apparent reason (not net congestion). Just re-run the  	//
// program.                                                                  	//
//                                                                           	//
///////////////////////////////////////////////////////////////////////////////////

//////////////////////
// the program code //
//////////////////////

///////////////////////////////////////////////////////////////////////////////////
//------------------------------------WinSock.cpp--------------------------------//
//-----------------------------Copyright Drew Sikora, 2000-----------------------//
///////////////////////////////////////////////////////////////////////////////////

With the header (and the footer), we can just read the description and know what the program will do, from start to finish. Again, it’s not long, but it manages to tell you everything the program does. A little habit of mine is to keep the sentences from running against the slash marks like this:

…. it isn’t quite//

Instead, I like to leave a space, even if it means taking out the whole word:

…. it isn’t  	//

Of course, this is the best-case scenario:

…. it isn’t quite //

But that doesn’t always happen. Anyway, that’s just me, you may not care. Also notice the header is completely boxed in, to separate it from the rest of the comments in the actual program. This is a good way to document. Another separator I use is the dash (-). They do a good job of breaking up comment groups inside the closed boxes. Finally, look at the footer, which marks the end of the program file.

Another use for a header is at the top of a function. This time, there is a function description, and a variable list. A notes section, as before, is optional depending on whether or not the function has any extreme qualities you can’t fully describe through your comments. Here’s an example of a function header.

///////////////////////////////////////////////////////////////////////////////////
//----------------------------------MakeWindow()---------------------------------//
//                                                                           	//
// This function will take in parameters usually sent to a CreateWindow()    	//
// function and use them to make the call to CreateWindow(). This is so the user //
// can make many windows without having to type out a new CreateWindow()     	//
// function call with most of the same parameters                            	//
//                                                                           	//
//------------------------------------Variables----------------------------------//
//                                                                           	//
// hwnd   	- the window handle                                            	//
// lpTitle	- the string to appear in the title bar                        	//
// style  	- window style flags                                           	//
//                                                                           	//
HWND MakeWindow(HWND hwnd, LPCTSTR lpTitle, DWORD style)///////////////////////////
{

  ///////////////////
  // function code //
  ///////////////////

} // end MakeWindow()

The function header serves mainly the same purpose as the program header, to let the reader know exactly what the function does, and why it does it. A CreateWindow() function has a lot of parameters that don’t change from window to window, so why retype them all? This function will do it for you. The description tells you this. Then you get the variables section so you know what each variable is supposed to do or represent. Notice I make the function declaration a part of the header-bounding box. This makes a nice transition from header to function, making the header seem more a part of the function itself. And then the function is ended with a comment to denote the close bracket. This is especially helpful so you don’t need to look back up at the end to see what function it is.

Of course, documenting doesn’t end here. The next step is to go back through the code and add in additional comments to explain certain areas in more detail. For example, a few months down the road, this may not cut it:

// define the structure to hold our packet info
typedef struct IP_HEADER
{
  char     	packinfo[80];
  GAME_STATS   gamedata;
  WCHAR    	packname;
  int      	packsize;
  ADDR_HEADER  packaddr;
  UINT     	packstyle;
} IP_HEADER;

That might be fine during development, but these things tend to fade from memory in light of other projects. Therefore, when you decide to look it over again, seeing this might be more beneficial:

// define the structure to hold our packet header, which is sent to the client and then sent
// to the other players, and contains game information (user pos, weapon, etc)
typedef struct IP_HEADER
{
  char     	packinfo[80];  // any text message sent
  GAME_STATS   gamedata;  // structure to hold player info
  WCHAR    	packname;  // used for client ID on the server
  int      	packsize;  // in bytes
  ADDR_HEADER  packaddr;  // structure for packet addr, to and from
  UINT     	packstyle;  // any flags – see PacketS.h
} IP_HEADER;

As you can see, not all the various fields worked as named. The field packinfo could have been named msginfo, but then you could figure it was some message setting. And you could have thought packname was used to ID the packet in the program, not on the server.

Well, this just about wraps up documentation, as well as the article. But I have one more section for you filled with odds and ends I couldn’t find a place for.


Odds ‘n Ends

In this section I’ll just mention a few things off the top of my head that really didn’t fit in with my other section topics.

Separators

There will be times when you’ll want to completely separate some sections of code from one another. I touched on this with the bounding box of slashes (/) but not in the actual program. Here are a few ideas:

//DEFINES//////////////////////////////////////////////////////////////////////////

or

//-------------------------------------Defines-----------------------------------//

or

///////////////////////////////////////////////////////////////////////////////////
//                                 	Defines                               	//
///////////////////////////////////////////////////////////////////////////////////

Personally, I prefer the middle option. It looks the nicest. Of course, there are many more ways to do this.

Programmer Tags

Here’s another idea I got from my thread on GameDev. In a team effort where you have many people operating on the same source code, passing it around, changing it, etc. in the comments add a short tag identifying the programmer. For example:

// <DS>

////////////////////////////
// code and comments here //
////////////////////////////

// </DS>

Yes, it looks like HTML tags, but what’s wrong with that? Now everyone knows who edited which part of the program. I’ve never used this system myself, so I can’t recommend it. My only concern is things starting to get mixed up when another programmer modifies the code set in place by the former programmer and you end up with stuff like this:

// <DS, MM>

//////////
// code //
//////////

// </MM>
// <AO>

///////////////
// more code //
///////////////

// </DS, /AO>

I make the first iteration, then MM comes along and changes half of it, and then AO changes the second half. If you try this, make sure the system you develop takes into account things getting mixed up.

Self-Control (over commenting)

Yes, in this case, there can be too much of a good thing. I know this won’t be that much of a problem for most of you, since before reading this article you probably never commented at all that much anyway, but I feel impelled to dispense with a warning: Too many comments is bad. Well, maybe.

It ultimately boils down to your commenting style. If you have a clean style, then you can probably comment every single line and it would still look good. But if you get sloppy, too many comments will start to get in the way of the actual code. The purpose of comments is to make code easier to read, but if you use too many comments and don’t place them correctly, you’ll undermine your efforts by making the code harder to read because you can’t tell the difference between the code and the comments. And believe me, color coding will not make a difference.

Descriptive Variable Names

For all the lazy programmers out there (including me), here’s a way to decrease your commenting workload – using descriptive variable names. What a concept. For example, instead of using the variable z to hold a number that represents the current amount of money, why not try current_amt, or currentMoney?

The same rule applies to any type of name – function, structure, instance, etc. As long as the variable name can describe what it’s supposed to do, you don’t have to describe it yourself. Ain’t life grand?


Conclusion

I hope that this article has helped you decide on how to best comment your code to make other people’s lives easier. For all those reading this that have never commented before, I hope that you take to heart most (if not all) of what I said in here and get into the habit of commenting (it’ll impress the Boss, believe me).

The greatest challenge of writing this article was trying to tailor it to meet the individual needs of everyone who would be reading this article. Unfortunately, there is no sort of generic commenting style I could utilize for my examples, so I simply used my own. Whether or not you like my style is irrelevant – there are many other ways to get it done just as nicely. But I hope you at least consider some of what I did with the comments and apply it to your programs; I can guarantee a better look and feel. As a last note, I know some of what I said cannot be applied to everyday problems – there may be a time where one line of code does require a few lines of comments. All my "rules" were stated with a "simple case" scenario in mind.

So, if you have any questions or comments, please post them to this thread. Happy commenting.

drew@gamedev.net

Special Thanks To:

MadKeithV
milo
GameDev.net





Comments

Note: Please offer only positive, constructive comments - we are looking to promote a positive atmosphere where collaboration is valued above all else.




PARTNERS