Another InitImportantThing Approach

I thought of another approach to the InitImportantThing problem that I blogged about yesterday. I think it’s a bit harder to code, but it’s certainly explicit and avoids the magic method that Jon dislikes so much.

The crux of the problem is that ServiceHostBase needs a valid ServiceDescription in order to operate. The WCF team chose to provide said description to ServiceHostBase via the abstract CreateDescription method. But as we saw, ServiceHostBase can’t call CreateDescription from it’s own constructor. So instead, derived classes are forced to call InitializeDescription in their own constructor. Since that call isn’t enforced by the compiler, it’s easy to forget to include it. Since the exception that gets thrown doesn’t really tell you what went wrong, it’s easy to spend hours trying to figure it out.

So here’s a better approach: since the ServiceHostBase needs a valid ServiceDescription in order to operate, why not pass it in as a constructor parameter?

ServiceHostBase has a protected constructor with no parameters. But since it needs you to call InitializeDescription in your derived class constructor, it really needs the ServiceDescription, a collection of ContractDescriptions (also returned from CreateDescription) and a collection of base addresses (passed into InitalizeDescription). If these were parameters on ServiceHostBase’s constructor, it could validate that information directly, without needing abstract or magic methods.

The one problem with this approach is that the creation of a ServiceDescription is non-trivial. ServiceHost’s implementation of CreateDescription generates the ServiceDescription by reflecting over the service type. You still need that code, but now you would call it from the base constructor initializer instead. That means it has to be a static method, but otherwise it would work just fine. Here’s yesterday’s code, updated for this approach:

public abstract class Base
{
    public Base(string importantThing)
    {
        if (string.IsNullOrEmpty(importantThing))
            throw new Exception();

        _importantThing = importantThing;

    }

    private string _importantThing;

    public string ImportantThing  
    {  
        get { return _importantThing; }  
    }
}

public class Derived : Base
{
    private object _data;

    public Derived(DateTime dt) : base(CreateImportantThing(dt))
    {
        _data = dt;
    }

    private static string CreateImportantThing(DateTime dt)
    {
        //this is obviously trivial, but could be much
        //more complicated if need be
        return dt.ToLongDateString();
    }
}

This seems like the best approach to me. You remove the un-obvious magic method call requirement when deriving your own service host while still enforcing the data consistency check in the base class during construction. Best of both worlds, right?

So I wonder why the WCF team didn’t do it this way?

Calling InitImportantThing

Jon Flanders throws a little vitriol at the WCF team fore their design of the abstract ServiceHostBase class, calling the current design “stupid”. Normally, I’m not one to take up for the WCF team. I’ve spent many an hour banging my head against WCF for different reasons but exactly how Jon describes. However, in this case, the WCF team looks caught between a rock and a hard place, where the rock is correct behavior and the hard place is the way CLR object construction works.

The crux of Jon’s beef is that if you build your own ServiceHost by inheriting from SeviceHostBase, it’s not enough just to override the abstract CreateDescription method. You also have to call the “magic” InitializeDescription method in your derived class constructor. If you don’t, CreateDescription never gets called. CreateDescription returns a ServiceDescription instance which is to route messages from the channel layer to the and service layer. Jon writes that “Creating a valid ServiceDescription and returning the list of implemented contracts is essential for making your ServiceHostBase-derived class work.” I.e. it’s really important. Yet, unless you remember to call InitializeDescription, this “essential” ServiceDescription doesn’t get configured correctly. Yep, I see how that might sound stupid.

But if this design is stupid, what would be a better design? After thinking about this specific problem a while, I’m don’t think there is a better design out there.

The question is, when is the right time to set up the service description? Jon called ServiceDescription “essential” to the operation of ServiceHostBase. That implies it should be configured during the construction of a new service host instance. It wouldn’t do to have ServiceDescription unconfigured for some period of time between construction and use. What if the ServiceDescription is invalid or the call to CreateDescription throws an exception? Then you’d be in a position where you could create what looks like a valid service host, but it would throw an exception when you tried to use it. You can see why the WCF team would want to avoid that scenario.

So if you want the service host to have a valid ServiceDescription by the end of construction, what choices do you have? Given that the ServiceDescription depends on derived class data, the only choice is to use a magic method! Here’s an example to demonstrate what I mean:

public abstract class Base
{
    public Base()
    {
    }

    private string _importantThing;
    protected abstract string CreateImportantThing();

    protected void InitImportantThing()
    {
        _importantThing = CreateImportantThing();
        if (_importantThing == null)
            throw new Exception();
    }

    public string ImportantThing  
    {  
        get { return _importantThing; }  
    }
}

public class Derived : Base
{
    private object _data;

    public Derived(DateTime dt)
    {
        _data = dt;
    }

    protected override string CreateImportantThing()
    {
        return _data.ToString();
    }
}

I’ve tried to distill out the relevant parts of ServiceHostBase. In the example, Base stores some important thing that gets created by the derived class based on data that’s passed into the derived class’s constructor. Remember, we want the class to be fully configured by the end of the constructor. If CreateImportantThing throws an exception or returns null, we want to know about it right away when the object is created.

In the code above, the magic method InitImportantThing never gets called and thus the _importantThing field never gets setup. This roughly corresponds to Jon’s scenario where he didn’t know to call InitalizeDescription. And like WCF, we can make this sample work by inserting a call to InitImportantThing at the end of Derived’s constructor.

You might be tempted to put the call to InitImportantThing in Base’s constructor. But that won’t work because Base’s constructor runs before Derived’s constructor does. Thus, Derived’s _data field will still be null and the call to CreateImportantThing throws a null reference exception.

