Friday, July 17, 2009

Fun with Stopwatch

Just for fun…

   1: public class MinimumExecuteTimer
   2:     : IDisposable
   3: {
   4:     private Stopwatch Stopwatch { get; set; }
   5:     private TimeSpan MinimumExecutionTime { get; set; }
   6:  
   7:     public MinimumExecuteTimer(TimeSpan minimumExecuteTime)
   8:     {
   9:         MinimumExecutionTime = minimumExecuteTime;
  10:         Stopwatch = new Stopwatch();
  11:         Stopwatch.Start();
  12:     }
  13:  
  14:     #region IDisposable Members
  15:  
  16:     public void Dispose()
  17:     {
  18:         Stopwatch.Stop();
  19:         TimeSpan sleepTime = MinimumExecutionTime.Subtract(Stopwatch.Elapsed);
  20:  
  21:         if (sleepTime.TotalMilliseconds > 0)
  22:         {
  23:             Thread.Sleep(sleepTime);
  24:         }
  25:     }
  26:  
  27:     #endregion
  28: }

So, now I can ensure an operation will always take at least XX time to execute.

   1: public void DoWork()
   2: {
   3:     using(new MinimumExecuteTimer(TimeSpan.FromSeconds(10)))
   4:     {
   5:         // do something, block will hang 
   6:         // for the time remaining
   7:     }
   8: }

“Why would you do this in production?” you ask…

Good question, none that I can think of right now.  I wrote the class to test what a Login form would look like while validating to a service call that took extremely long to execute.

Thursday, July 9, 2009

Indirect Implementation - Interfaces

Indirect implementation is something I don’t see done enough.

I think the biggest reason is “Why would I do that?”

Developers (myself included) that understand interfaces come up with cool reasons like: “So I can swap out the implementation with something else later”.  Then we go through and instantiate the class that implements the interface everywhere.  Making it catastrophic to remove the implementation later.  The developer that ignored the interfaces is probably tasked to help you undo your “extensibility”, further convincing her to not use interfaces.

My most recent task is to make my application “.NET 2.0 compatible”.  What does this mean?  Means if a feature uses part of a .NET framework that was implemented after .NET 2.0 I should turn off the feature and display a message to the user.

Now, the trick is how do I know there is a problem?

If I make my application depend on System.ServiceModel, and that assembly isn’t present on the users system my app will fail to run entirely.  Instead I create a separate project that holds a reference to my application.

So instead of:

MyApplication—references—>MyLibrary

I do:

MyLibrary—references—>MyApplication

This is odd initially, and in visual studio can be a pain in the ass for build ordering.  Typically I’ll setup like this:

MyApplication—references -–>MyLibrary<—referenced by—MyImplementation

Now in visual studio, I make MyImplementation a “Project Dependency” to MyApplication. (Note the white checkbox, references are the grey checkboxes that are only removed by removing the project reference)

image

Plus add a Post-Build script to copy the build output from MyImplementation to the bin directory of MyApplication.

image

So, neither MyApplication nor MyLibrary are explicitly dependent on MyImplementation.  If that assembly fails to load due to missing references I can have a recovery plan.

That takes care of the project setup.  Now for how to implement this in code.  This is where the factory pattern comes into play.

   1: public static class Factory
   2: {
   3:     public static IImplementation CreateImplementation()
   4:     {
   5:         Type t = Type.GetType("CoderJoe.Samples.IndirectImplementation.ActualImplementation, CoderJoe.Samples.IndirectImplementation.MyImplementation");
   6:         if (t != null)
   7:             return (IImplementation)Activator.CreateInstance(t);
   8:         else
   9:             return new FallbackImplementation();
  10:     }
  11: }

You can see in the factory code, first I try to get the type from inside the MyImplementation assembly.  If that fails (returns null), then I just instantiate a default implementation.

Now, lets say the MyImplementation project referenced a 3rd party assembly that may or may not be on the users system.  No worries, our FallbackImplementation can help us recover gracefully when our MyImplementation assembly fails to load due to missing dependencies.

Checkout coderjoe.codeplex.com for a sample solution showing this code in action.