Hacker News new | ask | show | jobs
by carapace 1203 days ago
Seems as good a hook as any to hang this rant...

> a good debugger supports different kinds of breakpoints, offers rich data visualization capabilities, has a REPL for executing expressions, can show the dependencies between threads and control their execution, pick up changes in the source code and apply them without restarting the program, can step through the code backward and rewind the program state to any point in history, and even record the entire program execution and visualize control flow and data flow history.

TL;DR: That's fantastic! But if you need any of it you're already "doing it wrong".

Context: I've recently been using a compiler for a C-like language that targets a simple 64-bit VM, the point being there's no debugger for the stack (the VM is written in Rust; I could put a debugger on that and just deal with the extra level of abstraction using e.g. features like those described above.)

So how do you cope?

Design simple and robust systems that can be understood in action easily via printf/log. Use tried-and-true off-the-shelf components (including algorithms and datastructures.) Write in small increments, compile often, never proceed without complete confidence in your understanding of the system. When the inevitable bugs appear, and they can't be discovered through just thought or a rereading of the code, then you bisect: often literally (LoC) but also conceptually. Solve the puzzle and eliminate the places where puzzles can hide in the first place.

I quite literally see how a having a debugger would lead to worse code. (Even if you don't use it.) This isn't news btw:

> Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it?

-- Brian Kernighan, 1974

(The feeling is different: like instead of a wild adventure, programming this way feels like gardening in an orderly and well-kept garden.)

3 comments

In the real world, programmers are brought into projects with literally millions of lines of code that have been developed over years or decades by tens or hundreds of programmers. They are under intense time pressure to fix bugs that they likely didn’t create. This is normal and debuggers are invaluable. No offence, but what you’re describing is a lovely ideal that only exists if you work mostly alone or on small things.
I hear you: people have been "doing it wrong" voluminously and for a long time. Ergo, fancy debuggers come in handy.

> This is normal...

That's the part that I have a problem with. We have leavened our entire complex civilization with software, it's important to get it right.

That's all good, but if the problem itself operates with more data than a human can reasonably operate with, this no longer applies.

I do 3D meshes programming. The amount of vertices, planes and other geometrical entities that I need to operate with in my algorithms is too big for me to do printf debugging. I can't just look on a long list of 3D vertex coordinates and visualize the mesh they make in my head. Moreover, I had to come with my own 3D visualization tool, once I got fed up with pen and paper for converting 3D coordinates to actual meshes, or using Blender for that. For me, a debugger (and debugging tools in general) is irreplaceable. I'm not saying my field is the most complex one, because it clearly isn't - but in that field, I can't think of any other way I could do what I do.

But it sounds like you had to come up with your own tools because a debugger wasn't enough?

That's my biggest criticism of debuggers having used both approaches: you forget that sometimes you need new tools. Whereas with prints you're constantly building new instrumentation for yourself.

https://merveilles.town/@akkartik/106138280776488247

I'm not sure I'm following. A visual debugger ticks a lot of boxes for my needs. Not all - some of them I had to tick myself, but I don't think that trying to reinvent the value that's already there in a debugger, would be particularly productive for me.

As for "forgetting", I don't think I forgot, because, well, I did make a new tool.

The main thing that I wanted to address in the parent comment is that needing tools to debug your code somehow means that the code is a mess - no, sometimes it doesn't.

> The main thing that I wanted to address in the parent comment is that needing tools to debug your code somehow means that the code is a mess - no, sometimes it doesn't.

Ah. I totally agree with that. Or at least, it's the sort of mess I don't know how to avoid yet.

Is your argument "Don't use debuggers because it will prevent you from writing a debugger?"
I'm not arguing "don't use debuggers."

I'm arguing, "don't just use debuggers."

I elaborate more on this argument in the first 2 minutes of this 4-minute video: https://handmade.network/snippet/1561

That makes sense. I'm also with you in that programmers forget that their development tools are also programs and they can modify and/or make more of them.
Whereas with prints you're constantly building new instrumentation for yourself.

What does this mean? Formatting text differently is still text, which the parent post was just explaining doesn't cut it.

I'm constantly finding new places in my program to add prints to. This isn't just copy changes. (Though that has also had a huge impact occasionally in understanding something. Imagine emitting 2 variables and then focusing on 1 of them. A pattern can pop out of a screenful of iterations of a loop when things line up just right.)
There are debuggers that will let you halt your program, go back in time, and then print out each place where a specific variable changes. If that's "interacting with your program through a pane of glass" then shrug.
I'm very happy to hear it! Can you point me at a few of them?
FWIW it sounds to me like you're using what effectively amounts to fancy 3D printf, eh? In other words logging/printf help "visualize" non-geometrical entities.
Not _only_ that. It was an example of how tools help me deal with inherent complexity that cannot be dealt with by "just write better code".

I do use debugger. During big fixing, I need answers to various questions, such as: on what halfspace does a vertex lie? Is this point inside that polygon? What is the distance between two points? - and so on. If I didn't have a debugger, I'd have to stop the program, find the distinguishing features of the entities I'm interested in again - and this is often the hardest part, since the same code can be called thousands of times with different data - put printfs, rebuild, relaunch and prepare for another cycle. With a debugger, I just put these questions into LLDB queries - and I get answers. It is so much faster.

Would it be possible for me to do my job without all that, using debug prints only? Theoretically, yes. Would it be practical? Absolutely not.

Meaning no disrespect, and I swear I'm not just being contrary for kicks, but it now sounds (to me) like you want to be using Common Lisp? It sounds like you're fighting your tools with your tools.
Why do you think so? I think I'm pretty comfortable with what I'm doing now, but maybe I don't know something.
'Design simple and robust systems...' and 'never proceed without confidence in your understanding...'. When I was a freshman, I would have said that. Then I entered the professional world. Complex problems are solved using complex solutions. Complete understanding is non-existing. Robustness is a relative term.
> never proceed without [total] confidence in your understanding

The fellow I learned that from was apenwarr, FWIW.