I, for one, only add debug code (such as print statements) when I'm trying to locate a bug. And once I've found it, I remove the debug code (and add a test case which specifically tests for that bug). I feel that it's cluttering the real code and therefore has no place there unless I'm debugging.

How do you do it? Do you leave the debug code in place, or remove it when obsolete (which may be difficult to judge when that is)?

8 Answers
8

Debug print statements should be taken out; however, if you're needing to add them to debug a production problem then it may be worth considering if you have enough information being put into your logging framework. Information about parameters, error conditions and so on may well be useful later on when the next bug appears. Using a good logging framework that can be have debug or tracing log messages turned on dynamically can be very useful in the wild.

+1 Primarily for mentioning having a sensible debugging framework in place. If this is in place initially, and there are various debug levels, then production code can hopefully run without calling expensive debug routines, and development code can run with whatever level of scrutiny is required, hopefully logged in whatever way is desired.
– OrblingJan 3 '11 at 0:56

1

Agree with Orbling. And plus, for debug code other than solely information display which had performance impact or other reason not suitable for production. (e.g. an Assert on result of function e.g. checking the result of a sort), you may consider two mode of build target. debug mode and release mode.
– Zekta ChanJan 3 '11 at 1:13

+1 for conditional compilation, but comment blocks will work in languages that don't support them. You should never leave it compiled into a prod release, but sometimes it is excessively inefficient to keep deleting it entirely every time you want to drop a release build.
– BillJan 3 '11 at 15:31

1

I've worked in environments where C/C++ code was always compiled with debug options in case production code needed to be debugged or a coredump examined. Sometimes this always ready to debug mandate required that debug statements be left in so they could be turned on with a flag without recompiling the code. Java always allows debugging if your JVM options are set for it so relatively less prep work is required to debug things later.
– Michael ShopsinSep 28 '16 at 19:02

It depends on what the code is doing. Some code that is used for debugging can be left as it is, and some should be removed.

Code that verifies the sanity of the parameters in a method isn't always useful once the code is working properly, but it's often kept to make sure that the code is continuing to work properly.

Sometimes you write code differently to make it easier to debug the code, for example calculating a value and putting it into a local variable, and then use the variable in next line, which makes it easy to check the result of the calculation when single stepping through the code. You could rewrite the code to use the calculated value directly, but the cost of using the local variable is so small (if any at all) that there is little reason to rewrite the code. Also, there is a point in leaving the code unchanged once you have tested it, there is always a small risk that you introduce a bug when changing it.

Code that you add just to track down a specific bug can often be removed after you have found the bug.

Once upon a time I used to use a lot of debugging code. I was almost entirely targeting Windows, so there was lots of this debug string output function that I don't remember how to spell any more, so I could capture the trace with a particular program.

Some debug code stayed in place, particular stuff that was intended to give the nesting of calls. However, even though the debug string thing mostly wouldn't be visible on a production system, it was still all done under conditional compilation.

The reality is, though, that all that debug code was a lot of effort for something that is ideally handled a different way - using, of course, a debugger. At the time, I wasn't that impressed with the Borland C++ debugger. The tools were there, but they too often gave misleading results, and using the non-IDE debugger (often necessary) meant memorizing shortcut keys, which meant a distraction from the job at hand.

The only debugging experience I've found that's worse is command-line GDB.

Being an expert with the tools you use every day is, of course, important - but debugging really shouldn't be something you do every day. If you use the debugger so often you're OK with learning dozens of commands and/or keyboard shortcuts, that seems a bit red flag-ish to me.

By the time I was working in Visual Studio 7, though, it was clear that debugging could be very practical and effective. If you can do your debugging in Visual Studio (express editions included), debugging is a breeze. No doubt if you can find the right GUI/IDE front end, GDB is easy and effective too, though I've not yet done that search.

There's also something to be said for unit testing, with coverage analysis using gcov. The more confident that you are in the behaviour of your libraries, the less deep your debugging needs to be - and the less often you need the debugger in the first place. And writing unit tests is quite reasonably something you should be doing most days.

Unexpectedly important tool = cmake, a build tool that allows me to easily switch between building for GCC and for VC++, among other things. So I can do my unit testing and gcov-based coverage using GCC, but easily switch to VC++ to use the debugger.

A debugger can pretty useless if not dangerous in multi-threaded applications, but I like your red flag-ish comment.
– PemdasJan 3 '11 at 1:32

@Pemdas - I haven't had a serious issue along those lines yet, though multi-threading is obviously not debugger friendly. Even so, I think the right tools are likely a better solution than debug code in principle. A static analysis tool that can spot race conditions, deadlocks, conditions when two threads can fight over the same memory/resource at the same time and so on would be nice. I have no idea what is available along those lines, though I do know that there are some clever tools out there. klee, for example - I don't understand it, but the basic description sounds very impressive.
– Steve314Jan 3 '11 at 1:36

"I think the right tools are likely a better solution than debug code in principle" That's a dangerous statement ;) . Having tools that preform some of the analysis might be nice, but I worry that developers especially new one's would start to become too dependent on the tools, like someone that needs to use a calculator to figure out what 15% of 100 is.
– PemdasJan 3 '11 at 1:47

Getting too dependent on tools I haven't even researched yet seems unlikely. On your calculator example, yes, but I'll still use OpenOffice Calc rather than write my own simple spreadsheet. There's a time for debug code (even with a debugger - e.g. your own bizarre-condition-creating case), but if it goes beyond a certain point, existing tools win. And when it comes to subtracting 15% from 115, I'll use that calculator too - what many people would give as the obvious answer (100) is wrong. In multithreading, obviously right answers are infamous for sometimes turning out to be wrong.
– Steve314Jan 3 '11 at 2:02

ChrisF and Alaric both have valid points; +1 for them. I can identify at least 5 different types of debug code that I use.

Using logs to dump system state at a specific point in time.

void function(...)
{
...dump everything i know about.
}

Using logs for execution check points.

void function(...)
{
...got here 1
...got here 2
}

Code that actually forces a certain condition to be true, but breaks normal behavior. Example:

Suppose you have some logs regarding an error, but you can't reproduce the problem. You might try writing code that force certain variables to have certain values that match the information in the log.

Verification logging - I would classify this as a verbose logging that can be used to validate the software's correctness that should not be included in production, like validating the individual steps of an algorithm for example.

Operation logging - refer to Alaric's post. That is pretty much what I mean by "operation logging".

1, 2 and 3 should be taking out completely. Something like 4 I would probably conditionally compile out of the code. For 5, Alaric had a great point about being able to dynamically turn the logs off. That may address ChrisF's point in his second bullet for most cases.

This is a good summary. However, it would be better if you could format it properly by replacing 1) … with 1. … (so that the Markdown formatting picks it up as a lists) and indenting the example code by 8 spaces (again, so that Markdown picks it up as an example code within a list).
– Konrad RudolphJan 3 '11 at 10:09

If the bug is from the unit testing or from internal, the debug code could be removed altogether. But if the bug is from the production, the debug code better be there inside the compile tags. Putting it inside compile tags will help the other developers to understand that this code is only for debug purpose.