Tuesday, November 22, 2005

Failing Tests Meaningfully

Scott Bellware does a wonderful job of describing what it means to write unit tests that fail meaningfully. I recommend reading this at least as many times as it takes to shine the Scion.

Friday, November 11, 2005

Pattern for rethrowing exceptions caused during singleton initialization

If you are doing provider or other similar constructs that have late-constructed singleton behavior, you need to be sure that anyone using the singleton will not proceed with an erroneously constructed object. But how do you let them know something went wrong originally? Simply rethrow the original exception again! I found this pattern in the System.Web.Profile.ProviderBase class thanks to Reflector

public class Default : Singleton
{
    public Default()
    {
        // anything else you really want to happen in the instance constructor...
    }
}

public class Singleton
{
    private static bool s_Initialized;
    private static object s_InitializeLock;
    private static Exception s_InitializeException;
    private static Singleton s_Instance;

    static Singleton()
    {
        s_InitializeLock = new object();
        s_InitializeException = null;
        s_Initialized = false;
        s_Instance = null;
    }

    protected Singleton()
    {
        if (!s_Initialized)
        {
            InitializeStatic();
        }

        // anything else you really want to happen in the base constructor...
    }

    public void Create()
    {
        InitializeStatic();

        if (s_Instance != null)
        {
            return s_Instance;
        }

        lock (s_InitializeLock)
        {
            if (s_Instance == null)
            {
                s_Instance = new Default();
            }
            
            return s_Instance;
        }
    }
    
    private static void InitializeStatic()
    {
        if (s_Initialized)
        {
            if (s_InitializeException != null)
            {
                throw s_InitializeException;
            }
        }
        else
        {
            lock (s_InitializeLock)
            {
                if (s_Initialized)
                {
                    if (s_InitializeException != null)
                    {
                        throw s_InitializeException;
                    }
                    
                    return;
                }
                try
                {
                    // do real singleton initialization
                }
                catch (Exception ex)
                {
                    if (s_InitializeException == null)
                    {
                        s_InitializeException = ex;
                    }
                }
                
                s_Initialized = true;
            }
            
            if (s_InitializeException != null)
            {
                throw s_InitializeException;
            }
        }
    }
    
    internal static Singleton Instance
    {
        get
        {
            InitializeStatic();
            return s_Instance;
        }
    }
}

Tuesday, November 08, 2005

Profiled performance does not equal real-life performance.

Ian nails it* with this post to the DevelopMentor Dotnet-CX mailing list. Profiling does not give you a real view of the performance of a segment of code, nor does the performance of a segment of code reflect the performance of that code in real use. Don't optimize the performance of something unless you:

  • Have a reproducible test-jig for repeatable performance testing
  • Have an idea of the baseline performance
  • Know where the bottlenecks really are in the code
  • Can tell if the performance of the system gets better or worse with changes.
  • Have an idea of what performance is good enough
* apologies to Don Box. Edit: Ian blogged it here.

How and when are generics realized as real code?

Questions often come up regarding .Net 2.0's generics; how much code is shared, when are the specialized versions created, and how much does it cost? While I want to repeat the refrain I often use—You don't really need to know this—it is useful information. The short version:

  • There is one copy of the generic IL
  • The JIT creates specializations as they are needed
  • All reference-type specializations share one JITted copy
  • Each value-type spawns a separate specialization
For more information, please refer to this excellent post from Ognjen Bajić