views:

234

answers:

5

I'm trying to decide whether or not it makes sense to go through the extra effort to encapsulate my IoC container. Experience tells me that I should put a layer of encapsulation between my apps and any third-party component. I just don't know if this is bordering on overkill.

I can think of situations where I might want to switch containers. For instance, my current container ceases to be maintained, or a different container is proven to be more light-weight/performant and better fits my needs. If this happens, then I'll potentially have a lot of re-wiring to do.

To be clear, I'm considering encapsulation of the registration and resolution of types. I think it's a no-brainer to encapsulate resolution - I'd hope it's common practice to have a helper/util class delegating to the container.

EDIT:

The assumption is that I prefer to wire-up my types programmatically for type-safety, compile-time checking and refactorability. It's this code and its dependency on the container that I'm looking to protect myself from.

I've also been using an IoC container for several other projects that share a lot of the same relationships, but the container is a pain to work with so I want change. But, a change means I lose the reusability of the registration code. Hence, why I'm contemplating encapsulation. It's not a huge burden, but one that I'd, nevertheless, like to mitigate.

I'm looking to:

  • Minimize the impact of change in containers / versions of containers
  • Provide some level of type-registration consistency across projects that may use different containers
  • Provide interface methods that make sense to me (RegisterSingleton<T,T> rather than RegisterType<T,T>( SomeLifetimeProvider ) - using Unity as an example).
  • Augment the container as conditions/scalability requirements change e.g. adding better caching, logging, etc during resolution/registration.
  • Provide my own model for registering type mappings.
    • Say I want to create a bunch of RegistrationHandler objects in an assembly/package and so I can easily segregate registration responsibilities across multiple classes and automatically pickup these handlers without changing code anywhere else.

I realize this is a bit subjective, so pros/cons might be helpful

Thanks!

A: 

Yeah go for it. It's not a whole lot of extra effort and like you say, it gives you better isolation from third party components.

It also means that you can easily switch out the IoC container if you find something that's better. I recently did this with swapping out the Spring.net IoC container for structuremap.

The ASP.NET MVC Contrib project on codeplex is a pretty good place to start. This is what I based my implementation off.

lomaxx
I don't see why the downvote, surely this question is a matter of opinion?
WW
Agreed, I don't understand the objection to increased protection from third-party changes. +1 to offset the downvote.
Ryan Emerle
+7  A: 

Do it later, and only if you actually have the need to change IOC containers.

Pick an IOC container that is non-invasive. That is, one where the objects being connected to each other don't have any dependencies on the IOC container. In this case, there's nothing to encapsulate.

If you have to pick an IOC container that requires that you have dependencies on the container, choose one with the simplest dependencies/API you can. If you need to replace this IOC container (and you probably won't), implement adapters that bridge the new API to the old one.

In other words, let the first IOC container be the one that defines the interfaces for any future container so that you don't have to invent your own, and you can delay any of this sort of work until you absolutely need it.

EDIT:

I don't see a way of guarunteeing type safety short of either:

  1. Designing a relatively complex implementation of the Builder pattern along with visitor implementations that would write IOC configuration files, or something equivalent.
  2. Implementing a type-safe IOC configuration DSL. (My choice if I had multiple apps that required swappable IOC containers.)
Doug Knesek
The type resolution is typically non-invasive, by nature; it's the registration that typically requires a lot of container-specific code. It's this code (assuming I prefer type-safety over XML configuration) that I'm trying to protect myself (and my app(s) from)I agree that steering clear of declarative type mapping is dangerous (such as through annotations or attributes).
Ryan Emerle
Additionally, I'm not totally satisfied with _any_ of the current IoC containers' interfaces, so I don't know that I want the one I choose to dictate.
Ryan Emerle
@Ryan: While I agree with type-safety over XML, I think you'll find that you have one class (possibly even one method) that performs all the registration for a given project. Depending on the number of projects you have, abstracting registration may provide little benefit.
TrueWill
+1  A: 

It's Been Done. (For .NET, at least.)

Common Service Locator library

In any case I agree with Mr. Knesek. You generally only need dependencies on your container in your top-level class.

TrueWill
That seems a bit like overkill for what I'm trying to achieve. I just want to minimize the impact of change should I choose to change containers (in my current project, or future projects). I don't want to introduce _another_ third-party library to accomplish this.
Ryan Emerle
+1  A: 

It's best practice to do something only if there's an actual need for it, and never code something that you guess to be required sometimes in the future (that's the so-called YAGNI-principle). If your architecture is ok, you can easily change the container, if it actually should become necessary...

If you think you need this kind of flexibility, you may look at the Common Service Locator project at CodePlex. It does exactly what you look for: providing a common facade for various IoC containers.

HTH!

Thomas Weller
Sometimes you need to make an educated guess on the maintenance needs of your application in the future. I prefer to have some level of future-proofing, though I am whole-heartedly guided by the YAGNI principle. A single, reusable, encapsulation library (and associated tests) require such minimal effort that it's worth considering now.
Ryan Emerle
I'm with Thomas (and Doug) - it only *seems* like minimal effort now. It would add more code to test, more code that can break, and more code to maintain. And for what? To save you a little time on something that might never happen. I'd even say *probably* won't ever happen, because the kinds of things you'd change containers for (for example, to go from attribute-driven injection to declarative mappings) are the kinds of things that wouldn't be covered by an encapsulating interface.
Jeff Sternal
Just out of curiosity: What kind of application would have "changing the IoC container implementation" as a maintenace need? And btw: If it requires "minimal effort" to encapsulate the container now, then it will require even less effort to change it in the future, should this need really ever arise...
Thomas Weller