Afterwood

If debugging is the process of removing software bugs, then programming must be the process of putting them in.” -- Edsger W. Dijkstra

When it comes to most books and technologies I’m typically very late to the party – the rest of the world has usually moved on just as I’m getting interested in it. Somewhat unusually for me then, I ended up reading the book Coders at Work by Peter Seibel within the first year of its publication (2009). A natural consequence of always being late to the party is that most of my books are second hand, so it was especially unusual for me to own, and be reading a brand-new book. The circumstances that led to this seemingly Black Swan like event were – my upcoming birthday, an online bookstore wish-list, and a mother struggling (yet again) to think of a present for her forty-year-old son.

I must confess that at the time I didn’t know who most of the programmers were that the author had interviewed – I only recognised four out of the fifteen names, and one of those had only entered my consciousness a couple of months earlier at the StackOverflow Dev Day. As someone who considered themself reasonably well-read this was somewhat of a surprise. Fifteen years later I can still only tell you who nine of the fifteen are, despite reading the entire book. It turns out names are hard in the real-world too – remembering them, that is.

Anyway, what I do remember most about that book was the subject of debugging. Most of the interviewees made very little use of a debugger, if at all, print-style debugging appeared to be their default technique. And yet, based on their biographies and conversations, these people have clearly all worked on non-trivial codebases so I couldn’t fathom how they’d manage to live without such an important diagnostic and exploratory tool.

At that point in time my programming career had focused entirely on lower-level programming languages, such as assembly language, C, and then C++. My first experience with a debugger was with the Pyradev toolset on the Amstrad CPC6128, although they called it a “monitor” rather than a debugger, but you could still single-step through machine code. From there to Devpac on the Atari ST, CodeView under 16-bit Windows (not forgetting the truly awesome SoftICE when you needed to pull out the big guns), and eventually to Visual Studio over its many incarnations (with CDB/NTSD/WinDbg making guest appearances here and there). In essence, from my mid-teens in the 80’s right up to my forties (and eventually on to my fifties), a debugger has been a fundamental part of my programming toolkit, even as I moved into the managed world of C# and .Net.

In contrast, the last five years has seen me working in an in-house language that has no debugger, and so consequently print-style debugging has become my only choice. This language is a pure functional language, so memory-safety is not a source of bugs, and people generally write small functions which are easy to invoke on a whim via a REPL. It’s a very different world, and yet I still yearn for a debugger, not necessarily to help fix bugs, though it would help reduce the time there, but mostly to help visualise the flows through the 100K+ lines of code.

When my son was very young, he came into the office one day when I was working from home and stood behind my chair and watched my screen. Eventually he asked, “what are you doing dad?” I explained that I was “debugging some code”. Later he remarked to my wife that all I did all day was “make a yellow line move up and down the screen”. (I was using an editor colour scheme where the current statement in the debugger was highlighted with a yellow bar. As an aside that choice of colour scheme – blue background with white text – also dates back to Pyradev.)

He wasn’t wrong. Source code is inherently static, and what a debugger does is to animate it. Suddenly the instruction pointer stops being an abstract hexadecimal value as the debugger translates that into positions within source files. Flow control stops being something you have to mentally picture because the debugger shuffles the code around on screen as you enter and exit functions and cycle around loop constructs. Most mainstream programming languages feature closures, which are simplified by syntactic sugar, but the debugger typically reveals what’s going on under the hood. (Maybe motion sickness during debugging could be a proxy for code complexity?)

This idea of using a debugger as a code exploration tool, not just something you reach for in times of despair is far from new. In Writing Solid Code Steve Maguire proposed you also step through all new code in the debugger as a way of testing it. In essence the debugger allows you to take the same journey as the CPU before it hits production. It’s much easier to spot an incorrect flow or off-by-one loop error when you’re watching the code execute in slow motion.

My move away from system programming languages has definitely caused my skills with a debugger to atrophy. That’s not the only reason though – Test-Driven Development has also given me confidence in my code in a way that allows me to avoid firing up the debugger “to see it in action”, more times than not. Even so, old habits die hard, and being able to fire up the debugger and use a unit test to quickly get into the production code is simply the icing on the cake and yet another way to unearth further test scenarios that weren’t obvious from the static viewpoint.

I’ve never really understood the backlash against using a debugger, as if “real programmers” only need print statements, though maybe Chuck Norris is probably the exception. I suspect Brian Kernighan’s famous quote probably hasn’t helped:

“The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.”

Of course, he wrote that way back in 1979 and therefore likely suffers from the same malaise as that optimisation quote from Sir Tony Hoare. Debugging Katas are quite a niche exercise too which doesn’t exactly help their popularity outside crisis management.

Having someone take my toys away from me has undoubtedly been a force for good as it’s prompted me to “think harder” (apparently that’s not just for LLMs) and put even more effort into making my code easier to reason about, but I’d still prefer to have a debugger in my back pocket for those Lewis & Clark style expeditions.

Chris Oldwood
12 July 2025

Biography

Chris is a freelance programmer who started out as a bedroom coder in the 80’s writing assembly language on 8-bit micros. These days it's enterprise grade technology in plush corporate offices from the comfort of his breakfast bar. He also commentates on the Godmanchester duck race and is easily distracted by emails and DMs to gort@cix.co.uk and @chrisoldwood.