Programming for Clarity and Reuse

Last update 12 Aug 1997

Here are a few notes on how to write code so others here at Activision can use it easily.

Basics

Everyone who's going to be sharing code should agree on a few basic things, like tabstops and indenting. (I think most people at Activision use tabstops=4, and indent each new level of code by one more tab. If you like something else, give me a yell, let's come to a consensus.)

Things to watch out for

Good things

Questions

Doesn't it waste time to design and document the interfaces before writing the code?

Not really - I find that writing and documenting the .h file clarifies my thinking so much that the .c file is a lot easier to write. In fact, if you can't write and document the .h file, you probably don't understand the module you're about to write well enough!

Isn't it a waste of time to write a unit test? Can't I test it by using it in an application I'm writing?

You could, but then you'd be debugging two things at once - the new module, and the application. Plus, if you ever make changes to your module, it's really nice to have that unit test around to verify you didn't screw it up.

If you're writing object-oriented code, why don't you just use C++?

Because my code gets used in a lot of environments where C++ isn't convenient (e.g. device drivers, InstallShield, DLL's), and I don't expect people to need to subclass most of my objects. I would love to use C++ for this stuff, and will probably switch to C++ sometime.

What is that _t on the end of type names for?

It's just a convention to show that it's a type name rather than a variable name.

Examples

How to protect your .h file from how it will be included

Design Comments

A design comment is a paragraph of text above a function which describes how it behaves in just the right amount of detail for somebody to use it correctly. It does not go into too much detail about how the function works internally. Here's an example:
/*--------------------------------------------------------------------
 Open a shrouded file for reading or writing.  Just like fopen().
 Returns NULL on error.
--------------------------------------------------------------------*/
shroud_t *shroud_open(char *fname, char *mode);

Data file shrouder

A data file shrouder might have a .h file that has functions something like this:
/*--------------------------------------------------------------------
 Open a shrouded file for reading or writing.  Just like fopen().
 Returns NULL on error.
--------------------------------------------------------------------*/
shroud_t *shroud_open(char *fname, char *mode);

/*--------------------------------------------------------------------
 Read len bytes from a shrouded file into buf, very much like fread().
--------------------------------------------------------------------*/
size_t shroud_read(shroud_t *sfile, char *buf, size_t len);

/*--------------------------------------------------------------------
 Close a shrouded file.
 Returns 0 on success, nonzero on error (e.g. disk full).
--------------------------------------------------------------------*/
int shroud_close(shroud_t *sfile);
etc. You can cheat and read the whole file in at shroud_open time if you like - no rule against that! The idea is to make the interface clean.

Modem delay simulator

See delay.h and delay.c for a real working example including unit test.
Dan Kegel