Live data from Hacker News

Don’t look down on print debugging

blog.startifact.com

31–40 of 164 posts

Re: Don’t look down on print debugging

#31
If a good debugger is available, it is a great tool to have. But it is just one out of many tools. Some are more effective than others in different situations.

For example, I rarely used a debugger in my career as an Android driver developer (mostly C), for several reasons.

1. My first step when debugging is looking at the code to build working hypotheses of what sort of issues could be causing the incorrect behavior that is observed.

2. I find assertions to be a great debugging tool. Simply add extra assertions in various places to have my expectations checked automatically by the computer. They can typically unwind the stack to see the whole call trace, which is very useful.

3. Often, there only choice was command-line GDB, which iI found much slower than GUI debuggers.

4. Print statements can be placed inside if statements, so that you only print out data when particular conditions occur. Debuggers didn't have as much fine control.

5. Debugging multi threaded code. Prints were somewhat less likely to interfere with race conditions. I sometimes embedded sleep() calls to trigger different orderings to occur.

Re: Don’t look down on print debugging

#32

While print-type debugging has a place, the reason there are a lot of articles dissuading the practice is the observed reality that people who lean on print debugging often have incomplete knowledge of the immense power of modern debugging tools. This isn't just an assumption I'm making: years of being in developer leadership roles, and then watching a couple of my own sons learning the practice, has shown me in hund…

I find that which tools I need changes immensely depending on what kinds of projects I'm working on.

When debugging parsers for my toy programming languages print debugging is less helpful and I make heavy use of all the debug tools you mention. The same goes for most types of business logic—writing a test and stepping through it in the debugger is usually the way to go.

But when troubleshooting odd behavior in a complex web app, the inverse is true—there are usually many possible points where the failure could occur, and many layers of function calls and API calls to check, which means that sticking a debug statement prematurely slows down your troubleshooting a lot. It's better to sprinkle logs everywhere, trigger the unexpected behavior, and then skim the logs to see where things stop making sense.

In general I think there are two conditions that make the difference between the debugger or print being better:

* Do you already know which unit is failing?

* Is there concurrency involved?

If you don't yet know the failing unit and/or the failing part of the code is concurrent, the debugger will not help you as much as logs will. You could use logs to narrow down the surface area until you know where the failure is and you've eliminated concurrency, but you shouldn't jump straight to the debugger.

Re: Don’t look down on print debugging

#33
I agree with the title that you shouldn't look down on print debugging. You should look down on people who are slow at fixing bugs and who refuse to try tooling to be able to keep pace -- and using print statements can sometimes be a marker of this. But print debugging is just a tool and has its place, and the use of print debugging is not itself an indicator of poor developer performance. If you can find/fix bugs as quickly as I can with a debugger using print statements, then I don't care what you use. If you can do it faster, then I'm going to try to steal your techniques so I can be faster too. If you do it slower, then I hope you would steal my techniques.

Don't care about the tool care about the performance.

Anecdotally, debuggers are faster than print statements in most cases for me. I've been able to find bugs significantly faster using a debugger than with using print statements. I still do use print statements on occasion when I'm developing something where a debugger is very complicated to set up, or in cases where I'm dealing with things happening in parallel/async, where a debugger is less suited. I'm not going to shame you for using print statements, but I do hope that you've tried both and are familiar/comfortable with both approaches and can recognise their strengths/weaknesses -- something I'm not convinced of by this author, which only outlines the strengths of one approach.

Also not a fan of the manufactured outrage of saying people are being "shamed" for using print statements. Coupled with listing a bunch of hyperbolic articles -- many of which don't even seem to be about debugging but about logging libraries.

