Debugging is an Art !

Debugging is one of those areas in programming which in my opinion doesn’t get enough emphasis when teaching programming. In this article I will discussion why it is important and also some suggestions to help in debugging. Since Powerbasic is my primary programming language, all suggestions will be geared towards debugging in PowerBasic for Windows.

First the “why” it is so important.

No matter how fancy and polished your software may look, if it has serious bugs in it, it is useless. Also it is very easy for a programmer to blame the end user when problems occur when using the software, rather than the programmer taking a hard look at his software to see if it really does have a bug. Lastly it is too easy for programmers to feel that “all software has bugs in it”, so “end users will just have to live with it”.

Personally I feel such feelings are absolutely wrong and may indicate the programmer is not as qualified as they make think they are. While it is true, that 100% bug free software may not ever be possible, it is also true that when a programmer becomes aware of known bugs and simply does nothing about them (at minimum warn the user and provide a workaround if possible until it can be fixed) something is definitely wrong.

Maybe the problem with buggy software has something to do with how programmers write software, so lets consider this. First, it is important to use good programming habits to decrease the risk of bugs. One of my favorites is the simple #DIM ALL compiler directive in PowerBasic. You would be surprised how many PB’ers (thats short for PowerBasic programmers) don’t ever use this directive. This simple directive forces the compiler to expect that every variable used must be declared at some point (ie. LOCAL, GLOBAL statements). This prevents so many simple typing errors from getting through, because if you misspell a variable name, the compiler won’t think it is just another variable, but it will actually generate an error message when compiling. This compiler directive is an absolute must in my opinion.

Another area has to do with variable names. While one does not have to follow any rules on this, one should seriously consider how their name conventions will effect debugging. For example I like to always define Global variables with a common prefix. One I use a lot is App_ which indicates this variable is global and available to the enitre app. This makes code so much more readable and it prevents a lot of problems.

Next, while it may not be the popular and so called “standard” today when writing code, I prefer to write variables with type identifiers rather than the syntax of LOCAL MyVar AS LONG. Now I can see if a variable may need to change because of changes in the Windows API, so it may be better for some variables to be defined with a type indentifier, so in that case definitely do it. But in code which will likely never experience a change in data types, use the type identifiers. It makes code more readable at a glance, because you can tell what type a variable is simply by its name. Now if you must avoid using type identifiers, then maybe name the variables with a prefix for each type. For example an asciiZ string variable could start with a small z (ie. zText) and a dword variable could start with dw (ie. dwSomeVar). Also it is a good idea to use some prefixes in general to indicate what is stored in a variable. For example I like to always add a small h to variable names which store some kind of handle (ie. hWnd, hDlg, hCtrl, hPen, hBrush).

Put some serious thought into your style of coding with the idea of making code more readable. If a bug is found later on, you may find yourself having to go back and read code you wrote last year, so you need to be able to make sense of it quickly.

Another important step in debugging software, is to write modular code. It need not be object oriented to be modular. I write all my code using good old fashioned procedural style coding (ie. sub, function), yet I tend to write very modular code. If code is not time critical (speed) it doesn’t hurt to break it up into smaller blocks of code. You will be amazed how much easier it is to debug modular code. Once a subroutine or function is debugged, then every other routine which calls it, is guaranteed to work better. Reuse code as much as possible. This make applications smaller, but also makes software more reliable because it is easier to debug.

Now the next area is where I think many programmers may have a difficulty. I strongly feel that debugging is the responsibility of the programmer and not of the users. It is easy for a programmer to fall into the trap of thinking, they can write all the code they want and if there are bugs, the Beta testers will catch them. Beta testing should not be ones sole means of debugging. A programmer should test everything he writes, even writing test applications to test the new code. If you write a database engine, then create a test app to create a database with it and make sure it works properly. The point is, be willing to put your code through the paces to see if it works. Also be willing to put your code to the test by pushing it to its max. If you write a database engine, don’t test it with a small tiny database, but test it with a huge, larger than normal database. What works well when not under load, may simply choke when put under a much larger load. For example, in autoparts stores when they bench test an alternator or a battery, they have to put it under some heavy load, because it may pass under a light load, but then fail under a heavier load. The same is true for sofware.

