Simon Mourier wrote a large blog about debugging and sums up several points why debugging is still a PITA and that during all those years debuggers are still well.. harsh and cumbersome.
I disagree with most of the points Simon mentions. The command line gnu debugger still causes sweaty palms and horrible nightmares when I think of it. In that light, debuggers have come a long way when I compare that horrible piece of software with a state of the art debugger like the one in Visual Studio.NET (which, if I might add, is also included in the .NET SDK, so you can visually debug your .NET code without Visual Studio.NET).
What is debugging anyway? To answer that correctly, we first have to define what a bug is. A bug is a defect in software that causes that same software to fail to comply to a given specification. You have two types of bugs: 1) code error related bugs and 2) design error related bugs. Lets start with category 1), our friends, the code error bugs.
Code error bugs
When a developer writes code, that code has to perform a fixed set of functionality. In theory, we should be able to define a pre-condition and a post-condition for every piece of code written. If a piece of code's runtime post-condition is not matching the post-condition defined in theory, we can speak of a code error related bug. The name suggests that fixing the code is fixing the bug, since the design is correct, the code written is simply not the right projection of the functionality defined on a program language.
How do you fix these code error bugs? With a debugger. Since every piece of code has a defined pre- and post-condition, we can fast nail down the hot-spot where the bug might be in. This technique is based on the fact that the code used by the code containing the code error is bug-free, or better: is able to match at runtime its post-condition when the pre-condition is met. A debugger like the Visual Studio.NET debugger is then an ultimate tool to dive into that hot-spot area. While stepping through the code you can see if the code written is matching its pre- and post-conditions for each line of code. You then also can see fast where the code is going wrong and where to insert new code/different code to fix the code error, which will fix the code error bug.
This is an individual process. The reasoning behind that is that, besides the programming-in-pairs in eXtreme Programming, it's wise not to let 2 or more developers work on the same routine: developer A writes routines M, N and O and developer B writes routines P, Q and R, which consume routines M, N and O. Developer B can, and has to, assume that A's code is OK, it will meet the defined pre- and post-conditions defined, or better: it will perform the functionality it's the implementation of. B should not be bugged (pun intended) with bugs in A's code, that's A's responsibility. Debugging A's code is therefor not a team-effort, but should be done by the individual who wrote the code and thus the errorous code.
Design error bugs
Design error bugs are a total different ballgame. Design errors are not caused by errors in the code, but by errors in the design, which implies that in theory the developers have done their best and have written code which will meet at runtime the pre- and post-conditions defined at designtime. A code-related debugger, ran by an individual is therefor not the right way to nail this type of bug. Design error bugs are found during testing, automated or manual, after several pieces of code are already tested for code error bugs. Design error bugs are removed by rational thinking, research, case studies and tests: only by investigating the possible issues with a given design, which is done without even looking at code, you can probably nail these kind of bugs and find solutions for the design flaws by defining a different design which is then implemented instead of the current, correct but wrongly design, code. Debuggers will not help you with that. Do not use debuggers for nailing down design error bugs, only for researching why correct code fails in a given situation.
Testing and debugging are not mutual exclusive but are often confused: people test the hell out of code which in its smallest possible unit, code flow statements inside a method, isn't even matching its theoretical post-condition. Such testing is not the way to go. Otherwise you whole legions of developers debugging code hour after hour, while they know its correct code but the design is flawed: if the code is correct, it's correct, and you shouldn't be spending time in a debugger, but on a chair next to the software designer explaining in which situation his design fails.
I think Simon confuses the two types of bugs a bit. Debugging isn't an art, it's using common sense. Not using common sense when you are confronted with unexpected behavior of software will result in the usage of the wrong tool (test tools when debuggers are better and vice versa) to fix what's wrong. That's why I debug a lot while writing code and test a lot while testing designs.