Wednesday, May 30, 2007

Code Coverage Analysis

Late last week a coworker asked me whether it was possible to see code coverage information for tests. Of course! I said, so since I had a project open with a bunch of unit tests, I right-clicked "Run Tests... With Coverage". Then I just let TestDriven.Net, MbUnit, NCover and NCoverExplorer do their magic. Needless to say we were both impressed! The resulting output showed me that I'd achieved 85% coverage without even trying very hard. The flip side was that I'd missed several interesting cases. Code coverage isn't everything but it is a useful metric for judging test quality. So I proceeded to use code coverage analysis to guide my testing efforts for the next few days. I found a couple of bugs because code coverage data indicated that certain unit tests weren't quite reaching their mark. The unit tests had not failed but the optimizations being tested had been implemented incorrectly in ways that were compensated for elsewhere. Subtle. Beware hidden behavior that cannot be observed! Ahh! So good to reaquire old habits! Now the Castle.Components.Scheduler project has 248 unit tests with 99% code coverage. Pretty neat!

Wednesday, May 23, 2007

P&P Caching Application Block: YAGNI

At Oren's suggestion I spent a few minutes today considering whether the Patterns & Practices Caching Application Block would be a good fit for a couple of my applications. It seemed quite powerful. I found myself admiring the abstract structures and some of the design ideas even though I wasn't sure I liked some of the dependencies. Still, I found myself feeling unaccountably lost. Why was it so difficult to decide whether and how to integrate these components?

Then it dawned on me. I was focusing on accidental properties of the problem. While sifting through this foreign code base I'd lost track of the essential problem I was trying to solve: caching. I wanted a simple caching service that I could plug into my applications with a rudimentary common case implementation and the option of swapping in fancier ones for certain deployment scenarios and for testing.

The P&P CAB components went well beyond solving the essential problem: they were codifying a solution! They provided a rigid framework with extension points for backing stores, instrumentation and other odds and ends. They designed it as if they thought they had solved the caching problem so well that no one else could ever quibble over the implementation.

The telling sign is that the central components were not designed as services. There was no ICache interface to be found anywhere, just a Cache class with many assumptions and pieces baked in and some half-hearted ICacheOperations interface. I was instantly reminded of all of the things that I dislike about frameworks...

I'm not in the market for frameworks! I want services I can use and choose to extend or reimplement as I see fit. (That's why I like the Castle Project so much.) For my caching needs all I want are some components that implement a little service like this:

public interface ICache
{
    bool ContainsKey(string key);
    object GetValue(string key);
    void SetValue(string key, object value);
    void Flush();

    // and maybe a few other things...
}

So after all that, this is what I finally wrote in the Castle Developers mailing list to sum up my observations:

Trouble is it's [P&P CAB is] so far out in YAGNI-land for me that I don't know what to do with it!

Tuesday, May 22, 2007

Laziness comes back to bite you.

Some time ago I wrote a class that was really just used as a record to carry some data around places. It looked a bit like this:

public class FilterInfo
{
    /// 
    /// The name of the filter.
    /// Maximum length of 100 chars.
    /// 
    public string Name;

    /// 
    /// The description of the filter.
    /// Maximum length of 1000 chars.
    /// 
    public string Description;
}

See how I saved a few keystrokes by declaring the members as fields rather than as properties? Silly me. Well, it turns out that NVelocity does not know how to access the values of fields in templates but it has no trouble at all with properties. Oops.

It took me 15 minutes to figure that out during which time I'm sure I could have declared those members as properties instead. Silly Jeff. Fortunately I think that was my only lapse in this project...

P.S. I do consider NVelocity's behavior here to be a little bit broken but I don't care enough to argue the point or to add support for public fields.

Thursday, May 17, 2007

Pet Peeve: Examples that do nothing but demonstrate the syntax

I hate documentation that does nothing but repeat verbatim what can already easily be deduced from the syntax. I mean, how often have I see a property called "Foo" with the description "Gets or sets the value of Foo.". This is plainly idiotic. This documentation won't help me at all if I don't know what "Foo" is used for, what values it admits, and whether there's lots of it on the moon.

So can't Microsoft's writers do better than this example?

From: System.Configuration.SectionInformation.ProtectionProvider

The following example shows how to get the ProtectSection value of a ConfigurationSection object.

C#

static public void GetProtectionProvider()
{
    SectionInformation sInfo =
        GetSectionInformation();

    ProtectedConfigurationProvider pp = 
        sInfo.ProtectionProvider;
    if (pp == null)
        Console.WriteLine("Protection provider is null");
    else
        Console.WriteLine("Protection provider: {0}", 
            pp.ToString());
}

Thank you very much. Your attention to detail in providing me with 100% example coverage in the documentation has been most enlightening. Fortunately I was just casually browsing through the Configuration API so I don't actually care about the ProtectionProvider property. In any case, I'm pretty sure I could figure out what to do with it. And if in doubt, I can always whip out Reflector. That's an especially useful trick with such programmer-friendly management-approved frameworks as ASP.Net.

P.S. Microsoft is by no means the only offender here!