The thing is, your imagination of what I’m doing (littering code with printf statements) and the actual reality of what I'm doing (solving AT LEAST 95% of my problems using extensive automated tests, strong linting, strict typechecking, and modern programming practices) is leagues apart. When I say I break out the debugger around every few months, I am not exaggerating. I may insert a printf or two once every other week. This is not the common case, it’s just significantly more common for me than attaching a debugger, because it’s quick and easy.
The practice I adhere to is to break code up into small modular bits then unit test the living hell out of those bits, then integration test larger combinations. Maintaining test code takes time, but I take it very seriously. I can’t share any of my actual work at Google but I can share my open source work; a project that I wrote this way is Restruct and it normally has around 98% line coverage. If someone finds a bug I add a new test. I have never used a debugger on Restruct or projects built on Restruct.
So then, what do I do all day? Console.log and printf everything? No, honestly no. I spend little of the day debugging because unit tests tell me nearly exactly what codepaths I broke, printing out helpful diffs of the expected behavior versus the actual behavior. This almost always gives way to the problem, even when I’m working on a brand new piece of code with tests I just wrote (sometimes before the code, even.)
So I would say printf is my goto debugging tool, but if I want to be accurate, it’s probably really automated testing. Automated testing used in this fashion basically acts as small little debug routines. We don’t call tests debugging tools though, because that would undermine their usefulness; they do so much more. Which is why I don’t sweat it when I have just as much or more test code than actual code; unlike other code, it often pays for itself if you do a good job.
And besides, if unit tests explain a bug to you before you actually run into it, did you really do any debugging or did you bypass it entirely?