A good debugger is a very capable tool. With it, an experienced developer can step through very complex code, look at all the variables, data structures, and stack frames; even modify the code and continue. And yet, for all their power, debuggers have done more to damage software development than help it.
Rob goes on:
…a debugger is a tool of last resort. Once you have exhausted every other avenue of diagnosis, and have given very careful thought to just rewriting the offending code, *then* you may need a debugger.
The problem is that by then, you might have missed your deadline and wasted your precious time by adding and removing manually all sorts of logging code, not mentioning the headache by staring at the screen for the outputs.
Andreas chimes in with a mind-boggling analogy:
A debugger is like a telescope looking at the night sky and you have to find the North Star.
Talk about a leaky abstraction (how about a telescope where you can type in the name of the star you want to watch and which will possibly rotate the Earth for you so you can observe it. Now that’s a more accurate analogy).
People who campaign against debuggers typically think that debuggers are only good to find bugs. That’s an unfortunately common misconception.
A debugger is also very powerful at making sure a bug doesn’t happen in the first place. I don’t know about you, but pretty much every time I write a reasonable chunk of code, I always run it first inside a debugger. No stupid println comment, just the hard facts and the naked truth about all the variables I created.
Now let’s turn to the alternative chosen by Rob and Andreas, which is so deeply flawed that it’s hard to know where to being: println debugging. Here are a few facts about this practice:
- A println is tedious and error prone. You need to know exactly where to insert your println and make sure you remove it before you ship. No matter how good you are, I’ll bet my little kitten Trogdor that shipping with a debug statement has happened to you at least once.
- A println is human, hence fragile. This debugging method is only as good as your eyes, or your brain. No matter how good you are at reading scrolling consoles or log files, your eyes will get tired. Really quickly. And at some point, I guarantee that you will miss something essential. Which you will forget to remove from your production code (have I already mentioned that?).
- A println cannot be automatically tested. Whenever you feel the need for println debugging, I am betting that you should write a regression test to make sure the bug is fixed. println’s don’t really lend themselves to this kind of exercise and you will probably find yourself changing your println statements to something more testable, like values in a HashMap.
- A println carries your bias. This is the worst thing about println’s: they are typically only found in places where you think there might be a bug. If you created three variables in a method, it’s pretty common to only print one or two of them, because you don’t really need to check that third variable, you just know it contains the right value. Right?
A debugger shows no mercy. It will expose every single variable you created, including arrays, hashmaps or Properties. When you are running your code through a debugger, you don’t just think it’s working. You know it.
Don’t underestimate the power of debuggers, they play a huge part in the software quality cycle.