I've been programming in 'C' and 'C++' for a few years now, along the way I've
learned a thing or two that have become part of my personal best coding
practices and I thought I would pass these tidbits on for others to use.
These hints, while written with the 'C' and C++ languages in mind, can
be applied to other structured programming languages as well.
Code For Maintainability
When coding, keep this firmly in mind: someone (most likely you!) will have
to revise and maintain the code your writing today at some point in the future.
Will you be able to understand the code you're currently writing six months
from now? A year from now? If not then you need to change some things.
Do not comment the obvious
But if you have done something rare, elegant, crafty, or otherwise tricky
then comment the hell out of it. Voodoo Programming is not a viable method for
ensuring job security.
It is common practices these days to use what is called Hungarian Notation
as a naming convention. This notation seeks to encode type information in a
name as a visual clue to the programmer, in an effort to eliminate data type
mismatches. The fact is that most modern compliers will always catch type
mismatch type problems.
int iCount; // An integer variable.
int iGetPageCount(DOC *ThisDoc); // Returns an int
iCount = iGetPageCount(MyDoc); // Types match.
The problem with this practice is that it detracts from the maintainability
of the code. If you need to change the iGetPageCount() function (above) to
return a long value, you have to wade through your source, looking for every
occurrence of the function name and change it to lGetPageCount() and you
have to change the name of every variable that receives a value in a call
to that function - what a maintenance nightmare!! Without using the Hungarian
Notation all that needs to be changed is the type of the function and the
variables that receive its values. For this reason alone I have given up
using this convention. Giving up Hungarian Notation has saved me many hours
that would otherwise be worthlessly spent maintaining my naming convention.
When dealing with large, daunting projects, it is very easy to get tied
up in trying to plan and design the whole thing at one time. This is usually
counter productive. Break the problem down into smaller logical units. If
each of these is still too big, then break them down into yet smaller
logical units. Start designing when you have a piece that you can get
your mind around. I've often found it beneficial to design and build a
small piece, test it, then go on to the next piece, rather than designing
them all at once. Do the coding while the design is fresh in your mind.
Test, test, test!
Test the small pieces of your project as individual units; make sure they work
as planned. If they do work then try passing them bad data elements, just to
see what happens. Yeah, yeah I know that subroutine will never be called with
a value that big! Yeah right. Been there, done that, spent hours tracking
down the problem. Protect your code from bad data!
Build test harnesses into your code
Include a main() function in each module (surrounded by conditional compilation
macros) so you can compile and test it in isolation from other modules. If
you've written a library take the time to write a module that includes a
main function that does nothing except test the library routines.
Read, read, read!
Do you read Dr. Dobbs, Software Development, or the C Users Journal?
If not - why not? You think you know everything? I learn something from
each of these magazines every single month. "So what?" you may ask? Well, let me
put it this way; I hope you are the competition for my next job.