[ 0x68.com Home ] [ Short Code Snippets ] [ Debugging FAQ ] [ Basic Debugging in Visual C++ ]

How To Avoid Debugging

tenfour August 3, 2002

Introduction

Although debugging is a necessity and smoothes out development, I think we would all rather avoid it if possible. With this as our focus, we have two choices:

  1. Write code with no bugs.
  2. Don't write code in the first place.
For most of us die-hards, the second option is simply impractical; how would we ever feed our addiction-to-code? This article is, then, a collection of my advice on how to avoid bugs in the first place. In particular, I will discuss Win32, but the concepts apply in all forms of programming (maybe even life in general, who knows).

These rules are basically common sense; I am just presenting them and bringing them forward in plain sight. You should follow these rules from the moment you create the project until the moment you receive your first royalty check (which doesn't happen until shortly after you die).

Your Program IS NOT Too Small... It's Just a Good Size :)

Many people think that their application is too small for these guidelines to apply. Nothing could be further from the truth. The advice I offer in this article applies very generally to coding - it even applies to web pages. Often coders think their project is very small so they can just dive in, keyboards-a-blazin, until they find that it wasn't as small as they thought, and now main.c is 1400 lines long and impossible to navigate.

The relief, though, is that for a small program, these steps are quick and easy.

Think First, Write Code Later

Before firing up your dev environment and typing int main(), think first about how you're going to design your application. For applications of *ANY* size, this is very important. I usually open up notepad.exe and type out a tiny document outlining at least these things: Doing just that tiny thing will clarify my intentions and also hopefully raise questions about issues I would otherwise encounter during development. It's obviously better to address those issues before you've begun to write the code.

Never Assume, Only Guess

There are very few instances where you already know all you need to know about what you're writing. When I write code, MSDN and Google are at my fingertips at all times so I can look up APIs or search google for sample code or do other research. I mean, who actually memorizes the ten arguments to CreateProcess(), or all the window styles for a ListView?

It's the mark of a weary developer when he/she starts typing out arguments to a function without knowing exactly what to put there. This leads to disaster when the application doesn't perform as expected and he/she is left to decypher the meaning of the mysterious code.

The difference between an assumption and a guess is that when you make a guess, you know it's probably wrong. When you guess at the answer for something, you are saying, "I think the answer should be [x], but I will research it and determine whether I am correct or not." At least that's what should happen.

Another example of this is when John Q. Developer assumes an API does something, when in fact the correct solution may be something he doesn't expect. For instance, I was working with a developer trying to force an update to a window. He was using UpdateWindow() (which he assumed would work, given its name), but it wasn't updating the window - he told me it acted as if it wasn't being called at all. A closer look at MSDN shows, though, that it will only draw the portion of the window that's been invalidated either by the user or by InvalidateRect(). After this bit of research, he was able to fix the app and move on.

Behavioral bugs can be very difficult to track down, and those are typically the bugs that arise from assumptions.

Test Frequently

I think this goes without saying. Don't write 4000 lines of code and then hit F5 and be faced with an access violation. It's better to write test code to narrow down issues. For instance, after writing a class, it's a good idea to write a function to test the different methods of the class and arguments to those methods.

If you can find the problem right after you've written the code for it, you'll not only have it fresh in your memory, but there will be less "other" code to interfere with your debugging efforts.

Check All Return Values

If you fail to check the return values of function calls, you will be faced with a debugging nightmare. Each and every function call can theoretically fail. Most functions will return a value indicating success or failure. For every failure, your application should behave in a way that is expected and not "choke". If you assume that a function will always succeed, you're cruisin-for-a-bruisin' (and you better be looking forward to releasing a service pack or patch).

It's not necessary to handle every failing call. For instance, if CloseHandle() fails, most of the time you can just ignore it because your application will still continue as normal after the failure.

However, if CreateWindowEx() fails and your program continues as if nothing ever happened, your program will most likely behave in a very unexpected way.

Webmaster: fromahuman@hotmail.com