Because Rx gave me a hammer

 

I am a little infatuated with the reactive extensions at the moment, it’s a new tool in my arsenal of trying to be cutting edge. As developers, when we do get given new toys we can get a little desperate to want to use them everywhere.

I initially started with some prototype code which needed improvement before committing to source control. The nature of the code is waiting for the debugger to attach before continuing execution. You might ask why I would want to do something this bizarre, so I’ll mention its for a developer tool so waiting on a debugger is in its domain. It also needs to be programmatic, doing Debugger.Attach or Debugger.Break won’t suffice here.

The prototype code we have is:

while (!Debugger.IsAttached)
{
    Thread.Sleep(200);
}

After sending the code round a mailing list, asking for a better way to do this, the best we could come up with is adding a timeout. So instead of adding a timeout I figured I’d see if reactive could help me improve this code.

var blockUntilTimeout = new AutoResetEvent(false);
bool isAttached = false;

var waitingForDebugger = Observable.Interval(TimeSpan.FromMilliseconds(200))
                    .SkipWhile(l => l < 25 && !Debugger.IsAttached)
                    .Take(1)
                    .Select(l => Debugger.IsAttached)
                    .Finally(() => blockUntilTimeout.Set());

waitingForDebugger.Subscribe(debuggerResult => isAttached = debuggerResult);

blockUntilTimeout.WaitOne();

if (!isAttached)
{
    output.WriteLine("fatal error: timeout while waiting for debugger to attach");
    return 2;
}

This code took me quite a while to write, I learned a few new Rx extensions doing this, which was fantastic. It was also quite a lot of fun to write, Rx’s flexibility is quite impressive, however upon sending this out to the mailing list I was greeted with:

“Skip the RX, only muddles the water and all you want is Thread.Sleep() anyway. Readability suffers this way.”

I have to admit, at the time I was quite disappointed, I wasn’t sure if it was peoples lack of familiarity with Rx that was causing the backlash. But never the less, if its a shared codebase, it should be loved by all, so I put my pride aside and rewrote it more conventionally:

int countdown = 5000;
int waitTime = 200;

while (!Debugger.IsAttached && countdown >= 0)
{
    Thread.Sleep(waitTime);
    countdown -= waitTime;
}

if (!Debugger.IsAttached)
{
    output.WriteLine("fatal error: timeout while waiting for debugger to attach");
    return 2;
}

 

Not only is it less lines of code, it is much easier to read in my opinion, my new hammer got in the way of picking up the screwdriver which was better at driving in screws. Although I do hate the Thread.Sleep(), and would love there to be a better construct in it’s place, its a good compromise for readability.

In retrospect, trying it out in Rx was a valuable learning process, but getting feedback is imperative to writing good code. While the Rx code has been binned, the experience in when not to use it I can keep forever, further refining my programmer toolbox.

September 12 2010
blog comments powered by Disqus