Search code examples
debuggingreleasestartup

Combatting debug code in release product


I work in a very small startup development shop (3 developers), and am often pulled away from what I am working on to fix a mission critical bug or implement an "absolutely critical" software feature - my bug list is re-prioritized on an almost daily basis and I seldom know what will be "important" a a few hours from now.

Because of this, I have found that I am becoming more and more wary of adding code that can potentially go unchecked by our QA department (read: person).

When I implement a new function, not knowing whether I'll be called away from it at any time, I sometimes try to write a return statement at the top just to make sure that the code never gets executed on a release build.

The problem with statements like:

public void NewFunction()
{
    return; // Put break point so that I can use the debugger to step to meat:

    meat:
    // ... More code
}

are that even in debug mode, Visual Studio is smart enough to know that meat: will never be executed, so you can't use the "set next statement" command to meat:. The same is true for wrapping code in compiler directives like #if !DEBUG.

Instead, I write things like:

public void NewFunction()
{
    if("a"[0]=='a')
        return; // put break point here

    meat:
    // ... More code
}

so that if this code accidentally slips into a release, no harm is done, but because it's not evaluated until run time, I can use the debugger to step to meat: with no problem.

I don't really like leaving things unfinished, but in crunch times we often don't have time to shelve change sets or do things properly. Access to unfinished features like the function outlines above via an API aren't a concern at the moment, so I don't see any immediate harm in leaving them in the software (but down the line, they can lead to several wtf moments during maintenance - as in "wtf is this function that doesn't do anything doing here?" because I won't remember what I was doing 6 months from now).

Considering that I am (sadly) doing stuff like this on a semi-regular basis, is there a standard practice for this issue? As a larger issue, is there some set of practices that help to combat debug code in software releases in general?


Solution

  • Assuming your code is in C#, you can use [Conditional] attribute to exclude certain method calls in Release configuration:

    [Conditional("DEBUG")]
    public void NewFunction (object something)
    {
        // do something
    }
    

    This is equivalent to wrapping method itself and all its calls into #if DEBUG / #endif clauses.

    Any calls to NewFunction will be excluded by compiler when DEBUG symbol is not defined. The simplest way to control it is by solution and project configurations in Visual Studio. In Debug configuration, DEBUG symbol is defined, as opposed to Relase configuraiton.

    Note that only void calls can be excluded because code doesn't depend on return values for these methods.

    However this is designed to be used for tracing, logging etc. I don't quite understand how you plan to leave some methods unfinished yet still use them in debug versions. What's the sense of calling them if they don't work, or if they do, why not include them in release?