If Anders Hejlsberg does it, there's no shame in it.
I've found that stepping through code in a debugger at a human pace, and getting to really understand what's happening when a bug occurs is invaluable.
Same problem happens with other methods too: If you develop solely with unit and integration tests, it might actually be quite difficult to get a step-through debugger set up to debug your application. I worked at a company where I was the only one who used a step-through debugger, and some uses of compile-time metaprogramming would frequently break the debugger.
And if you use multiple techniques as appropriate(unit tests, printf or equivalent, step-through debugging), it's generally easy to use any of them as appropriate.
Organized (multi verbose level) tracing built right into the application can go a long way before you actually need a debugger.
Sometimes I think the people who have success with debuggers often must be working on a different class of problems than I am familiar with.
Numerical problems can usually be fixed with a series of targeted asserts and logs.
For example, just a few hours ago I convinced a colleague to try using the debugger. Our hardware has had a functional JTAG-based debugging toolchain for years, but people still haven't picked up on it. I'm the new guy who spearheaded it in the team -_-
The general workflow, when presented with a new system, was something like:
(a) Board would arrive. Admire it for a bit.
(b) Look suspiciously at the supplied CD. Gingerly insert it into computer. Oh, look, a Windows install.exe. Insert it into the Windows computer next to mine (with its screen and keyboard slaved to mine with x2vnc, which is great). Install.
(c) Load the terrifying, buggy, proprietary IDE. Close it again. (This was in the pre-Eclipse days. You really had no idea what you were going to get here.)
(d) Search through the vast pile of useless guff which it had installed for the embedded copy of gcc. Find it. Also find the BSP libraries, and link scripts.
(e) Realise it's a terrifying, buggy, proprietary-patched version of gcc where the source package doesn't match the binary.
(f) Attempt to find whatever terrifying, buggy, proprietary tool actually downloads images onto the board.
(g) From the command line, write a tiny makefile which uses everything found in (c) plus (f) plus the terrifyingly misspelt quote documentation unquote (supplied in a PDF on the CD) and attempt to produce and run a 'Hello world' image. Download and run it.
(h) Assuming (g) worked, bolt it on to our existing gcc-and-make based built automation and actually start work.
Any debugger was usually so tightly integrated to the IDE, which was always set up to assume a particular project layout which didn't match our source layout, that it was usually more trouble than it was worth; particular as our product had a lot of JIT stuff in it, which a source debugger couldn't help with much anyway.
The very best boards had an on-board monitor which gave you a Commodore PET-style assembler debugger. One even had hardware watch and breakpoints! The ability to single step through stuff, via a serial terminal, with no prior setup required, was amazing. It was sufficiently robust that even when the board really crashed badly it would drop into the monitor and you could examine what had gone wrong.
I have a particular hatred for the debuggers which required a slave task running on the board itself. (a) sucks to be you if you were running a different OS; (b) oddly enough, if your app crashed and scribbled all over memory, it tended to stop working...
</rant>
Edit: Oh, I forgot to say --- this was mostly before JTAG was ubiquitous, so debugging options were either a terrible, proprietary serial monitor or a terrifyingly expensive ICE unit. JTAG did come along later, and it was miraculous; you could even single-step through interrupt handlers with it! But it wasn't standardised and each board typically had its own interface, which wasn't supplied, plus its own software. Then not long after I got out of the game.
...I'm having flashbacks now. Downloading Java images onto an M-Core development board at 100-200 bytes per second with a 1 in 10 chance of a failed download for every megabyte. You think I'm exaggerating. I'm not. I still have the CPU from that board somewhere; I ripped it off once we were finished to make sure that nobody would ever have to use it again.
This is why I have a stash of whiskey at my desk ;)
(though honestly I haven't touched it in a while. Impairs debugging, really)
The BSPs are still as scary as they ever were, though.
For my 400 level embedded systems design paper (which was actually a hardware design paper, we weren't graded on the code), we built boards that we could program and debug with JTAG.
I was stuck on a pain point for hours until one of the tutors showed me how to use GDB with the boards via JTAG. It took me literally 5 minutes to fix the problem. Being able to step through the code line by line allowed me to see exactly where it was breaking, and why it was breaking.
If I'm ever doing embedded development again (unlikely as I'm now employed as a web developer), I don't think I'll be able to function at all without a proper debugging environment.
Should be enough for anyone. Some people used flashing LEDs to dump an entire firmware! ;)
There's a grain of truth in both cases - there's no energy efficiency like not needing to move around at all, and there's no memory/CPU/cost efficiency like not having sophisticated functionality in the first place.
But once you are used to the functionality that comes from heavyweight tools, "do without - it's better for you" is frustrating at best and more likely engenders hostility for the person saying it.