"That's ridiculous, I would never do that" you think.  But there's a certain class of mistakes that cause this. And smart people make these mistakes.

1) If your app behaves differently under a debugger, it may behave incorrectly when not under a debugger.

The mere presence of a debuggers should not change a program's behavior.   I say that a lot, but some people may not appreciate it.

If you have debug-only hooks, how do you know somebody isn't using those hooks for core application functionality?

Or in more academic terms: if running under a debugger changes program behavior, then it's possible that not running under a debugger could change behavior in a way that breaks things.

The most common example is exception behavior. Don't write this:

        static void Foo(Thing o) 
        {
            if (Debugger.IsAttached) { // BAD!!!
                if (o == null) {
                    throw MyExeption("Something bad happened");
                }
            }
            // Now assumes o is not null
            o.DoSomething();
        }

Not under a debugger, when o is null, Foo() will throw a null refernence. But when under the debugger, Foo() will throw a MyException. That could be very significant for any upstack catch block and significantly change behavior .

Write this instead:

        static void Foo(Thing o) // GOOD!
        {
            Debug.Assert(o != null)
            // Now assumes o is not null
            o.DoSomething();
        }

 

2) Developers spend a lot more time under the debugger than customers do.

If you do most development under the IDE (such as with Edit-and-Continue), then that may be where you must aggressively inspect state to make sure everything is behaving exactly as expected.

Sure, you may write unit tests that give code-coverage. But will those unit tests check every field of the objects like the locals window? Will they ensure the statements are executed in the same order you expected like stepping through your code does?

Now the tests will certainly stress other things that you don't normally do under the IDE (like stress cases), but my point is that there is a significant class of things that you check most aggressively under the IDE.

And if running under a debuggers changes behavior, then this aggressive testing is all under the "running under a Debugger" codepath and not the "production" codepath. So you'd be missing some of your most aggressive testing under your most common codepath.

And how did your developers miss this case? Because they didn't run the same codepaths the customers did.

 

Related reading: