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 /* ... */).
[size="5"]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.
[size="3"]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;
// fill in the structure
struct.name = SNAME;
struct.player = P1;
struct.pFlag = NODIE;
FillUp(&struct, 0, INDEX);
// 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);
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.
[size="3"]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()
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
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.
[size="5"]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?":
[bquote]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)[/bquote]
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?"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)[/bquote]
[size="5"]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
// sentence number one. Sentence number two. Sentence number three
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;
// 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;
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);
// 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);
// set x to zero
int x = 0;
// set y to zero
int y = 0;
// set z to zero
int z = 0;
// initialize the counters by setting them to zero
int x = 0;
int y = 0;
int z = 0;
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
}
// 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
}
[size="5"]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-----------------------//
///////////////////////////////////////////////////////////////////////////////////
.... it isn't quite//
.... it isn't //
.... it isn't quite //
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()
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;
// 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;
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.
[size="5"]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.
[size="3"]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//////////////////////////////////////////////////////////////////////////
//-------------------------------------Defines-----------------------------------//
///////////////////////////////////////////////////////////////////////////////////
// Defines //
///////////////////////////////////////////////////////////////////////////////////
[size="3"]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:
//
////////////////////////////
// code and comments here //
////////////////////////////
//
//
//////////
// code //
//////////
//
//
///////////////
// more code //
///////////////
//
[size="3"]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.
[size="3"]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?
[size="5"]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.
[email="drew@gamedev.net"]drew@gamedev.net[/email]
[size="3"]Special Thanks To:
MadKeithV
milo
GameDev.net