3 ms·
"In fact, how people can debug large existing codebases without a debugger is beyond me." I currently work on a product with a 15-20 Mloc codebase (mostly C).
by NLips 10y ago
"In fact, how people can debug large existing codebases without a debugger is beyond me."
I currently work on a product with a 15-20 Mloc codebase (mostly C). The development facets which give the closest parallel to a line-by-line debugger are:
Components in the system communicate with each other by sending signals through the framework. All such signals are traceable in all builds, and can easily be decoded. These narrow down which components is doing something wrong, and what exactly it's black-box behaviour is (i.e. when I see bug B, it's because component C is giving output O after receiving input I).
Lots of trace. All branches are traced in debug builds, unless there's a serious perf reason not to. Many interesting variables are traced too.
Extensive UT and FV, using powerful (rubbish in other ways) frameworks. Any real-world bug should be reproducible in automated tests, which you can build and run with debug-level trace.
It's not always fast, but with these you can always find the problem line / section with typical code bugs. Obviously some types of bug (e.g. perf) often don't come down to 'a line of code' or 'a bad interaction', so aren't necessarily resolved this way, but that's the same with line-by-line debuggers, in my experience.
- jononor 10y agoWhat do you use for tracing?
- NLips 10y agoNothing special - just macros (provided by the framework that the components run in), which allow the programmer to filter based on filename and/or log level, and print the filename, function and text to file. There's so much trace that you can't use it in production mode, even if you have a test system which isn't handling any load, so it's purely a debug tool.
- randomthoughtss 10y agoTracing is great but often gives you a low signal-to-noise ratio and for new code, is often missing for the bug you're trying to investigate. A debugger lets you add tracing as the system is executing, which in my experience is extremely productive, especially in C++ codebases where adding some logging can result in 10 minutes to rebuild and deploy. And I don't know what I would do without data breakpoints that give you the callstack and threading info when an address is written to.
- NLips 10y agoIn case it wasn't clear: I don't mean to suggest that no-debugger is superior to debugger. WRT the benefits of interactive debuggers, I definitely see the advantages of faster debug cycles. Luckily, it's not often that I need to worry about the 'often missing for the bug' / 'callstack and threading info when an address is written to' style of bug by virtue of working in codebases with strong coding standards and diligent code review. Most of the bugs I need to fix are 'developer didn't think of scenario S when writing feature F' or 'developer has forgotten edge-case E', rather than 'code is broken e.g. address re-use'. And as I said in a cousin comment, I can't deploy a system with trace. That 10 minutes is just spent building :-p