Successful IoC container usage

Every now and again I here the meme of IoC containers being bad, they lead to bad developer practices, they’re too complicated and on and on. IoC containers – like any sharp tool – can be easily abused. Dependency injection, as a concept, is here to stay. Heck, it’s even in Angular.

Good usage of IoC containers goes hand in hand with good OO design. Dependency injection won’t make your design better, but it can enable better design.

So what do I use IoC containers for? First and foremost, dependency injection. If I have a 3rd-party dependency, I’ll inject it. This enables me to swap implementations or isolate that dependency behind a façade. Additionally, if I want to provide different configurations of that component for different environments, dependency injection allows me to modify that behavior without modifying services using that component.

I am, however, very judicious in my facades. I don’t wrap 3rd party libraries, like a Repository does with your DbContext or ISession. If a library needs simplification or unification (Adapter pattern), that’s where wrapping the dependency helps.

I also don’t create deep compositional graphs. I don’t get stricken with service-itis, where every function has to have an IFooService and FooService implementation.

Instead, I focus on capturing concepts in my application. In one I’m looking at, I have concepts for:

  • Queries
  • Commands
  • Validators
  • Notifications
  • Model binders
  • Filters
  • Search providers
  • PDF document generators
  • Search providers
  • REST document readers/writers

Each of these has multiple implementers of a common interface, often as a generic interface. These are all examples of the good OO design patterns – the behavioral patterns, including:

  • Chain of responsibility
  • Command
  • Mediator
  • Strategy
  • Visitor

I strive to find concepts in my system, and build abstractions around those concepts. The IModelBinderProvider interface, for example, is a chain of responsibility implementation, where we have a concept of providing a model binder based on inputs, and each provider deciding to provide a model binder (or not).

The final usage is around lifecycle/lifetime management. This is much easier if you have a container and ecosystem that provides explicit scoping using child/nested containers. Web API for example has an “IDepedencyScope” which acts as a composition root for each request. I either have singleton components, composition root-scoped components (like your DbContext/ISession), or resolve-scoped components (instantiated once per call to Resolve).

Ultimately, successful container usage comes down to proper OO, limiting abstractions and focusing on concepts. Composition can be achieved in many forms – often supported directly in the language, such as pattern matching or mixins – but no language has it perfect so being able to still rely on dependency injection without a lot of fuss can be extremely powerful.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in DependencyInjection, OO. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Piotr Perak

    “So what do I use IoC containers for? First and foremost, dependency injection.”
    I thought this is what they are used for. What are other possible uses?

    • jbogard

      Fancy factories or service locators.

  • beton

    Good thoughts Jimmy.
    Especially about capturing concepts while hunting for abstractions instead for plumbing IFoo -> Foo everywhere just because IoC is up and running.

  • Ryan O’Neill

    Jimmy, would you be able to point me in the direction of an open source project that you consider uses good patterns? I’ve been looking for something to dissect but I can’t find anything that isn’t over engineered or just too simple to even bother with.

  • Phil Sandler

    “I also don’t create deep compositional graphs. I don’t get stricken with service-itis, where every function has to have an IFooService and FooService implementation.”

    I feel this needs a little defending. Using injection to create tiny components really simplifies each component (SRP), and moves your code toward a more functional style (which is also highly compatible with SOA). This does lead to some classes having a lot of small dependencies–in fact you could argue that each injected component could/should only contain a single method.

    There may be better ways to move toward a more functional style, but IoC is a convenient way to do so in C#.

    I’m not saying this is a *better* approach than what you are suggesting, but I’ve seen a lot of success with it.

    • jbogard

      This approach is OK – as long as you don’t mock those components. From the outside, I shouldn’t care about any of those sub-components, as they aren’t really dependencies, they’re internal components. I shouldn’t have to mock anything out. I leave my mocks for behaviors I can’t control (wrapping Http requests etc).

      • Phil Sandler

        I’m not sure I follow. If your dependency talks to the database, you will likely want to mock it in a test (unless we’re talking about integration tests).

        In any case, it depends a lot on how code is structured and your overall testing strategy. The types of structures that take a lot of service dependencies are usually not the types that I write a lot of unit tests around.

        • jbogard

          Probably better with an example – even if I decompose a service into multiple sub-components, I still won’t mock those components in a unit test. Does that make sense? I only mock dependencies I can’t control.

          This is all pretty abstract too without looking at actual code.

          • Uli armbruster

            I would really enjoy a blog post about that specific detail because what Phil mentioned is also my point of view. But I agree this can only be discussed reasonably on a concrete example.

            Besides that I totally agree with you not abstracting libraries like an ORM. So your post about your switch from NHibernate to EF in a 3 year old project was the best bedding for that!

  • Mark

    I’m still not convinced by IoC containers and DI frameworks in general. I massively prefer to do DI manually, since it makes all the code much easier to understand.

    Angular is an exception, though, since it’s a DI framework which is built specifically for building Angular apps, so it makes the code structure easier to understand rather than harder when done right :)

    • jbogard

      What’s the difference between Angular DI and C# DI? They both seem to take items in the ctor (or function ctor), supplied by “something else” that can be configured. Also, what’s manual DI? Is that “poor man’s DI”? Or just you’re manually creating composition roots or manually creating items?

      • Mark

        I see two main differences between Angular DI and a random C# DI IoC container. Firstly, javascript is a much more loosely-typed language, so you don’t lose so much of the navigation and analysis power that C#/Resharper give you by using a some magic IoC container, because you never had it in the first place. Secondly, Angular DI is built around Angular concepts like services, directives, etc. Having some order imposed on your Angular app makes it much easier to navigate, while C# DI frameworks have to be much more generic in order to accommodate arbitrary programs, so they make navigation harder.

        And yeah, “manual DI” is just passing around factories and calling constructors manually as opposed to using some IoC container/DI framework like NInject or Autofac

    • What if you *cannot* call a constructor? I.e. you have something that you want to use in your WebAPI controller, WCF service or NSB message handler? To be honest, I hear about “I have more control” quite often and every time the cause of it that the one didn’t manage to grasp the concept or was lazy enough not to get into the usage details. Writing everything in assembler gives us the higher level of control but happily not many do that in real life.

  • Pingback: Successful IoC container usage | JS App Develop...()

  • Steve Codes

    I try to do as described in the article. But I usually end up with service-itis anyway. I’d love to see some more concrete real world examples of how to avoid this. I just don’t find that my code always fits into the abstractions you listed. I do use CQS patterns talked about in this blog so that covers most data access. However I feel like I am always battling between two opposing forces: wanting to separate out my code into multiple classes for SRP and easy unit testing, but at the same time trying to reduce the number of abstractions.

  • pedant

    here! here! ;-)

  • Uli Armbruster

    I would be really interested in an article about getting IoC container usage and DDD married effectively.

    • jbogard

      Not sure what one has to do with the other?

  • Dariusz Lenartowicz

    Queries, commands, filters, binders… I have BasePriceCalculator, RabateCalculator and DiscountCalculator which are used by InvoiceFactory which uses InvoiceNumberGenerator. Where those classes belongs in your list of limited abstractions? How to get rid of “service-itis” in situations like this?

    • jbogard

      Basically, I only introduce those things through refactoring. Those concepts are fine – patterns are fine – but those are different than Service-itis I think. Service isn’t a pattern.

      • Dariusz Lenartowicz

        Does this mean that You will register those classes in the container (as they are)?

        • jbogard

          Perhaps, perhaps not. It’s not horrible just to new things up.