| 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.) |