The final option would be to place the a call to InitImportantThing in ImportantThing’s property get method, if _importantThing is null. This defers construction of _importantThing until the first time it’s used. By this time, the derived class constructor will have run and so the derived class data will be available for use. This eliminates the magic method call, but it means we don’t know if the instance is valid until we go to use it – i.e. the scenario we were expressly trying to avoid.

So basically, the looks like the WCF team had two choices:

  1. Err on the side of caution and require calling InitializeDescription in the ServiceHostBase derived class’s constructor.
  2. Err on the side of easy extensibility and call InitializeDescription the first time the ServiceDescription.

Put that way, what the WCF team ended up doing doesn’t seem so stupid. This is especially true when you consider that the vast majority of people aren’t creating their own service hosts anyway. It would have been possible to do both: explicitly call InitializeDescription in ServiceHost’s constructor but also have an implicit call in ServiceDescription property get if the field was null. But I’m not on the product team, so I don’t know what other tradeoffs that implies. Checking for a null reference seems like no big deal, but I don’t know how often this property gets called.

One other point: even though I don’t think this design is stupid, I agree 100% with Jon that the exception is misleading.The way it’s written, the immediate assumption is that your implementation of CreateDescription is bad, not that you forgot to call InitializeDescription. It turns out that ServiceHostBase is already tracking wether InitializeDescription has been called via the initializeDescriptionHasFinished field. So why can’t it throw an exception like “Dude, you forgot to call InitializeDescription” when that field is false? It wouldn’t make the design any cleaner, but it would have saved Jon hours of digging thru the implementation of ServiceHost and ServiceHostBase in Reflector.

Morning Coffee 109

  • I forgot to add a number to my last morning coffee post. However, after extensive research, I have determined that it was #108. So thing are continuing as usual today with #109. On the other hand, do you really want development and architecture opinions from a guy who can barely count? 😄
  • The finalists in the Dream-Build-Play contesthave been announced. I haven’t played any of them yet (some are available for download) but they several of them sure look good.
  • And speaking of gaming, MS announced an Xbox 360 price drop yesterday. So if you want to get in on some of the XNA action, here’s your chance (or you could just build for your PC – take your pick).
  • Finally on the gaming front, if you’re not busy Monday you can watch the first day of Gamefest 2007 online. Get the scoop on XNA 2.0 as well as the new XNA networking support. I, alas, am busy Monday so I’ll have to catch it on demand.
  • On to, you know, actual geek stuff things. Scott Guthrie seems to have retired his LINQ to SQL series and moved on to LINQ to XML. He shows how to build an RSS reader application with LINQ to XML. An oldie demo, but a goodie.
  • Wanna learn F#, there’s a whole site of samples up on CodePlex. (via Don Syme)
  • Jeff Atwood is annoyed at how many different products you have to install to get a current & complete setup of VS 2005. Of course, MS shipped two parts of that stack since VS05 shipped (TFS & DBPro), three service packs (VS05 SP1, SQL 05 SP2 and DBPro SR1) and a major OS upgrade (VS Vista update). Doesn’t the same thing happen with any shipping product after a few years? BTW, if this is such a huge hassle, I wonder why Jeff doesn’t create a slipstreamed VS installer?
  • Udi Dahan has a great post on estimation where he claims “Developers don’t know how to estimate.” No argument, but the way he phrases it sounds like it’s the developer’s fault they suck at estimation. It’s not. Developing – by definition – is building something you’ve never built before. Is it any surprise we suck at estimating how long it will take us to do something we’ve never done before?

Quote of the Day

In a discussion on governance in our bi-weekly Integration v-team meeting, Jason Howell made the following tongue-in-cheek suggestion:

“If you have architect in your title, you get a taser.”

Morning Coffee

  • Libor Soucek continues our conversation about durable messaging. We still don’t agree, but he says he “fine” with durable messaging. He does go out of his way to differentiate between enterprise and supporting systems. But when you’re building connected systems, does that differentiation still matter?
  • After taking a few months off, John deVadoss is back at the blog. Check out his Big SOA/Little SOA post. I especially like his snowball analogy “How do you build a big snowball? You start with a small snowball.”) though he’s also on this “middle out” bandwagon. Do we really believe “middle out” works, or are we just saying it because we know top down and bottom up don’t? And John: You’re welcome!
  • Anyone coming to the Microsoft SOA & Business Process Conference this fall? Maybe we can have a shindig / blogger dinner / unconference / something?
  • Remus Rusanu writes about SSB’s dynamic routing. One of the (many) cool things about SSB is that all the addressing is logical, not physical. Routing is what binds logical addresses to physical addresses, and it’s extensible.
  • Martin Fowler discusses the value of sticking to one language. I agree with his points about large frameworks being as difficult to learn as a new language. I’ve said for a long time “If you build a framework, build tools to make it easy to use your framework”. Language is obviously a core example of a tool. Another interesting point Martin makes is the traditional “intimate relationship” between scripting languages and C, but that the rise of JVM & CLR makes them impossible to ignore. Does the need to play well in a managed environment hinder a C based language like Ruby when compared to a natively managed scripting language like Powershell? Finally, Martin’s “jigger of 80 proof ugliness” quote made me laugh.
  • Politics 2.0 Watch: EJ Dionne says that DailyKos is doing for Democrats what Rush Limbaugh did for Republicans almost twenty years ago: mobilization. Josh Marshall points out that “what’s happening today is vastly more participatory and distributed…than anything happening back then.”