For example, I was bench testing so to speak my EZSprite software (a 2D Sprite engine). It ran well with say 12 or 24 sprites. One day I was comparing my sprite engine to another graphic tool which could animate objects like sprites and while the other tool worked well with a small load, when I put it under a much larger load, say 100 objects, it demonstrated that it was not as fast as you would have thought. I figured I needed to put EZSprite under a much larger load to see if it would do the same. I created a test app where EZSprite used the exact same sprite animation as the other tool and then had it create and animate (move and frames) 500 sprites. Thats a lot of sprites for a software based 2D sprite engine. Amazingly it did quite well and actually was faster than the tool I was comparing it to. Only when the other tool resorted to using hardware support, did it run faster than EZSprite.

The idea is to bench test ones applications and to put it through the paces, before it even gets to the end user. You will find that bugs (or poor speed) will show up more quickly when you purposely are looking for them. With EZGUI, I find most bugs even before my customers ever notice they are there, because I do a lot of testing.

Now one will say that testing takes valuable time I just don’t have. My answer is “make the time”, because if you don’t want to test your software you shouldn’t be writing it. Look at car manufacturers where they run their cars through torture tests and crash them, just to see how they perform when pushed to the limit.  You have to be willing to do the same with software.

Debugging and testing is a art form. You have to learn how to do it and how to do it right. It is not enough to learn how to write code. You have to learn the fine art of debugging. Now a warning! Do not think the solution to debugging is simply making the compiler or other third party tools do all the work for you. Some programmers feel they are debuggers when the use software tools such as third party debuggers to “catch” bugs. The best debugger is you the programmer. Software is stupid compared to a human being. Thats the truth. The human mind, when trained to look for bugs, is better than all the debugger tools combined. Now this does not mean you can’t or shouldn’t use such tools. It just means don’t think that a software tool will relieve you of the responsibility of learning the art of debugging and the need to write quality, modular code. Just for your information, personally I don’t use any of the debug tools built into the compiler and I don’t use any third party debuggers available and my software has a reputation of being “solid as a rock”. This is because I have taken the time to learn the art of debugging. I learn from my mistakes and over time I change my coding habits to add new ways to produce better code. I test my code, specifically new routines I write before I use it in production code. I experiment a lot to make sure I know what I am doing with some new API before I introduce it to my actual software products.

Lastly, I spend a lot of time testing and experimenting to make sure what I write works as intended.

If you want to be “great programmer”, then take the time to learn the art of debugging. Strive for 100% bug free software. Learn from your mistakes and be willing to change your style of coding when it becomes obvious you need to. Lastly, don’t expect the end users (the customers) to be your debuggers and testers. Consider it your responsibility!

3 comments

  • Sorry, I got a bit off track and didn’t stick to the debugging subject. How about some future thoughts on testing ?

  • Most debugging requires “common sense”, even tough bugs like corrupted memory. I use a simple messagebox a lot or the BEEP command to test for logic errors. I will REM out blocks of code to see the effects (ie. IF GPF will go away). The idea is to be like a “blood hound” and step by step track down the origin of the bug. Once you get close enough to the problem code (you find the offending routine) it is just a matter of closely examining the code to look for errors. My GUI engine, EZGUI has a debug window for help in tracking errors in events. I add code to display values of certain variables or print a message if certain logic is executed to the debug window. You still though have to track down the ‘area” where the bug is first and then start checking out code line by line. I do have to note though that by writing good code in the first place (proper variable names, modular, etc.) you have less bugs to track down in the first place.

  • do you do any unit testing ? very powerful stuff and you can ‘roll your own’ test harness very easily.