After my MEF presentation at the Hampton Roads .NET User Group someone asked me about creating objects like customers and invoices via MEF. I gave an overly quick answer to a really good question.
A lot of the IoC history involves using dependency injection for services. This is great partly because it’s a framework to isolate plain old objects from services, and services from each other. Like many of the techniques we’ve adopted in the agile timeframe, it’s not just what the technique does for us, but what the technique does to us. That’s the quick answer I gave.
But, we can go further to fully composed systems. Fully composed systems have offered mind boggling benefits in some places they’ve been tried, and they haven’t been tried in very many places yet. This is why I have such a high fascination with NetKernel and the work people like Randy Kahle (@RandyKahle) and Brian Sletten (@bsletten) are doing. And that work is similar to work Juval Lowy and I have talked about for a number of years.
However, fully composed systems with MEF, and I assume other DI tools (although I’ll be happy to be proven wrong) are hard. Without the infrastructure of something like NetKernel there’s a fair amount of work to do, and without the caching benefits of NetKernel it’s going to be tough to justify. It’s hard because everything needs an interface. Everything. And even if you generate the interfaces and plain objects, the level of infrastructure ceremony gets very unwieldy.. At least that’s my experience from using MEF to wrap everything (yes, everything) in interfaces, in order to create a fully composed MEF 1.0 system.
We could go a slightly different direction. Put everything into the container, but place plain old objects in the container as their own type, rather than via an interface. Plain old objects in this sense are objects that we can’t imagine a scenario where they’ll be reused and they have a unique, and generally multi-valued interface. A customer or invoice POCO would be examples.
Placing these objects into the container offers the immediate benefit of guaranteeing their usage is isolated We take advantage of what DI does to us, not just for us..
And if we use inference in MEF 2.0 (.NET 4.5), and probably configuration techniques with other IoC containers, we can stick another object in if we have a later reason to do it.
But here’s where strong typing bites us. Any new class that ever replaces that plain old object (the customer or invoice) has to be assignable to that class. That means it has to be that class or a class that derives from it. I’m still hanging on to the strong typing life boat because I still feel that without it I’m in a North Atlantic storm. For big systems, I think that’s still true, and while I put a lot of thought into making big systems into smaller systems, non-typed based DI is still a jump into icy water for me.
With the plain object in the container under its own type, if I get blindsided with a requirement that just doesn’t fit I can manage, I just have to write a wrapper for the non-derived object and the wrapper has to derive from the expected type. Ugly, but workable.
What I want to do is experiment with strongly typed systems with generated interfaces. I’ve already done this with traditional generation, and I want a solution that is cleaner than that. I don’t have the syntax worked out, but imagine that we never create the interface for our plain old object, we just tell the system to do it. The container uses the interface, all using objects request the object by its interface, and we humans can ignore it.
Until the day the plain old object needs attention. On that day, we make the interface explicit and do whatever we need to do.
But with the versions of .NET we have today, we can’t build this.