If you scan the internet, you'll find most comment threads on this topic get the Brian W. Kernighan quote posted to them at least once:
As Brian W. Kernighan and Rob Pike put it in their truly excellent book "The Practice of Programming":
* * *
As personal choice, we tend not to use debuggers beyond getting a stack trace or the value of a variable or two. One reason is that it is easy to get lost in details of complicated data structures and control flow; we find stepping through a program less productive than thinking harder and adding output statements and self-checking code at critical places. Clicking over statements takes longer than scanning the output of judiciously-placed displays. It takes less time to decide where to put print statements than to single-step to the critical section of code, even assuming we know where that is. More important, debugging statements stay with the program; debugging sessions are transient.
I have never been a fan of debuggers, at least not for debugging application code. It's too tedious. One wrong keystroke (step over instead step into) and you throw all your work away. It is much easer to write a test script that exercises the bug, and then run that until the bug is fixed. (print is a great way to get information out of your program while debugging.) The added benefit is that this can become a regression test after you fix the bug, so the bug never comes back. I doubt a debugger can do that.
I will admit that sometimes I play with things in the REPL for a while instead of writing a script. This is somewhat like the debugger, but at a higher level (functions instead of lines), and more interactive. You can fix your faulty function, then hit M-p and try invoking it again until it works.
> One wrong keystroke (step over instead step into) and you throw all your work away.
That's what breakpoints are for, set the breakpoint just before where you "step too far" and try again... I personally find the "printf" technique too limiting, because it's not always obvious which variable is the one that had an unexpected value, especially if your programming to a commercial OS's API. Also, inserting an IO function will sometimes cause a subtle change in state or code compilation that causes "Heisenbugs."
But then again, I got spoiled by the debuggers in older environments like THINK Pascal, with "Observe" and "Instant" windows. It's only recently that IDEs like Xcode and Visual Studio finally attained functionality like that... (FYI, automatic variable watching and the ability to run "immediate" code while stepping.)
My big gripe with using debuggers with modern code, however, is the notion of using accessor functions. It makes what looks like only one line of code involve multiple jumps to other places, making "Step Into" a much less useful command...
I find that using print statements is usually much more effective in debugging than using a debugger, because it forces you to think about how the code being inspected behaves as whole instead of what is causing a particular bug.
I would love to have debugging available to me, but as it is I only have printf (sometimes not even full stacktraces on error!). Printing works. I've become much less dependent on debuggers and much more careful while writing code.
I guess I just use the 2 Ps, but I am wondering: Do some debuggers let you run until error, then step backwards? That seems like it could be very valuable, to me.
i was expecting this to be some kind of linux kernel debugging article given the domain name but it's actually an introductory article on ruby's debug gem.
As Brian W. Kernighan and Rob Pike put it in their truly excellent book "The Practice of Programming":
* * *
As personal choice, we tend not to use debuggers beyond getting a stack trace or the value of a variable or two. One reason is that it is easy to get lost in details of complicated data structures and control flow; we find stepping through a program less productive than thinking harder and adding output statements and self-checking code at critical places. Clicking over statements takes longer than scanning the output of judiciously-placed displays. It takes less time to decide where to put print statements than to single-step to the critical section of code, even assuming we know where that is. More important, debugging statements stay with the program; debugging sessions are transient.
* * *
http://logging.apache.org/log4j/1.2/manual.html