Live data from Hacker News

The unreasonable effectiveness of print debugging

buttondown.email

181–190 of 366 posts

Re: The unreasonable effectiveness of print debugging

#181

Earlier quoted context omitted.

As a counter-point, I think there’s an argument that folks don’t spend enough time in the debugger. But there’s a lot of value there and in fact one could use a debugger environment to unit test as even native debuggers have scripting environments. Personally, I think folks should master the debugger _first_ and during all steps learning a programming language. But similar to test-driven-development it’s a different…

The problem is that it's not just a matter of "learning the debugger for Java." In practice there are many different projects that configure debugging many different ways, and it doesn't matter that you know which keys to press in IntelliJ if it will take you an hour to figure out how to attach it to the project. This speaks to OP's point, where it's hard to use a real debugger to casually investigate random projects…

> The problem is that it's not just a matter of "learning the debugger for Java."

In the Java case, for stanalone projects (i.e. not something deployed on a server) an if it is your own project and you don't do anything unreasonable it is mostly just set a breakpoint and hit "run with debugging".

Probably the least painful debugging experience I know.

Doing it for Tomcat/Tomee was slightly more advanced IMO but still utterly trivial compared to wrangling css or js ;-)

There are reasons why we "old folks" like Java so much despite its verboseness.

Re: The unreasonable effectiveness of print debugging

#182

Speed of iteration beats quality of iteration. You can step through the program, reason about what's going on, tracking values as they change. But if you missed the moment, you have start again from the beginning (time traveling debuggers being rare). Or maybe you're looking at the wrong part entirely at this stage, and just wasting time. With print debugging you write a bit of code to test a hypothesis. Then you run…

> Speed of iteration beats quality of iteration.

I totally agree but for me that means using a debugger and make full use of its features.

> But if you missed the moment, you have start again from the beginning

As already mentioned in another comment, "drop frame" is a standard Java debugger feature. You can easily go back to the start of any method and go though everything again (side effects of already executed code can give some trouble though).

> Or maybe you're looking at the wrong part entirely at this stage, and just wasting time.

You have the same issue when printing in the wrong parts. Of course you can plaster the code with lots of print statements to see which gets executed. But you can do the same with breakpoints and see where the debugger stops.

> With print debugging you write a bit of code to test a hypothesis. Then you run it, and you keep running it, and especially if it's an UI program you play with the UI and see how the values change during that run.

I really like conditional breakpoints for this. You write a condition for a state that interests you. Then play around in the UI until it stops for that condition and you can easily inspect the complete state at that moment. This is quite useful for debugging methods that are executed very often. Trigger breakpoint (which disable all other breakpoints until they are triggered) are also useful in those situations without requiring any code.

> Once you do know where the problem is, and if it's not apparent what the problem is (most problems are pretty trivial once located), that's IMO the time to break out the debugger and slowly step through it. But the vast majority of problems are faster to solve through rapid iterative exploration with prints in my experience [...]

I can just say that I usually locate issued way faster with a debugger. "rapid iterative exploration" could also kind of describe my workflow using breakpoints. Maybe it actually less about the tool and more about your approach for locating issues in the code.

Re: The unreasonable effectiveness of print debugging

#183
post #177

Earlier quoted context omitted.

If you've chased heap corruption printf doesn't really help you much but a data breakpoint is a godsend. Same thing with watch windows, memory views and the like. There are classes of problems that do well with printf but calling them "no-code" is vastly underselling them.

I’m not sure when no-code became a pejorative, but that wasn’t my intent! Only that most of these tools, unlike print, are special-purpose, exceptional for that purpose, and often even useful in other circumstances. A data breakpoint is a great example of something useful that print doesn’t do well.

You seemed to be drawing a parallel between no-code -> "not as powerful", in my experience they're different tools for different use cases.

I also don't think they're nearly as no-code as you call out. VS' watch window has very few limitations compared to printf back when I was working on win32 things.

Also important to consider iteration time. I once worked on a system where adding a printf was a 20 minute process due to the need to heavily optimize for a memory constrained platform(scripting fit in 400kb block with the asset bake step).

Re: The unreasonable effectiveness of print debugging

#184
post #91

Earlier quoted context omitted.

Debugging is impossibly difficult to teach. It's much closer to "how to solve an escape room" than it is to "how to build X". Debugging requires deep understanding what you are doing and your system. It's different every time. And while there's a general algorithm you can follow: 1. Guess what's wrong 2. Ask "How would I prove that's wrong?" 3. Try it 4. If bug found, fix, if not go back to 1 How would you teach that…

I think this is the standard algorithm and it's absolutely terrible. People poke at things, which ends up giving a linear search across a possibly huge system. Even if the "guess" is intelligent, it's not like you can trust it. If you actually fully understood the system, you would know what's wrong and you wouldn't be debugging. Do a bisect instead. The complexity is O(log n). It's probably slower than if you guess…

