Hacker News new | ask | show | jobs
by wodny 1884 days ago
Print debugging is not that different from setting logging level to DEBUG and those logging calls should already be there in code and give meaningful insight so I don't get printing being often ridiculed.

For over ten years of commercial work I used a debugger only a couple of times and in most cases it was against someone else's code, usually when things were completely broken and I needed to get backtraces from multiple deadlocked threads or lacked debugging symbols and things like radare were also required. There were also times when I manually called a syscall using gdb.

My opinion is that if you can't reason about the code helping yourself with just a couple of additional messages the code is probably broken/too complicated to begin with and requires serious refactoring. I've never understood people stepping through a program hoping to find some mysterious creature somewhere along a huge stack of calls. In my career I have often seen people always debugging an application as a whole instead of separated modules. Dividing a problem is the key. The same key that allows me to still program using vim without autocompletion, keep APIs sane and coherent, and avoid dead code.

One really useful exception is when dealing with electronics. My friends programming hardware use debuggers all the time and in this case it actually makes perfect sense because there is no way to print anything and things like hardware interrupts come into play.

7 comments

> My opinion is that if you can't reason about the code helping yourself with just a couple of additional messages the code is probably broken/too complicated to begin with and requires serious refactoring. I've never understood people stepping through a program hoping to find some mysterious creature somewhere along a huge stack of calls. In my career I have often seen people always debugging an application as a whole instead of separated modules. Dividing a problem is the key. The same key that allows me to still program using vim without autocompletion, keep APIs sane and coherent, and avoid dead code.

The big thing here is that you seem to only work with your own code, where you can arbitrary refactor it and keep the entire thing in your head, as well as quickly find which module does what. But when working with a large foreign project, none of this works. You have to start working at the scope of the entire program, because you have no idea of the internal structure yet. Of course, people who use debuggers divide the code up as they go, but the point here is that they place a few choice breakpoints at central points in the application logic, inspect the stacktraces when one gets hit, and use them to further dig in to the part of the code they need to look at.

> The big thing here is that you seem to only work with your own code, where you can arbitrary refactor it and keep the entire thing in your head, as well as quickly find which module does what.

Not at all. Due to lack of documentation I look at code of foreign libraries and applications all the time to check what really happens inside and what are the guaranties. The latter being often the case when it comes to concurrency problems.

> I used a debugger only a couple of times and in most cases it was against someone else's code

The vast majority of code I investigate is "someone else's" code. Most of the cases, it's a historical accumulation by multiple authors. If you generally only work in your own code, that's quite a different experience, and debugging is generally easier (because you were there when it was written).

That is not the point I was trying to make here. I was talking about extreme cases of faulty code which luckily are not that common. I meant that as long as you couple with sane libraries and adhere to standards in your own team extreme measures such as a debugger are not necessary.
Actually, using the UART interface to send text breadcrumbs out the port is a standard technique in embedded, too ...

The article hits the point of print debugging, you get to see the backward in time.

By the time you hit "the problem", the pointer is NULL, the memory is trashed, the system is deadlocked, etc. You need to reason about how you got there.

There is a reason why the next step up from basic debugging embedded is "streaming trace"--effectively print on steroids.

Memory watches let you see exactly when the pointer becomes null, and the call stack. In that particular case, the debugger is much faster and easier. Not saying print debugging is useless, but I do find many of the arguments in these comments seem to think the primary feature of a debugger is to step through code
I pretty much all of these. One thing I wanted to add is decorators. There is code you might have easy access to edit to add print statements. I don’t love the spring boot docs and reading the code isn’t as useful as stepping through your specific autowired code tree. There’s definitely use cases but 95% of the time prints will get you there. Imo you should learn it because it will save you a bunch of time and headache when you need it.
When I start to use a new server framework, I like to step thru the main loop, just to see how it works with system calls/listens/accepts/reads and how it dispatches up the stack. But for debugging, I like to a) make it reproducible, b) read the code, c) add logging to help with any deductions that b yields. (Sometimes will just go to b if it's a simple bug).
> I don't get printing being often ridiculed

I just told one of my co-workers last week that I was going to print-debug an issue. He paused for a moment before saying, "Uh, I can just debug this for you if you like."

So yeah, there's definitely some kind of stigma against print-debugging.

You’ve only used a debugger a couple of times in 10 years? Yikes.
Why "yikes"? Note that doesn't mean I don't know how to use eg. gdb outside or inside IDE. My debugging record proves my methods are quite efficient but there's something even more important - there are ways to systematically avoid the need to use a debugger by keeping projects' sanity level high.