(Also as a side note: don't forget if you are using print statements for debugging to check if your language buffers the print output!! You'll likely want to have it be unbuffered if you're using print for debugging)

Re: Don’t look down on print debugging

#34
post #12

I think in many scenarios, print debugging wins the cost/benefit analysis - new project where I don't want to learn how to set up a debugger, trying to debug something really custom or specially formatted, etc. However, if I know I'm going to be working on a project for a long time, I usually try to pay the upfront cost of setting up a debugger for common scenarios (ideally I try to make it as easy as hitting a butto…

[deleted]

Re: Don’t look down on print debugging

#35
post #30

I've used both print and proper debuggers plenty. I tend to lean on print debugging more these days. The thing about debuggers, in addition to often being a headache to set up, it usually seems tricky and time-consuming to get it to step to the lines you actually want to examine and skip the stuff you don't. And if you step past something but then later realize it was important, time to start over. It's often faster…

Agree, there are some time travel debuggers though but either only for some programming languages or expensive commercial or only for linux e.g. rr-debugger[0]. Also there is rerun [1] that is only for image processing pipeline debugging.

I wish there was something similar like rerun but for code: you record the whole program running and capture all snapshots then stop it running. Now you can analyze all app execution and variables even offline and use any data queries, modify prints without execution and feed it too AI as extra context. I guess RAM would be a big obstacle to make it work since you would either have to capture snapshot at every program modification or some less snapshot but some diffs between what changed.

[0] https://rr-project.org/

[1] https://www.rerun.io/

Re: Don’t look down on print debugging

#36
post #30

I've used both print and proper debuggers plenty. I tend to lean on print debugging more these days. The thing about debuggers, in addition to often being a headache to set up, it usually seems tricky and time-consuming to get it to step to the lines you actually want to examine and skip the stuff you don't. And if you step past something but then later realize it was important, time to start over. It's often faster…

All that tells me is that you have never used a good debugger. There is no "setup" and stepping through lines is trivial.

Re: Don’t look down on print debugging

#37

While print-type debugging has a place, the reason there are a lot of articles dissuading the practice is the observed reality that people who lean on print debugging often have incomplete knowledge of the immense power of modern debugging tools. This isn't just an assumption I'm making: years of being in developer leadership roles, and then watching a couple of my own sons learning the practice, has shown me in hund…

I kinda want to push back against the blanket statement that there are articles pushing back on print debugging. That implies there’s well known mind share thinking about it? Is it real mind share? Is it bullshit? Print debugging is the literal pocket knife of debugging.

There are loads of articles discouraging print debugging, and it's a very real thing that people fight against (and for). Print style debugging is the first thing most programmers learn, and for some it absolutely becomes a bad habit.

And to be clear, print debugging and pervasive, configurable logging are very different things and the latter is hugely encouraged (even with logging levels), while the former is almost always suboptimal. Being able to have your client turn on "DEBUG" logging and send you the logs after some abnormal behaviour is supremely useful. Doing "prinftf("Here!")" in one's project is not, or at least not remotely as useful as better approaches.

Re: Don’t look down on print debugging

#38

Some of the trickiest bugs to hung down are those involving concurrency and non-deterministic timing. In these cases, stepping through a debugger is not at all what you want, since you may actually change the timing just by trying to observe. To see the nature of the race condition, just put some print statements in some strategic locations and then see the interleaving, out of order, duplicate invocations etc that a…

Even without a race condition, concurrency itself can make debuggers difficult to use. Debugging async code almost feels pointless.

Re: Don’t look down on print debugging

#39
post #23

It feels like the author is making the opposite point when they distinguish between logging and print debugging. Logging being the permanent bits of code, that either ship with the program or are disabled when the code is built for release. Print debugging are temporary bits of code that are manually added and removed as needed and is never intended to ship. If that is the distinction being made, then print debugging…

> print debugging is problematic since the developer has to be diligent about removing it once it is not longer needed.

Linters make this a non-issue, and most modern development environments support them.

https://eslint.org/docs/latest/rules/no-console

https://docs.astral.sh/ruff/rules/print/

In situations where for whatever reason it's infeasible to use a linter, a basic grep can surface prints in a codebase reliably enough.

Re: Don’t look down on print debugging

#40
post #27
post #16

Earlier quoted context omitted.

To be fair though: printing also will likely impact timing and can change concurrent behaviour as well. Still agree that print debugging is more useful in such situations (and I prefer it in general).

>printing also will likely impact timing and can change concurrent behaviour as well. I've had a bug like that and the intuitive way to handle it turned out to be entirely sufficient. The bug (deep in networking stack, linux kernel on embedded device) was timing sensitive enough that printk() introduced unsuitable shifts. Instead I appended single-character traces into pre-allocated ring buffer memory. The overhead w…

>I appended (...) traces into (...) memory. (...) An unrelated process would read (...) at opportune time and hand over to the developer.

I did something similar to debug concurrent treatments in Java, that allows to accumulate log statements in thread-local or instance-local collections and then publish them with possibly just a lazySet():

https://github.com/jeffhain/jolikit/blob/master/src/main/jav...

Post reply on HN