You're basically describing the scientific method. Particularly the practical application of Occam's Razor: Starting from simple theories, and working your way up towards more complex ones until the theory is just complex enough to describe the system behavior you're trying to understand.

Re: The unreasonable effectiveness of print debugging

#185
post #152

Earlier quoted context omitted.

Print debugging not (really) working is haskell is... Non-idea, and a bad pairing for bad real debugging. But test cases are usually easier to figure out. Presumably there's a balance discovered by people in big projects but it never seemed as good as normal approaches to me.

Haskell debugging by testing is great for small functions where you can use quickcheck. But larger tests for the more complicated stuff don't work in quickcheck and there isn't much else that one can easily do.

I haven't actually used quickcheck in Haskell, but I've used it for very complicated tests in other languages including Racket, TypeScript, Rust, and Java. The nicest thing about quickcheck is that it lets you easily create test data without imposing too many constraints on it. Regular fuzzing or randomized testing is almost as good, but the narrowing done by quickcheck is sometimes nice for understanding test failures.

Re: The unreasonable effectiveness of print debugging

#186
post #152

Earlier quoted context omitted.

Print debugging not (really) working is haskell is... Non-idea, and a bad pairing for bad real debugging. But test cases are usually easier to figure out. Presumably there's a balance discovered by people in big projects but it never seemed as good as normal approaches to me.

Haskell debugging by testing is great for small functions where you can use quickcheck. But larger tests for the more complicated stuff don't work in quickcheck and there isn't much else that one can easily do.

Not sure what you mean, there's e.g. Tasty for non-QC testing. It can do all sorts of variations of test, e.g. traditional unit tests, "golden" tests, etc.

Re: The unreasonable effectiveness of print debugging

#187

Another aspect, where printf debugging can be better than debuggers are use-cases where timing is relevant. Some bugs don't occur when break points stop the program at certain points in time. For completeness is should be added, that there are also cases where the printf can change the performance and make it impossible to find a bug. I think the two methods are complementary and should be use in combination. However…

If you have a timing related issue fixed by a debugger it's probably going to be fixed by printing/logging too.

Not at all. Stepping through a function with a debugger usually takes on the order of seconds and minutes. Printing some stuff in the function usually takes on the order of microseconds or milliseconds. That's a difference of at least three, possibly eight or nine orders of magnitude. It's very easy to imagine a timing-related issue that's affected by a delay of X seconds, but not a delay of X microseconds (RPC calls are typically on the order of milliseconds, for instance).

Re: The unreasonable effectiveness of print debugging

#188

Modern debuggers allow you to execute log statements on breakpoints. Much better than modifying your program to output something.

I used this a lot! Combined with scripting support, you can make the experience even more interactive.

Used gdb scripts in the past to make debug sessions repeatable. Stuck beyond the point your interested in? No problem, just restart the session with your gdb script and your right back on track! You can also add custom functions to output your state in a more meaningful way or to mock some state. In longer debugging sessions, a good debugger can be a life safer!

Still, for shorter sessions, reading logs and adding occasional prints are hard to beat.

Re: The unreasonable effectiveness of print debugging

#189
post #177

Earlier quoted context omitted.

I’m not sure when no-code became a pejorative, but that wasn’t my intent! Only that most of these tools, unlike print, are special-purpose, exceptional for that purpose, and often even useful in other circumstances. A data breakpoint is a great example of something useful that print doesn’t do well.

You seemed to be drawing a parallel between no-code -> "not as powerful", in my experience they're different tools for different use cases. I also don't think they're nearly as no-code as you call out. VS' watch window has very few limitations compared to printf back when I was working on win32 things. Also important to consider iteration time. I once worked on a system where adding a printf was a 20 minute process d…

> in my experience they're different tools for different use cases

Exactly!

Debuggers are very useful tools, and typically not as general-purpose as print. I don’t view “not as powerful” as a meaningful distinction, because it requires that you ask “powerful at what?” ---

VS’ watch window is great but (I assume) doesn’t work across distributed systems, etc. — as a general technique, print is universal in the sense that there are very few problems that can’t be diagnosed by modifying your code and printing some (possibly a manipulation!) of the hidden state. This is going to be harder than using a special-purpose tool designed for exactly your problem.

In the same way, “no-code” tools are typically better and/or easier than writing code to solve the same problem, but special-purpose.

Re: The unreasonable effectiveness of print debugging

#190

Personally, I think my biggest reason for using print debugging is.. it works. In C++ I often find the debugger doesn't find symbols on projects built with configure/Make. If I have a Java Gradle project I have no idea how to get it into a debugger. Python debuggers always seem fragile. Rust requires I install and use a "rust-gdb" script -- except on my current machine that doesn't work and I don't know why. I'm sure…

>> If I have a Java Gradle project I have no idea how to get it into a debugger You download Intellij IDEA, run it, choose File->Open and select the build.gradle file, right click the main class and there's a Debug option.

[deleted]
Post reply on HN