Although you might need additional infrastructure requirements for your unique environment, you'll find the ones covered in this chapter are generic across all environments. And, they are the ones that I've seen make a great deal of difference in real-world development. If you don't have one or more of these infrastructure tools or techniques set up at your development shop, I strongly
you to implement them immediately. They will save you literally hundreds of hours of debugging time.
Debugging During Coding
In Chapter 2, I laid the
for the project-wide infrastructure needed to enable
to work more
. In this chapter, we'll
to what you need to do to make debugging easier while you're heavy in the coding
. Most people refer to this process as defensive programming, but I like to think of it as something broader and deeper: proactive programming, or debugging during coding. To me, defensive programming is the error handling code that tells you an error occurred. Proactive programming
you why the error occurred.
Coding defensively is only part of the battle of fixing and solving
attempt to make the obvious defensive maneuvers—for example, verifying that a C++ pointer to a string isn't NULL—but they often don't take the extra step that proactive programming would require: checking that same parameter to see whether the memory is sufficient to hold the maximum string allowed. Proactive programming means doing everything possible to avoid ever having to use the debugger and instead making the code tell you where the problems are. The debugger can be one of the biggest time drains in the world, and the way to avoid it is to have the code tell you exactly when something isn't perfect. Whenever you type a line of code, you need to stop and look at what you're
is the good-case scenario and determine how you're going to verify that the case in question is exactly what the state will be every time you execute that line of code.
It's a simple fact: bugs don't just magically appear in code. The "secret" is that you and I put them in as we're writing the code, and those pesky bugs can come from myriad sources. They can be the result of a problem as critical as a design flaw in your application or as simple as a typographical error. Although some bugs are easy to fix, others are nearly
to solve without major rewrites. It would be nice to blame the bugs in your code on gremlins, but you need to accept the fact that you and your coworkers are the ones
the bugs in the code. (If you're reading this book, it has to be
your coworkers putting the bugs in.)
Because you and the other developers are responsible for any bugs in the code, the issue becomes one of finding ways to create a system of checks and
that lets you catch bugs as you go. I've always referred to this approach as "trust, but verify," which is Ronald Reagan's famous quote about how the United States was going to enforce one of the
with the former Soviet Union. I trust that my colleagues and I will use my code correctly. To avoid bugs, however, I verify everything. I verify the data that others pass into my code, I verify my code's internal manipulations, I verify every assumption I make in my code, I verify data my code
to others, and I verify data coming back from calls my code makes. If there's something to verify, I verify it. This obsessive verification is nothing personal against my coworkers, and I don't have any psychological problems (to speak of). It's just that I know where the bugs come from; I also know that you can't let anything by without checking it if you want to catch your bugs as early as you can.
Before we go any further, I need to stress one key tenet of my development philosophy: code quality is the sole responsibility of the development engineers, not the test engineers, technical writers, or managers. You and I are the ones writing, implementing, and fixing the code, so we're the only ones who can take meaningful measures to ensure the code we write is as bug free as possible.
As a consultant, one of the most surprising attitudes I encounter in many organizations is that developers should only develop and testers only test. The prevailing problem with this approach is that developers write a bunch of code and ever-so-
decide whether it executes the good condition before throwing it over the wall to the testers. It goes without saying that you're asking for schedule slippage as well as a poor quality product when developers don't take responsibility for testing their code.
In my opinion, a developer is a tester is a developer. I can't stress this enough:
if a developer isn't spending at least 40 to 50 percent of his development time testing his code, he is not developing
. A tester's job is to focus on issues such as fit and finish, stress testing, and performance testing. Finding a crash should be an extremely rare occurrence for a tester. If the code does crash, it reflects directly on the development engineer's competence. The key to developer testing is the unit test. Your goal is to execute as much of your code as possible to ensure that it doesn't crash and properly meets established specifications and requirements. Armed with solid unit test results, the test engineers can look for integration issues and
test issues. We'll go over unit testing in detail in the section "Trust Yourself, but Verify (Unit Testing)" later in this chapter.