There was an article linked from Digg posted up a couple days ago entitled “6 ways to write better code”. It’s pretty good advice (for the most part), so I thought I’d link it here.
Here are the recommendations of the author, along with my own comments:
1) Comment like a smart person.
I can’t emphasize this enough. Code that seems beyond obvious has a funny way of reading like a foreign language after a couple of months. Comment everything -- and don’t just state the obvious. Try to write the comment as if you were writing it for someone else who has no prior knowledge of what you are doing. Because in three or six months, that person will be you.
2) Use #define a lot. No, a LOT.
Right sentiment, wrong implementation. As the article says, it’s a very bad idea to hard-code numbers into your program. Inevitably, you’ll want to change something in the future, and it’s really difficult if everything there are numbers scattered everywhere. Using #define helps document what you are doing, and makes it easy to change those numbers in the future.
But #define is so… C. There are a few problems with using #defines. First, because #define is a preprocessor command, the preprocessor goes through and replaces all your defined names with their corresponding values. This means those names are not available when you are debugging, which makes debugging more difficult. Assume you have a function call that passes in a #defined value called EXP_PER_KILL. Even though the code you are debugging may says AddExp(EXP_PER_KILL), you won’t have any idea what EXP_PER_KILL evaluates to unless you can locate it’s definition.
Second, #defined variables are always declared in the global scope regardless of where they are defined.
In the world of C++, we can do better. One better choice is to use a const variable. Const variables are actual objects, so you can easily get their values in the debugger, and they follow normal scoping rules. The other better choice is to use an enum, which has the same benefits.
3) Don’t use variable names that will mock you.
Not much to say about this -- naming your variables things that makes their purpose clear is an important aspect of documenting your code.
4) Do error checking. You make errors. Yes, you.
This one is both easier and harder than it looks. Inevitably you will misuse a function you wrote by passing it an invalid parameter, or something will go wrong and a pointer will end up NULL when you were expecting it to have a value or vice-versa. Checking for these things is good and can and will keep your program from crashing. However, if you do detect an error and then do not do anything intelligent with that information, your program might as well just crash and get it over with.
Just as big a problem as detecting an error is doing something intelligent about it. If you’re writing a reusable function, the intelligent thing generally involves informing your caller that something went wrong and leaving it up to the caller to handle the problem. If you’re the caller, or you’re writing a function that’s integral to your program, figuring out how to handle errors can be a tricky proposition. Do you pop up a message box warning? Do you ask the user for new input? Do you save the user’s data and then terminate the program? It really depends, and there’s no easy solution.
But before you can do any of these things, you have to detect than an error occurred, and that’s why I agree with the author that this is important.
5) “Premature optimization is the root of all evil.” - Donald Knuth
One of the biggest problems new or overzealous programmers run into is trying to write code that is as fast as possible at the expense of things like code readability. This is almost always a bad idea. It IS a good idea to pick an algorithm that’s right for the problem you’re trying to solve -- for example, if you’re doing lots of element insertions and deletions, a linked list is probably going to be a better choice than an array. But that doesn’t mean you have to design an algorithm that squeezes out every last bit of performance out of the linked list. Efficiency generally comes at the expense of legibility, and honestly, with a few exceptions, legibility is more important, because at some point, you’re going to have to fix a bug, or expand your code, and code that’s tricked-out to be as efficient as possible isn’t going to be conducive to either of those things.
Once your code is written, you can always profile it to find out where the ACTUAL bottlenecks are, rather than prematurely act on where you perceive the bottlenecks may be. With properly implemented code that utilizes concepts such as encapsulation, swapping out one algorithm for a better one when needed is often no problem.
6) Don’t be too clever by half.
This is sort of along the same lines as #5. It’s almost always a better idea to write code that is clean, straightforward, and legible than code that is as efficient as possible. As I wrote in the section on comments, if you need a comment to explain what your line of code is doing, it probably needs to be rewritten, not commented.
Many of you have heard of the KISS acronym -- Keep It Simple, Stupid. It applies to code too.