Why do I need an IoC container as opposed to straightforward DI code? [closed]
Asked Answered
C

30

598

I've been using Dependency Injection (DI) for a while, injecting either in a constructor, property, or method. I've never felt a need to use an Inversion of Control (IoC) container. However, the more I read, the more pressure I feel from the community to use an IoC container.

I played with .NET containers like StructureMap, NInject, Unity, and Funq. I still fail to see how an IoC container is going to benefit / improve my code.

I'm also afraid to start using a container at work because many of my co-workers will see code which they don't understand. Many of them may be reluctant to learn new technology.

Please, convince me that I need to use an IoC container. I'm going to use these arguments when I talk to my fellow developers at work.

Convulsive answered 16/5, 2009 at 1:6 Comment(6)
Good question. I am answering this in comments as I am very new to the idea of IOC. It looks like the idea of plug and play components and loose coupling. Whether you will have the need to use some other component in place of the current one, is need based. Use of IOC is to prepare the code for such a change, if it arises IMO.Crary
@Crary but I can achieve loose coupling with simple DI. However, I see your point in case I use configuration file. However, I'm not sure if I like to use configuration file. Config files are very verbose, difficulties with refactoring, and switching between several files.Convulsive
just adding a comment since it seems you are looking for reasons to use IoC mainly; but something else needs to be said about your issue. You cannot write your code to the level of the worse person on your team or for fear that they wont want to learn. You have a responsibility not just to being a professional but also to your future to grow and your team should not hold you back.Lynching
@Kevin, Actually we're using IoC. It wasn't as hard as thought to teach everyone about IoC.Convulsive
@Vadim, good to hear. I guess by Joel's standard your team is full of geniuses and I envy you hah!Lynching
I've got no idea why moderators close massively upvoted and useful questions. Perhaps in this case, Will doesn't understand the question, or he doesn't understand what people use stackexchange for? If it's "not a good fit for stackexchange's Q&A format" then perhaps consider that your policy is wrong and not all of these hundreds of useful questions with hundreds of up-votes and up-voted useful answers.Derry
W
440

Wow, can't believe that Joel would favor this:

var svc = new ShippingService(new ProductLocator(), 
   new PricingService(), new InventoryService(), 
   new TrackingRepository(new ConfigProvider()), 
   new Logger(new EmailLogger(new ConfigProvider())));

over this:

var svc = IoC.Resolve<IShippingService>();

Many folks don't realize that your dependencies chain can become nested, and it quickly becomes unwieldy to wire them up manually. Even with factories, the duplication of your code is just not worth it.

IoC containers can be complex, yes. But for this simple case I've shown it's incredibly easy.


Okay, let's justify this even more. Let's say you have some entities or model objects that you want to bind to a smart UI. This smart UI (we'll call it Shindows Morms) wants you to implement INotifyPropertyChanged so that it can do change tracking & update the UI accordingly.

"OK, that doesn't sound so hard" so you start writing.

You start with this:

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime CustomerSince { get; set; }
    public string Status { get; set; }
}

..and end up with this:

public class UglyCustomer : INotifyPropertyChanged
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            string oldValue = _firstName;
            _firstName = value;
            if(oldValue != value)
                OnPropertyChanged("FirstName");
        }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set
        {
            string oldValue = _lastName;
            _lastName = value;
            if(oldValue != value)
                OnPropertyChanged("LastName");
        }
    }

    private DateTime _customerSince;
    public DateTime CustomerSince
    {
        get { return _customerSince; }
        set
        {
            DateTime oldValue = _customerSince;
            _customerSince = value;
            if(oldValue != value)
                OnPropertyChanged("CustomerSince");
        }
    }

    private string _status;
    public string Status
    {
        get { return _status; }
        set
        {
            string oldValue = _status;
            _status = value;
            if(oldValue != value)
                OnPropertyChanged("Status");
        }
    }

    protected virtual void OnPropertyChanged(string property)
    {
        var propertyChanged = PropertyChanged;

        if(propertyChanged != null)
            propertyChanged(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

That's disgusting plumbing code, and I maintain that if you're writing code like that by hand you're stealing from your client. There are better, smarter way of working.

Ever hear that term, work smarter, not harder?

Well imagine some smart guy on your team came up and said: "Here's an easier way"

If you make your properties virtual (calm down, it's not that big of a deal) then we can weave in that property behavior automatically. (This is called AOP, but don't worry about the name, focus on what it's going to do for you)

Depending on which IoC tool you're using, you could do something that looks like this:

var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper());

Poof! All of that manual INotifyPropertyChanged BS is now automatically generated for you, on every virtual property setter of the object in question.

Is this magic? YES! If you can trust the fact that this code does its job, then you can safely skip all of that property wrapping mumbo-jumbo. You've got business problems to solve.

Some other interesting uses of an IoC tool to do AOP:

  • Declarative & nested database transactions
  • Declarative & nested Unit of work
  • Logging
  • Pre/Post conditions (Design by Contract)
Weed answered 16/5, 2009 at 1:6 Comment(25)
Excellent addition. I often find myself doing that kind of plumbing for an object. I will now open my mind for IoC and see what it can be accounted for.Decussate
Also, which IoC tool are you referring too?Decussate
Oops, you forgot to make all the properties virtual, and it didn't work. Is the time you needed to spend debugging this stealing from your client too? (Apologies if you're not using DynamicProxy. :P)Fairyfairyland
Actually we're using IoC. It wasn't as hard as I thought to teach everyone about IoC.Convulsive
Truly the only way of writing maintainable code.Spiny
You sacrifice a LOT of clarity by using the INotifyPropertyChanged wrapper. If it takes you more than a few minutes to write that plumbing to begin with then you're in the wrong business. Less is not more when it comes to the verbosity of your code!Divebomb
@Divebomb - I completely disagree. First, where does clarity matter in this example? Nearest the consumer. The consumer is explicitly asking for INotifyPropertyChanged. Just because we can create this type of code with micro or macro code generation, doesn't mean it's a good idea to write it. That INotifyPropertyChanged gunk is just rote, mundane, plumbing and actually detracts from the readability of the class in question.Weed
I'm interested in what tool knows how to inject code automatically to work as the NotifyPropertyChangedWrapper(), though your example is crafted to be particularly poor - if you'd use Observable wrappers around each property then you could make the code significantly cleaner without using an IoC container (or whatever NotifyPropertyChangedWrapper() is).Susie
Jamie - the real work is generally done by something like DynamicProxy that lets you easily intercept calls to (virtual or interface) members on your objects. This has little to do with IoC - in fact, in the example above, we're talking about an entity anyway, so you'd never be resolving that from your container. You'd have to muck about with your ORM, which is entirely separate. I don't want to sound anti-IoC - I'm using Castle and a ton of custom facilities in my current project, but the above example is a poor one (which doesn't work as written, or as described).Fairyfairyland
To be fair, my comment regarded the first half of your answer before the edit. You went a bit out there with the NotifyPropertyChanged wrapper (this is not a common case, though admittedly cool).Mousebird
@Jamie, @Fairyfairyland I don't think Ben's example above was intended to be a complete implementation by any means. That said, I'd be curious to see your implementation of "Observable wrappers around each property" that doesn't look like the typical implementation of INotifyPropertyChanged.Fantoccini
Marked down because you're confusing the Dependency Injection pattern and the Service Locator pattern. The former is meant to be used instead of the latter. E.g. an object (or indeed the entire system) should never call Resolve(...) to get an instance of IShippingService. The objects that need an IShippingService should receive a reference to the instance they should use when they are constructed, and some higher layer is responsible for connecting the two objects together.Paresis
@Nat: I'm not confusing the two. I'm illustrating the power of an IoC tool. Eventually you have to ask the container for an object, and ideally this happens way at the forefront, and subsequent injections happen for you.Weed
@Nat: See my comment on this exact topic on the next answer down.Weed
Whatever this is (IoC, DynamicProxy, AOP or black magic) can someone link me to a concrete article/specific documentation in framework that provides more details for achieving this?Farman
Ben - Whilst I agree with your comments on IoC/DI, I think this example - var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper()); seems to be completely wrong. I can't see any scenario where your IoC container could return a Customer object with INotify.. implemented without having something else declare the "gunk" How on earth would you actually implement this?Torgerson
I need to agree with Chris Webb, what does NotifyPropertyChangedWrapper look like ??Stanwin
I'm confused by this answer. An answer here on SO that I can't find, says that entities should never be constructed by a DIC. This one says that your application should be seperated to a construction, and an execution part, and the DIC should never show up in the execution part, making it impossible to use it to create an entity.Rag
IoC != AOP. IoC aims at removing hard-wired dependences between objects/services, while AOP aims at separating concerns in well-encapsulated modules, and "weave" all this concerns automatically. The former can be used to perform the latter, but there are other (likely better) alternatives, like preprocessing or dynamic code generation. In my opinion, if you choose to use an IoC container because it allows you to do AOP, you are not making the right choice: ther are better tools for that (see the numerous AOP frameworks, such as PostSharp, AspectC++, AspectJ, etc.).Karolekarolina
@ChrisWebb Someone very helpfully asked this as a new SO question and got a helpful answer, in case you're still interested.Midwest
@Ben Scheirman Your first example is bad - you missed out the five lines of registration.Menken
IOC and AOP are not identical, no, but they go very well hand-in-hand. Castle Windsor gives you both. Here is an example of how you may use it to implement INotifyPropertyChanged in a clever way. We have successfully been using this in our application framework at work, currently empowering something like 50? or so applications. I totally agree with the one who wrote that classes without a lot of plumming is much easier to read & maintain.Knowles
Hopefully Ben has moved on in 4 years & is now embarrassed by this answer. 400+ upvotes for nothing more than an attack on two badly constructed strawmen is a dreadful indictment of how poor a source of information SO can be at times.Mattah
-1, This is an example of how not to use IOC.Semipro
Your second example appears to be totally unrelated to IOC. I don't use IOC at all (sticking with standard DI), but do use AOP via PostSharp, and can totally implement INotifyProperty via aspect weaving by adding an attribute on top of my class. Since this question is about what IOC brings to the table, and what you can gain from it that you can't have otherwise, I have to conclude that either you don't understand what AOP is and how it is different from IOC, or you're being disingenuous.Acey
C
138

I'm with you, Vadim. IoC containers take a simple, elegant, and useful concept, and make it something you have to study for two days with a 200-page manual.

I personally am perplexed at how the IoC community took a beautiful, elegant article by Martin Fowler and turned it into a bunch of complex frameworks typically with 200-300 page manuals.

I try not to be judgemental (HAHA!), but I think that people who use IoC containers are (A) very smart and (B) lacking in empathy for people who aren't as smart as they are. Everything makes perfect sense to them, so they have trouble understanding that many ordinary programmers will find the concepts confusing. It's the curse of knowledge. The people who understand IoC containers have trouble believing that there are people who don't understand it.

The most valuable benefit of using an IoC container is that you can have a configuration switch in one place which lets you change between, say, test mode and production mode. For example, suppose you have two versions of your database access classes... one version which logged aggressively and did a lot of validation, which you used during development, and another version without logging or validation that was screamingly fast for production. It is nice to be able to switch between them in one place. On the other hand, this is a fairly trivial problem easily handled in a simpler way without the complexity of IoC containers.

I believe that if you use IoC containers, your code becomes, frankly, a lot harder to read. The number of places you have to look at to figure out what the code is trying to do goes up by at least one. And somewhere in heaven an angel cries out.

Calycle answered 16/5, 2009 at 1:6 Comment(50)
If I may say, it looks like different view of the world for different people. People who use IOC are like ideologists wanting the world to follow their footsteps & then there are other like me (and other developers) who are stuck between ideology & reality ;)Crary
Couldn't agree more. Started looking into using a DI framework (StructureMap) which claims to be the oldest IoC container. The complexity was staggering considering what I wanted. Instead I am writing my own very simple Service Locator. Perhaps one of the other IoC containers would have made more sense but I really don't see the point nor do I have the leisure of spending several days figuring out how to use something that will make reading the code more complex.Vikki
Martin Fowler, while a great author, didn't in any way invent IoC.Sacral
I think you have your facts mixed up a bit Joel. IoC and containers came first, then came the treatise by Martin, not vice-versa.Nomanomad
shahkalpesh Which IoC container did you work with?Nomanomad
eesh most of the containers let you get going very quickly. With autofac, structure map, unity, ninject, etc you should be able to have the container working in about 5 mins. Yes they have advanced features but you don't need those to get off the ground.Nomanomad
How this: ninject.codeplex.com/Wiki/… is considered rocket science is beyond me.Implore
I used structure map and Unity before. You can do the basic very simply (a few lines of code, reading their FAQs), but if you try to shoehorn it into too many situations it gets complex fast.Arabella
I am a fan of IoC containers but in no way do I think they are 'easy to get' (the concepts are quite abstract and go to the heart of software development)... Also I think Joel's answer is going to encourage people to dismiss the important ideas behind IoC hence my downvote.Aton
Also if anyone is writing testable code, following SRP etc (which I think most people agree is good) your class basically always end up with a ton of interfaces dependancies. I ask: without an IoC framework how on earth do you wire up all your classes?Aton
Following IoC without a container is, quite frankly, far more complicated and time consuming than "reading a 200 page manual". Not to mention that the containers came before Mr. Fowler's article and are part and parcel with the design pattern. So, if Mr. Spolsky wanted to claim that IoC was overly complicated, we might have to agree to disagree, but since that's not what he said... he's just plain wrong.Meghan
Joel I used to think the same way as you. Then I literally and seriously spent five minutes to figure out how to get the most basic setup running and was amazed at the 80/20 rule in action. It makes code much cleaner especially in the simple cases.Emission
I've been programming for less than two years and I read the Ninject wiki and got it. I have been using DI in a lot of places since then. Did you see that? Less than two years and reading a few pages on a wiki. I'm not a wizard or anything. I don't consider myself a genius, but it was easy for me to understand. I can't imagine someone who really understands OO not being able to grasp it. Also, what 200-300 page manuals are you referring to? I've never seen those. All of the IoC containers I have used are pretty short and to the point.Cheju
So if you don't use IoC containers, it's because you are not smart enough to understand them, but if you do use IoC containers (and love every second of it) it is because you are too smart?Mousebird
@Joel-spolsky I don't understand why you think it makes the code harder to read. The code is actually simpler to understand. All your dependencies just get injected through the constructors. No tracing of dependencies is necessary. It takes about 2-3 lines of code to setup depending on how many items you need to create.Messalina
I don't know why you guys are questioning Joel. He knows what is going on in our heads, the dude is like Santa Claus or something. He knows we can't understand IoC and more than we can put our pants on in the morning without help. Thank you Joel for reminding me how dumb I am, I was getting way too full of myself.Lynching
Joel - I assume you haven't looked at IoC Containers for a while because a watershed has most certainly passed in the past couple of years. They're now trivial to configure mainly due to conventions. DI is good; make a good practice easier to implement & maintain. Why pass concrete implementations of your code around when a 3rd party library can do it for you? An IoC Container will: manage the entire graph; without having to pepper your classes with poormans DI ctors; reducing lines of code and; centralising your dependency resolution in one succinct place in your code base.Mushro
Joel - Your claim that the main benefit of IoC is swapping out implementations for testing, shows that you don't understand IoC. IoC is about separation of concerns and freeing you from having to re-write all your instantiation chains when you want to add/remove a dependency. Not to mention numerous other benefitsCentiare
I really don't understand how I was convinced to come to the StackOverflow DevDaysUntinged
I need to make an I heart VBA t-shirt for devdaysShawanda
Wow... Geez talk about the backlash. I'm thinking this is some sort of experiment on how not to go against the crowds. Honestly, I haven't been developing full time for too long (almost 3 years now) and I have used 3 different .Net IoC containers. I don't claim to understand everything that they do. But I do know that they have simplified my development. In the same way, I use SQL Server. But I won't claim to understand all the intricacies of a modern RDBMS system.Storms
In Joel's defense, DI and IoC may be very difficult to grasp in Z80 Assembly or when using templates with COM in multi-threaded code.Bowel
+1 well written and thought out. One thing I think a lot of people don't realize is that adding in a framework or such to "magically" handle something automatically adds complexity and limitations to a system. Sometimes it's worth it, but often something gets overlooked and entropy is released into the code trying to fix a problem enforced by limitations. It may save time up front, but people have to realize that may cost 100 fold down the line trying to fix some obscure problem only a handful of people truly have enough knowledge to solve.Florindaflorine
@Ryan Emerle: It seems to me that there is a difference between grokking IoC and believing that an IoC framework should be commonly employed.Vergne
I totally agree with Joel.. seems like an awful lot of navel grazing here when a simpler solution is staring you right in the face. People tend to forget the KISS principle and this is one case where it sorely needs to be applied.Vend
IOC is fine when done correctly, but it's really horrible when someone messes it up, and eventually someone will mess it up. It also can obfuscate exactly what's happening with a bit of code. IMHO it's always better if you can look at a bit of code and get what's going on in a few seconds without digging through the rest of the source.Divebomb
I'm tempted to +1 this just for aggressively expressing the minority opinion, but I will refrain-I think you're partially correct in that IOC containers can make simple things complex, and make the code harder to trace (because so many of the code paths become indirect), but there are other benefits than what you mention, allowing for for a convenient way of scaffolding application resources. You'd have to handle that somewhere. I also don't think they're too complex, but then again I work somewhere where all the IOC is coded backwards(!) so maybe you shouldn't take my word for that.Leeann
You made a great point for small applications. However, the complexity cost of using an IoC container is surmountable in medium to large projects and pays for itself in value.Vernacularism
There are a few commenters that are supporting Joel's argument, citing KISS. The thing these people don't realise is that using and IoC container is the KISS way. KISS stands for "keep it simple, stupid", not "start off simple, end up with a mess, stupid" (SOSEUWMS). An IoC container helps you KEEP your application simple as it grows over time. I'm sure Joel is a fan of SOSEUWMS, because it helps keep bug trackers in high demand.Coerce
It's not that I have trouble believing that there are people who don't understand IoC, it's that I have trouble believing there are people who won't try to understand. Truly, it's not that hard. I think the biggest problem is the name sounds intimidating.Shaeshaef
I am not sure if you have seriously given a try to StructureMap. Please have a look at one of the Rob Connery's Video, you can start using it in 10 mins. No Kidding.!!!Custer
Like in so many situations, your attempt to protect developers from powerful ideas just ends up patronizing them and devaluing their abilities. In order to make your point stick, you must provide an example of an IoC container with a 200 page manual - I simply don't believe there is one! Which makes your contrarian rhetoric that much less palatable. In order to practice IoC/DI, one must learn the problems being solved by these techniques. With that understanding, you can use any tooling, or none. Without it, it doesn't matter what tooling you use.Stylographic
@KevDog: I totally agree about the name problem. Dependency Injection Container totally sounds like something invented by a Dalek.Swung
I use an IOC container and I am not smart.Wonacott
+1 for a sanity check to reduce code complexityBergerac
I am guessing Joel is talking about something like Spring and not Guice. Guice is very simple and doesn't require more than a 15 minute introduction. Spring on the other hand is a more complicated (yet more versatile) beast.Erek
Wow, most controversial post... just because Joel dared suggest that IoC is not the be-all-end-all of development grail. Honestly, enough with the religious wars already! Even IF (big if) IoC is the best thing since sliced butter, even any half-decent programmer with more than a couple weeks real-world experience outside of academia could not believe it is the best solution in all - or even most - situations.Anisette
On the other hand, I consider myself to be quite smart, and while I did spend the time to research and experience enough to grok IoC - I still hate it. With a passion. But that might be just because I spend most of my time actually reading code, not just producing write-only code.... which is where IoC really shines, write a lil bits of code, then combine them and recombine them differently at config time. On the other hand, code readability takes a HUGE hit with IoC.Anisette
If you are dealing with wiring up hundreds+ of components and want a centralised way of managing the dependencies, an IoC container makes life much easier. I was sceptical about using a container because I didn't see the benefits. I'm now convinced that they're useful bits of kit. We swap out huge sections of our object graph construction via configuration and re-use our modules in different contexts (this is something we do extensively, it's not just a speculative pipe dream). The trade-off is unfamiliarity with a new concept and sacrificing some compile time safety.Blavatsky
@Joel did you know this is the most controversial answer on the site? :) data.stackexchange.com/stackoverflow/s/87/…Refutative
@AviD: Actually, where IoC shines is in unit testing - I doubt I would use it if I could test without it, but since DI+mocking is pretty much the only want to test classes in isolation, and that benefit is definitely 100% worth the extra effort, I'm going to have to stick with it for now.Menell
There is some truth to this answer, in that the authors of most articles about DI I've seen seem to have a complete inability to explain the concept with resorting to heaps of jargon. They write explanations of DI for people who already know DI. They don't write for people who don't know DI and need to learn.Xerography
@Kyralessa: see github.com/ninject/ninject/wiki/Dependency-Injection-By-HandMenell
The answer proves that almost the half of so community regards downvote button as "I don't agree", rather than "This answer is not helpful". I hate it whenever I face with the fact that we are just complicated primates.Macnamara
For simple things, use lightweight things. Check this tiny and simple IoC container with support to IoC, DI and Auto-Wiring: mentacontainer.soliveirajr.comDoting
The fact that this answer is the most controversial answer on SE hints at how much of a fad (for good or ill) Ioc/DI has become. I like Joel's answer because he offers a bit of practical wisdom; YAGNI. Certainly some project warrant IoC, as certainly as others do not. It's a good tool to keep on your belt, but don't use a sledge-hammer to hang a picture frame...El
IoCs: hide complexity instead of solving it (that crap constructor in the other answer? it's still there); trade compile time errors for run-time errors; make hard-to-test and hard-to-spot errors possible (errors in component registration); favour god classes ("kernels"). All of these issues are easy to spot in most IoC code. What's troubling is that many people think this is good code.Towpath
XML configuration/ or "dependency injection" work great even in small-size projects. They improve clarity & structure, and (for the first time) enable the long-time claim of OO -- making code reusable -- by separating 'glue code' from the functional code. They also enable software products and per-client configurability to easily swap strategies/implementations/or algorithms.. within the exact same codebase.. by deploying just one changed XML file. For example, a different ShippingCostCalculator.Recusancy
And anybody who doesn't see how clean & powerful this is, should be banished for life to write embedded code for refrigerators :)Recusancy
+1 for "they have trouble understanding that many ordinary programmers will find the concepts confusing". These people usually give ordinary programmers a hell of a time too.Johanajohanan
D
37

Presumably no one is forcing you to use a DI container framework. You're already using DI to decouple your classes and improve testability, so you're getting many of the benefits. In short, you're favoring simplicity, which is generally a good thing.

If your system reaches a level of complexity where manual DI becomes a chore (that is, increases maintenance), weigh that against the team learning curve of a DI container framework.

If you need more control over dependency lifetime management (that is, if you feel the need to implement the Singleton pattern), look at DI containers.

If you use a DI container, use only the features you need. Skip the XML configuration file and configure it in code if that is sufficient. Stick to constructor injection. The basics of Unity or StructureMap can be condensed down to a couple of pages.

There's a great blog post by Mark Seemann on this: When to use a DI Container

Dosser answered 16/5, 2009 at 1:6 Comment(3)
Very good response. The only thing I'd differ in opinion on is whether or not manual injection EVER can be considered less complex or not a chore.Meghan
+1. One of the best answers here. Thanks also for the blog article link.Britannic
+1 for the balanced viewpoint. IoC containers aren't always good, and they're not always bad. If you don't see a need, don't use it. Just know that the tool is there if you do see a need.Subtropical
C
32

IoC Containers are also good for loading deeply nested class dependencies. For example if you had the following code using Depedency Injection.

public void GetPresenter()
{
    var presenter = new CustomerPresenter(new CustomerService(new CustomerRepository(new DB())));
}

class CustomerPresenter
{
    private readonly ICustomerService service;
    public CustomerPresenter(ICustomerService service)
    {
        this.service = service;
    }
}

class CustomerService
{
    private readonly IRespository<Customer> repository;
    public CustomerService(IRespository<Customer> repository)
    {
        this.repository = repository;
    }
}

class CustomerRepository : IRespository<Customer>
{
    private readonly DB db;
    public CustomerRepository(DB db)
    {
        this.db = db;
    }
}

class DB { }

If you had all of these dependencies loaded into and IoC container you could Resolve the CustomerService and the all the child dependencies will automatically get resolved.

For example:

public static IoC
{
   private IUnityContainer _container;
   static IoC()
   {
       InitializeIoC();
   }

   static void InitializeIoC()
   {
      _container = new UnityContainer();
      _container.RegisterType<ICustomerService, CustomerService>();
      _container.RegisterType<IRepository<Customer>, CustomerRepository>();
   }

   static T Resolve<T>()
   {
      return _container.Resolve<T>();
   }
}

public void GetPresenter()
{
   var presenter = IoC.Resolve<CustomerPresenter>();
   // presenter is loaded and all of its nested child dependencies 
   // are automatically injected
   // -
   // Also, note that only the Interfaces need to be registered
   // the concrete types like DB and CustomerPresenter will automatically 
   // resolve.
}
Carincarina answered 16/5, 2009 at 1:6 Comment(2)
But IoC class is called using service locator anti-pattern. Should_container be passed using constructor DI instead of calling static T Resolve<T>() ?Ferland
@Carincarina Your example implies that it automatically passes in the arguments to the constructors for new CustomerService and new CustomerRepository. Is this how this works? What if you have other additional parameters as well?Komi
C
32

In my opinion the number one benefit of an IoC is the ability to centralize the configuration of your dependencies.

If you're currently using Dependency injection your code might look like this

public class CustomerPresenter
{
  public CustomerPresenter() : this(new CustomerView(), new CustomerService())
  {}

  public CustomerPresenter(ICustomerView view, ICustomerService service)
  {
    // init view/service fields
  }
  // readonly view/service fields
}

If you used a static IoC class, as opposed to the, IMHO the more confusing, configuration files, you could have something like this:

public class CustomerPresenter
{
  public CustomerPresenter() : this(IoC.Resolve<ICustomerView>(), IoC.Resolve<ICustomerService>())
  {}

  public CustomerPresenter(ICustomerView view, ICustomerService service)
  {
    // init view/service fields
  }
  // readonly view/service fields
}

Then, your Static IoC class would look like this, I'm using Unity here.

public static IoC
{
   private static readonly IUnityContainer _container;
   static IoC()
   {
     InitializeIoC();
   }

   static void InitializeIoC()
   {
      _container = new UnityContainer();
      _container.RegisterType<ICustomerView, CustomerView>();
      _container.RegisterType<ICustomerService, CustomerService>();
      // all other RegisterTypes and RegisterInstances can go here in one file.
      // one place to change dependencies is good.
   }
}
Carincarina answered 16/5, 2009 at 1:6 Comment(11)
Ben, what you're talking about is really Service Location, not Dependency Injection - there is a difference. I always prefer the first over the latter. stevenharman.net/blog/archive/2009/09/25/…Deception
Instead of doing the IoC.Resolve<T> in your default constructor, you should leverage the IOC container's ability to construct the object for you. Get rid of that empty constructor, and let the IOC container build the object for you. var presenter = IoC.Resolve<CustomerPresenter>(); voila! all dependencies already wired up.Weed
@ben, Agreed! but don't forget the fine point to tuck that Service Location up into some corner of your infrastructure, limiting the use of location to as few places as possible.Deception
The down-side of centralization of this kind of configuration is the de-contextualization of knowledge. Joel points out this problem in saying, "code becomes, frankly, a lot harder to read".Sinistrous
@sbellware I disagree. While some knowledge becomes de-contextualized, it is mostly likely boilerplate code anyway which is merely detracting from the real work your class and methods are trying to get done.Welldisposed
@sbellware, what knowledge? The interface being taken as a primal dependency serves as a contract and should be enough to both convey it's purpose & behavior, no? I suppose you may be referring to knowledge gained from spelunking into the implementation of the contract, in which case you'd need to to track down the appropriate configuration? I rely on a computer (R# in VS, IntelliJ, etc.) for that as they are great at navigating nodes & edges of a graph; I reserve my brain's stack for the context of the work site I'm currently focused on.Deception
Steve, I know the .NET text and walked that walk for many years. I also have intimate familiarity with other modes and forms, and I understand viscerally that there are real tradeoffs. I know how and when to make those tradeoffs, but the diversity in my work life at least lets me tangibly understand Joel's perspective. Rather than lecture me on tools and tricks that I've been using for longer than most .NET mono-culturists, tell me something I don't know. I reserve my brain's stack for diverse, critical thinking rather than alt.net stasis and orthodoxy.Sinistrous
Jesse, "boilerplate" is a perspective. I'm not passing judgments on that perspective, but to say that it's just a perspective.Sinistrous
Scott, I get Joel's point; there is a loss of contextual knowledge when the configuration happens, well... outside the context of its use. And I wasn't trying to lecture on tools nor tricks to work around that tradeoff. Rather, I was observing that w/in the context of certain architectural constraints (in this case: .NET, JAVA, or any other language that requires a container) why not lean on the tools to do that type of work, when you can? I should have been more clear about the context under which I was making that statement.Deception
Agree with the centralized approach. Spreading configuration around is bad, but that's my personal preference. That's why I prefer programmatic configuration over XML and Annotations. Take a look on the configuration approach done here: mentacontainer.soliveirajr.comDoting
The Service Locator pattern (as described here) is actually considered an anti-pattern by some, e.g. something which should not be followed. I must say I agree with them. Service Locator is bad, proper Dependency Injection is much beter.Knowles
S
28

I'm a fan of declarative programming (look at how many SQL questions I answer), but the IoC containers I've looked at seem too arcane for their own good.

...or perhaps the developers of IoC containers are incapable of writing clear documentation.

...or else both are true to one degree or another.

I don't think the concept of an IoC container is bad. But the implementation has to be both powerful (that is, flexible) enough to be useful in a wide variety of applications, yet simple and easily understood.

It's probably six of one and half a dozen of the other. A real application (not a toy or demo) is bound to be complex, accounting for many corner cases and exceptions-to-the-rules. Either you encapsulate that complexity in imperative code, or else in declarative code. But you have to represent it somewhere.

Swung answered 16/5, 2009 at 1:6 Comment(4)
I like your observation about the unavoidable presence of complexity. The difference between container-based and manual dependency wiring is that using a container, you can focus on each component individually, and thus manage increasing complexity in a fairly linear way. Systems with manual dependency wiring are more challenging to evolve, since the act of configuring one component is hard to isolate from the configuring of everything else.Sacral
I like AspectJ. It's not Java, but it's not XML either. It sort of IS Java, in that it feels and looks like Java by being an extension of it. I'd rather keep my aspects out of my POJOs and in my business logic. I'd almost like to keep my IoCs out as well. There's entirely too much XML in wiring up tools, IMHO. If I have to have configuration files, let them be BeanShell scripts. /Java, apply your .Net workalikes here -> .Farseeing
I certainly understand your answer, but I think a large part of the problem is that a lot of the IoC frameworks (and, really, a lot of the other frameworks for other things too) are described and documented for others already very familiar with the requisite concepts and terminology. I'm learning about a lot of this having just inherited another programmer's code. I'm struggling to understand why the code is using IoC when the 'object graphs' are fairly small and there's no real test coverage of the code. As a SQL programmer, you can probably better appreciate using IoC with an ORM.Hyperkeratosis
@KennyEvitt, good point, it would seem premature to use an IoC framework if one has a simple app and haven't even bothered to have good test coverage.Swung
P
27

Using a container is mostly about changing from an imperative/scripted style of initialization and configuration to a declarative one. This may have a few different beneficial effects:

  • Reducing hairball main-program startup routines.
  • Enabling fairly deep deployment-time reconfiguration capabilities.
  • Making dependency-injectable style the path of least resistance for new work.

Of course, there may be difficulties:

  • Code that requires complex startup/shutdown/lifecycle management may not be easily adapted to a container.
  • You will probably have to navigate any personal, process and team culture issues -- but then, that's why you asked...
  • Some of the toolkits are fast becoming heavyweight themselves, encouraging the sort of deep dependency that many DI containers started off as a backlash against.
Presumption answered 16/5, 2009 at 1:6 Comment(0)
I
23

It sounds to me like you already built your own IoC container (using the various patterns which were described by Martin Fowler) and are asking why someone else's implementation is better than yours.

So, you have a bunch of code that already works. And are wondering why you would want to replace it with someone else's implementation.

Pros for considering a third-party IoC container

  • You get bugs fixed for free
  • The library design may be better than yours
  • People may be already familiar with the particular library
  • The library may be faster than yours
  • It may have some features you wish you implemented but never had time to (do you have a service locater?)

Cons

  • You get bugs introduced, for free :)
  • The library design may be worse than yours
  • You have to learn a new API
  • Too many features you will never use
  • It's usually harder to debug code you did not write
  • Migrating from a previous IoC container may be tedious

So, weigh your pros against your cons and make a decision.

Implore answered 16/5, 2009 at 1:6 Comment(2)
I agree with you Sam - DI is a type of IoC, so if the original poster is doing DI, they're already doing IoC so ther real question is why roll your own.Susie
I disagree. IOC is a way of doing DI. IOC Containers do DI by taking control of type instantiation using dynamic runtime reflection to satisfy and inject dependencies. The OP is suggesting he's doing static DI and is pondering at why he needs to trade off the benefits of compile time checking for the benefits often associated with IOC's dynamic runtime reflection.Pico
A
17

I think most of the value of an IoC is garnered by using DI. Since you are already doing that, the rest of the benefit is incremental.

The value you get will depend on the type of application you are working on:

  • For multi-tenant, the IoC container can take care of some of the infrastructure code for loading different client resources. When you need a component that is client specific, use a custom selector to do handle the logic and don't worry about it from your client code. You can certainly build this yourself but here's an example of how an IoC can help.

  • With many points of extensibility, the IoC can be used to load components from configuration. This is a common thing to build but tools are provided by the container.

  • If you want to use AOP for some cross-cutting concerns, the IoC provides hooks to intercept method invocations. This is less commonly done ad-hoc on projects but the IoC makes it easier.

I've written functionality like this before but if I need any of these features now I would rather use a pre-built and tested tool if it fits my architecture.

As mentioned by others, you can also centrally configure which classes you want to use. Although this can be a good thing, it comes at a cost of misdirection and complication. The core components for most applications aren't replaced much so the trade-off is a little harder to make.

I use an IoC container and appreciate the functionality but have to admit that I've noticed the trade-off: My code becomes more clear at the class level and less clear at the application level (i.e. visualizing control flow).

Armillda answered 16/5, 2009 at 1:6 Comment(0)
P
16

I'm a recovering IOC addict. I'm finding it hard to justify using IOC for DI in most cases these days. IOC containers sacrifice compile time checking and supposedly in return give you "easy" setup, complex lifetime management and on the fly discovering of dependencies at run time. I find the loss of compile time checking and resulting run time magic/exceptions, is not worth the bells and whistles in the vast majority of cases. In large enterprise applications they can make it very difficult to follow what is going on.

I don't buy the centralization argument because you can centralize static setup very easily as well by using an abstract factory for your application and religiously deferring object creation to the abstract factory i.e. do proper DI.

Why not do static magic-free DI like this:

interface IServiceA { }
interface IServiceB { }
class ServiceA : IServiceA { }
class ServiceB : IServiceB { }

class StubServiceA : IServiceA { }
class StubServiceB : IServiceB { }

interface IRoot { IMiddle Middle { get; set; } }
interface IMiddle { ILeaf Leaf { get; set; } }
interface ILeaf { }

class Root : IRoot
{
    public IMiddle Middle { get; set; }

    public Root(IMiddle middle)
    {
        Middle = middle;
    }

}

class Middle : IMiddle
{
    public ILeaf Leaf { get; set; }

    public Middle(ILeaf leaf)
    {
        Leaf = leaf;
    }
}

class Leaf : ILeaf
{
    IServiceA ServiceA { get; set; }
    IServiceB ServiceB { get; set; }

    public Leaf(IServiceA serviceA, IServiceB serviceB)
    {
        ServiceA = serviceA;
        ServiceB = serviceB;
    }
}


interface IApplicationFactory
{
    IRoot CreateRoot();
}

abstract class ApplicationAbstractFactory : IApplicationFactory
{
    protected abstract IServiceA ServiceA { get; }
    protected abstract IServiceB ServiceB { get; }

    protected IMiddle CreateMiddle()
    {
        return new Middle(CreateLeaf());
    }

    protected ILeaf CreateLeaf()
    {
        return new Leaf(ServiceA,ServiceB);
    }


    public IRoot CreateRoot()
    {
        return new Root(CreateMiddle());
    }
}

class ProductionApplication : ApplicationAbstractFactory
{
    protected override IServiceA ServiceA
    {
        get { return new ServiceA(); }
    }

    protected override IServiceB ServiceB
    {
        get { return new ServiceB(); }
    }
}

class FunctionalTestsApplication : ApplicationAbstractFactory
{
    protected override IServiceA ServiceA
    {
        get { return new StubServiceA(); }
    }

    protected override IServiceB ServiceB
    {
        get { return new StubServiceB(); }
    }
}


namespace ConsoleApplication5
{
    class Program
    {
        static void Main(string[] args)
        {
            var factory = new ProductionApplication();
            var root = factory.CreateRoot();

        }
    }

    //[TestFixture]
    class FunctionalTests
    {
        //[Test]
        public void Test()
        {
            var factory = new FunctionalTestsApplication();
            var root = factory.CreateRoot();
        }
    }
}

Your container configuration is your abstract factory implementation, your registrations are implementations of abstract members. If you need a new singleton dependency, just add another abstract property to the abstract factory. If you need a transient dependency, just add another method and inject it as a Func<>.

Advantages:

  • All setup and object creation configuration is centralized .
  • Configuration is just code
  • Compile time checking makes it easy to maintain as you cannot forget to update your registrations.
  • No run-time reflection magic

I recommend sceptics to give it a go next green field project and honestly ask yourself at which point you need the container. It's easy to factor in an IOC container later on as you're just replacing a factory implementation with a IOC Container configuration module.

Pico answered 16/5, 2009 at 1:6 Comment(3)
This doesn't seem to me like an argument against IoC, but an argument against configurable IoC frameworks. Don't your factories here just boil down to simple hard-coded IoCs?Warfourd
I think when the poster mentioned IoC an IoC container framework was meant. Thanks for the original writeup this helps convince me to go without a framework. So if it's configurable in tests and in production code what's the advantage of a "configurable" framework?Claudell
From my understanding of the terminology, Inversion Of Control means finding dependencies at run-time. So yes, you could say the factory is basically a hard-coded or static container, but it's not an IOC container. Types are resolved at compile time. It's an argument against using configurable frameworks that use dictionary lookups to resolve types at runtime.Pico
M
14

IoC frameworks are excellent if you want to...

  • ...throw away type safety. Many (all?) IoC frameworks forces you to execute the code if you want to be certain everything is hooked up correctly. "Hey! Hope I got everything set up so my initializations of these 100 classes won't fail in production, throwing null-pointer exceptions!"

  • ...litter your code with globals (IoC frameworks are all about changing global states).

  • ...write crappy code with unclear dependencies that's hard to refactor since you'll never know what depends on what.

The problem with IoC is that the people who uses them used to write code like this

public class Foo {
    public Bar Apa {get;set;}
    Foo() {
        Apa = new Bar();
    }
}

which is obviously flawed since the dependency between Foo and Bar is hard-wired. Then they realized it would be better to write code like

public class Foo {
    public IBar Apa {get;set;}
    Foo() {
        Apa = IoC<IBar>();
    }
}

which is also flawed, but less obviously so. In Haskell the type of Foo() would be IO Foo but you really don't want the IO-part and is should be a warning sign that something is wrong with your design if you got it.

To get rid of it (the IO-part), get all advantages of IoC-frameworks and none of it's drawbacks you could instead use an abstract factory.

The correct solution would be something like

data Foo = Foo { apa :: Bar }

or maybe

data Foo = forall b. (IBar b) => Foo { apa :: b }

and inject (but I wouldn't call it inject) Bar.

Also: see this video with Erik Meijer (inventor of LINQ) where he says that DI is for people who don't know math (and I couldn't agree more): http://www.youtube.com/watch?v=8Mttjyf-8P4

Unlike Mr. Spolsky I don't believe that people who use IoC-frameworks are very smart - I simply believe they don't know math.

Mellins answered 16/5, 2009 at 1:6 Comment(8)
throw away type safety - except your example is still type safe, that's what the interface is. You're not passing around types of object, but the interface type. And type safety doesn't do away with null reference exceptions anyway, you can happy pass null references as type safe parameters - that's not a type safety issue at all.Iconostasis
You throw away type safety since you don't know if the type is wired up or not in the IoC-container (the type of IoC<IBar> is not IBar, it is in fact IO IBar).. And yes, in the Haskell-example I can't get a null-reference.Mellins
Type safety not really about an object being wired up, at least not in Java/C#, it's simply about the object being of the right type. And ConcreteClass myClass = null is still of the right type. If you want to enforce not null then code contracts come into play.Iconostasis
Sure, null-pointers can exist in c#/java without IoC but you wouldn't write foo = null; foo.ToString() but that's what you can get with IoC-frameworks. ToString demands an object, which is another type than "maybe an object". Just because c#/java/javascript doesn't make a distinction compile-time between Object and Maybe Object doesn't mean that there is no difference (i.e. there is a difference). Thus you'll get less type safety when using IoC-frameworks. That aside I think that less type safety is a secondary problem compared to the globals that IoC introduce.Mellins
I agree with your 1st point to some extent, I'd like some explanation of 2nd and the 3rd has never been a problem for me. Your C# sample uses the IoC container as a service locator, a common mistake. And comparing C# vs Haskell = apples vs oranges.Guerin
obviously you're confused about what's DI and what's Service Locator Pattern..Stopple
You don't throw away type-safety. Some (if not most) DI containers allow you to verify the complete object graph after the registration process. When doing this you can prevent the application from starting on a misconfiguration (fail fast) and my applications always have a few unit tests that call the production configuration to allow me to find these errors during testing. I would advice everyone using an IoC container to write a few unit tests that make sure all top-level objects can be resolved.Mump
You are all in violent agreement. When the author refers to "throwing away type safety" he means that IoC container configuration problems cannot be detected by the compiler. Instead, errors can only be detected at runtime, "IoC frameworks forces you to execute the code if you want to be certain everything is hooked up correctly". "verify[ing] the complete object graph after the registration process" may be useful, but it is not type safety.Rustle
S
14

The biggest benefit of using IoC containers for me (personally, I use Ninject) has been to eliminate the passing around of settings and other sorts of global state objects.

I don't program for the web, mine is a console application and in many places deep in the object tree I need to have access to the settings or metadata specified by the user that are created on a completely separate branch of the object tree. With IoC I simply tell Ninject to treat the Settings as a singleton (because there is always only one instance of them), request the Settings or Dictionary in the constructor and presto ... they magically appear when I need them!

Without using an IoC container I would have to pass the settings and/or metadata down through 2, 3, ..., n objects before it was actually used by the object that needed it.

There are many other benefits to DI/IoC containers as other people have detailed here and moving from the idea of creating objects to requesting objects can be mind-bending, but using DI was very helpful for me and my team so maybe you can add it to your arsenal!

Staley answered 16/5, 2009 at 1:6 Comment(14)
This is a huge plus. Can't believe no one else has mentioned it prior. Without the need of passing or storing tempoary objects makes code much cleaner.Hintz
"they magically appear when I need them!" - I can tell you a little secret - just use global objects, and they magically appear when you need them, without any iocc bloat!Syst
@Syst global objects work great ... if you want your code base to be a tightly coupled, un-testable nightmare that gets harder and harder to modify over time. good luck with that.Staley
@JeffreyCameron IoC Container is global object. It doesn't remove your global dependencies.Syst
True, however the IoC container is transparent to the rest of the application. You call it once at startup to get an instance and then that's the last you see of it. With global objects your code is littered with hard dependenciesStaley
@Syst if your IoC container is literally a global object and your project is littered with references to it, you are using it wrong. As Jeffrey says, if you have any references beyond configuration and using it to request an instance at startup, you are doing it wrong.Warfourd
@JeffreyCameron, "You call it once at startup to get an instance and then that's the last you see of it." - how would you create object instances without ioc-container?Syst
@Syst use factories to create transient instances on the fly. The factories are singleton services. If the transient instances need something from the IOC container then wire them into the factory and get the factory to pass the dependency into the transient instance.Staley
XML configuration & IoC really is simpler, cleaner & better. When you have a real software product with more than one client, you can swap out strategies/algorithms within the exact same codebase by deploying just one changed XML file. Access to services or settings is greatly simplified, and for the first time in OO history you can actually directly reuse your code on other projects because it's no longer all stuck together with hard-wired glue.Recusancy
@Thomas I would argue that your implementation is an anti-pattern. Your configuration should be selectable through properties that are set, either by the user when they start the application or by the person deploying an application to the environment. In either case, the configuration should remain the same but how it gets configured is what differs. If that is the case then your configuration is static and it doesn't matter if it is in XML or Code. Code, however, is refactorable while XML is not. This explains my preference for configuring in code.Staley
XML configuration was definitely cleaner, more elegant & enabled reuse in an extremely powerful way. That is absolutely not an anti-pattern.Recusancy
@Thomas Perhaps I wasn't clear enough. I wasn't arguing that XML configuration was an anti-pattern. Rather, having to adjust your XML file to deploy to a new environment was an anti-pattern. We use XML config as well but the things that can change per environment are selected through properties files. The point being if you use properties files then it doesn't matter if you use XML or code configuration. If it doesn't matter then why not go for the easy refactoring and type safety of code configuration?Staley
I use properties for that! Properties for server & deployment settings, XML for the structure of the application and to clean the codebase & enable reusability by removing the need for glue, init-dependencies & manually implemented configuration in the codebase.Recusancy
If you are passing references down object trees, you are not doing dependency injection. You can avoid this needles passing without going for an IOC container, by not having normal objects create other objects. Only factories are allowed to create objects , which you pass in via the constructor. At the root of your program you create the factories and services and construct your object hierarchy. No unnecessary passing this way.Pico
M
10

I've found that correctly implementing Dependency Injection tends to force programmers to use a variety of other programming practices that help to improve the testability, flexibility, maintainability, and scalability of code: practices like the Single Responsibility Principle, Separations of Concerns, and coding against APIs. It feels like I'm being compelled to write more modular, bite-sized classes and methods, which makes the code easier to read, because it can be taken in bite-sized chunks.

But it also tends to create rather large dependency trees, which are far more easily managed via a framework (especially if you use conventions) than by hand. Today I wanted to test something really quickly in LINQPad, and I figured it'd be too much bother to create a kernel and load in my modules, and I ended up writing this by hand:

var merger = new SimpleWorkflowInstanceMerger(
    new BitFactoryLog(typeof(SimpleWorkflowInstanceMerger).FullName), 
    new WorkflowAnswerRowUtil(
        new WorkflowFieldAnswerEntMapper(),
        new ActivityFormFieldDisplayInfoEntMapper(),
        new FieldEntMapper()),
    new AnswerRowMergeInfoRepository());

In retrospect, it would have been quicker to use the IoC framework, since the modules define pretty much all of this stuff by convention.

Having spent some time studying the answers and comments on this question, I am convinced that the people who are opposed to using an IoC container aren't practicing true dependency injection. The examples I've seen are of practices that are commonly confused with dependency injection. Some people are complaining about difficulty "reading" the code. If done correctly, the vast majority of your code should be identical when using DI by hand as when using an IoC container. The difference should reside entirely in a few "launching points" within the application.

In other words, if you don't like IoC containers, you probably aren't doing Dependency Injection the way it's supposed to be done.

Another point: Dependency Injection really can't be done by hand if you use reflection anywhere. While I hate what reflection does to code navigation, you have to recognize that there are certain areas where it really can't be avoided. ASP.NET MVC, for example, attempts to instantiate the controller via reflection on each request. To do dependency injection by hand, you would have to make every controller a "context root," like so:

public class MyController : Controller
{
    private readonly ISimpleWorkflowInstanceMerger _simpleMerger;
    public MyController()
    {
        _simpleMerger = new SimpleWorkflowInstanceMerger(
            new BitFactoryLog(typeof(SimpleWorkflowInstanceMerger).FullName), 
            new WorkflowAnswerRowUtil(
                new WorkflowFieldAnswerEntMapper(),
                new ActivityFormFieldDisplayInfoEntMapper(),
                new FieldEntMapper()),
            new AnswerRowMergeInfoRepository())
    }
    ...
}

Now compare this with allowing a DI framework to do it for you:

public MyController : Controller
{
    private readonly ISimpleWorkflowInstanceMerger _simpleMerger;
    public MyController(ISimpleWorkflowInstanceMerger simpleMerger)
    {
        _simpleMerger = simpleMerger;
    }
    ...
}

Using a DI framework, note that:

  • I can unit-test this class. By creating a mock ISimpleWorkflowInstanceMerger, I can test that it gets used the way I anticipate, without the need for a database connection or anything.
  • I use far less code, and the code is much easier to read.
  • If one of my dependency's dependency's changes, I don't have to make any changes to the controller. This is especially nice when you consider that multiple controllers are likely to use some of the same dependencies.
  • I never explicitly reference classes from my data layer. My web application can just include a reference to the project containing the ISimpleWorkflowInstanceMerger interface. This allows me to break the application up into separate modules, and maintain a true multi-tier architecture, which in turn makes things much more flexible.

A typical web application will have quite a few controllers. All of the pain of doing DI by hand in each controller will really add up as your application grows. If you have an application with only one context root, which never tries to instantiate a service by reflection, then this isn't as big a problem. Nevertheless, any application that uses Dependency Injection will become extremely expensive to manage once it reaches a certain size, unless you use a framework of some kind to manage the dependency graph.

Microclimatology answered 16/5, 2009 at 1:6 Comment(0)
H
9

Whenever you use the "new" keyword, you are creating a concrete class dependency and a little alarm bell should go off in your head. It becomes harder to test this object in isolation. The solution is to program to interfaces and inject the dependency so that the object can be unit tested with anything that implements that interface (eg. mocks).

The trouble is you have to construct objects somewhere. A Factory pattern is one way to shift the coupling out of your POXOs (Plain Old "insert your OO language here" Objects). If you and your co-workers are all writing code like this then an IoC container is the next "Incremental Improvement" you can make to your codebase. It'll shift all that nasty Factory boilerplate code out of your clean objects and business logic. They'll get it and love it. Heck, give a company talk on why you love it and get everyone enthused.

If your co-workers aren't doing DI yet, then I'd suggest you focus on that first. Spread the word on how to write clean code that is easily testable. Clean DI code is the hard part, once you're there, shifting the object wiring logic from Factory classes to an IoC container should be relatively trivial.

Hypogeal answered 16/5, 2009 at 1:6 Comment(0)
U
8

Because all the dependencies are clearly visible, it promotes creating components which are loosely coupled and at the same time easily accessible and reusable across the application.

Underpinning answered 16/5, 2009 at 1:6 Comment(0)
K
7

You don't need an IoC container.

But if you're rigorously following a DI pattern, you'll find that having one will remove a ton of redundant, boring code.

That's often the best time to use a library/framework, anyway - when you understand what it's doing and could do it without the library.

Kristoferkristoffer answered 16/5, 2009 at 1:6 Comment(0)
J
6

I just so happen to be in the process of yanking out home grown DI code and replacing it with an IOC. I have probably removed well over 200 lines of code and replaced it with about 10. Yes, I had to do a little bit of learning on how to use the container (Winsor), but I'm an engineer working on internet technologies in the 21st century so I'm used to that. I probably spent about 20 minutes looking over the how tos. This was well worth my time.

Jillayne answered 16/5, 2009 at 1:6 Comment(1)
"but I'm an engineer working on internet technologies in the 21st century so I'm used to that" -> +1Jersey
C
5

As you continue to decouple your classes and invert your dependencies, the classes continue to stay small and the "dependency graph" continues to grow in size. (This isn't bad.) Using basic features of an IoC container makes wiring up all these objects trivial, but doing it manually can get very burdensome. For example, what if I want to create a new instance of "Foo" but it needs a "Bar". And a "Bar" needs an "A", "B", and "C". And each of those need 3 other things, etc etc. (yes, I can't come up with good fake names :) ).

Using an IoC container to build your object graph for you reduces complexity a ton and pushes it out into one-time configuration. I simply say "create me a 'Foo'" and it figures out what's needed to build one.

Some people use the IoC containers for much more infrastructure, which is fine for advanced scenarios but in those cases I agree it can obfuscate and make code hard to read and debug for new devs.

Consider answered 16/5, 2009 at 1:6 Comment(2)
why do we continue to appease the lowest common denominator rather than work to pull them up?Deception
I didn't say anything about appeasing. I just said the advanced scenarios can make things more obfuscated for new devs - this is a fact. I didn't say "so don't do it". But even then (time for devil's advocate) there are often other ways to accomplish the same thing that make a codebase more explicit and approachable. Hiding complexity in your infrastructure tool custom configuration just because you can isn't the right reason, and it pulls nobody up.Consider
A
4

Dittos about Unity. Get too big, and you can hear the creaking in the rafters.

It never surprises me when folks start to spout off about how clean IoC code looks are the same sorts of folks who at one time spoke about how templates in C++ were the elegant way to go back in the 90's, yet nowadays will decry them as arcane. Bah !

Analgesia answered 16/5, 2009 at 1:6 Comment(0)
P
2

So, it's been almost 3 years, eh?

  1. 50% of those who commented in favor of IoC frameworks don't understand the difference between IoC and IoC Frameworks. I doubt they know that you can write code without being deployed to an app server

  2. If we take most popular Java Spring framework, it is IoC configuration moved from XMl into the code and now look like this

`@Configuration public class AppConfig {

public @Bean TransferService transferService() {
    return new TransferServiceImpl(accountRepository());
}

public @Bean AccountRepository accountRepository() {
    return new InMemoryAccountRepository();
}

} ` And we need a framework to do this why exactly?

Portmanteau answered 16/5, 2009 at 1:6 Comment(0)
A
2

In the .NET world AOP isn't too popular, so for DI a framework is your only real option, whether you write one yourself or use another framework.

If you used AOP you can inject when you compile your application, which is more common in Java.

There are many benefits to DI, such as reduced coupling so unit testing is easier, but how will you implement it? Do you want to use reflection to do it yourself?

Axinomancy answered 16/5, 2009 at 1:6 Comment(2)
The new MEF framework allows just this for .NET and I must say the code is cleaner and easier to understand, makes it a lot easier to understand the DI concept.Sonorous
@TT: MEF is not a dependency injection container and has nothing to do with AOP.Guerin
E
1

I will try to find why IOC might not be good for from my perspective.

As with everything else, IOC container (or as Einstein would put it I=OC^2) is a concept you have to decide for yourself if you need it or not in your code. Recent fashion outcry about IOC is only that, fashion. Don't fall for fashion, that is first. There are myriads of concepts out there you could implement in your code. First of all, I am using dependency injection since I have started programming, and learned the term itself when it was popularized under that name. Dependency control is a very old subject and it was addressed so far in trillions of ways, depending on what was decoupling from what. Decoupling everything from everything is a nonsense. The problem with IOC container is that it tries to be as useful as Entity Framework or NHibernate. While writing an object-relational mapper is simply a must as soon as you have to couple any database with your system, IOC container is not always necessary. So when IOC container is useful:

  1. When you have a situation with many dependencies you want to organize
  2. When you do not care about coupling your code with third-party product
  3. When your developers want to learn how to work with a new tool

1: It is not that often that you have so many dependencies in your code, or that you are aware of them early in design. Abstract thinking is useful when abstract thinking is due.

2: Coupling your code with third-party code is a HuGe problem. I was working with code that is 10+ years old and that was following at that time fancy and advanced concepts ATL, COM, COM+ and so on. There is nothing you can do with that code now. What I am saying is that an advanced concept gives an apparent advantage, yet this is cancelled on long run with the outdated advantage itself. It just had made all of it more expensive.

3: Software development is hard enough. You can extend it to unrecognizable levels if you allow some advanced concept to crop into your code. There is a problem with IOC2. Although it is decoupling dependencies, it is decoupling the logic flow as well. Imagine you have found a bug and you need to set a break to examine the situation. IOC2, as any other advanced concept, is making that more difficult. Fixing a bug within a concept is more difficult than fixing a bug in a plainer code, because when you fix a bug a concept must be obeyed again. (Just to give you an example, C++ .NET is constantly changing the syntax so much that you need to think hard before you refactor some older version of .NET.) So what is the problem with IOC? The problem is in resolving dependencies. The logic for resolving is commonly hidden in the IOC2 itself, written maybe in uncommon way that you need to learn and maintain. Will your third-party product be there in 5 years? Microsoft's was not.

"We know how" syndrome is written all over the place regarding IOC2. This is similar to automation testing. Fancy term and perfect solution at first glance, you simply put all your tests to execute over night and see the results in the morning. It is really painful to explain company after company what automated testing really means. Automated testing is definitely not a quick way of reducing the number of bugs which you can introduce overnight to increase the quality of your product. But, fashion is making that notion annoyingly dominant. IOC2 suffers the same syndrome. It is believed that you need to implement it in order your software to be good. EvErY recent interview I was asked if I am implementing IOC2 and automation. That is a sign of fashion: the company had some part of code written in MFC they will not abandon.

You need to learn IOC2 as any other concept in software. The decision if IOC2 needs to be used is within the team and the company. However, at least ALL above arguments must be mentioned before the decision is made. Only if you see that plus side outweighs negative side, you can make a positive decision.

There is nothing wrong with IOC2 except that it does solve only the problems it solves and introduces the problems it introduces. Nothing else. However, going against the fashion is very difficult, they have sweat mouth, the followers of anything. It is strange how none of them is there when the problem with their fanciness becomes apparent. Many concepts in software industry have been defended because they create profit, books are written, conferences held, new products made. That is fashion, usually short lived. As soon as people find something else they abandon it completely. IOC2 is useful but it shows the same signs as many other vanished concepts I have seen. I do not know if it will survive. There is no rule for that. You think if it is useful, it will survive. No, it does not go that way. One big rich company is enough and the concept can die within few weeks. We'll see. NHibernate survived, EF came second. Maybe IOC2 will survive too. Do not forget that most concepts in software development are about nothing special, they are very logical, simple and obvious, and sometimes it is more difficult to remember the current naming convention than to understand the concept itself. Does the knowledge of IOC2 make a developer a better developer? No, because if a developer was not able to come up with a concept similar in nature to IOC2 then it will be difficult for him or her to understand which problem IOC2 is solving, using it will look artificial and he or she may start using it for sake of being some sort of politically correct.

Eberhart answered 16/5, 2009 at 1:6 Comment(0)
B
1

Here is why. The project is called IOC-with-Ninject. You can download and run it with Visual Studio. This example uses Ninject but ALL the 'new' statements are in one location and you can completely change how your application runs by changing which bind module to use. The example is set up so you can bind to a mocked version of the services or the real version. In small projects that may not matter, but in big projects it's a big deal.

Just to be clear, advantages as I see them: 1) ALL new statements in one location at root of code. 2) Totally re-factor code with one change. 3) Extra points for 'cool factor' 'cause it's... well: cool. :p

Ballyhoo answered 16/5, 2009 at 1:6 Comment(0)
O
1

You would need an IoC container if you needed to centralize the configuration of your dependencies so that they may be easily swapped out en mass. This makes the most sense in TDD, where many dependencies are swapped out, but where there is little interdependence between the dependencies. This is done at the cost of obfuscating the flow of control of object construction to some degree, so having a well organized and reasonably documented configuration is important. It is also good to have a reason to do this, otherwise, it is mere abstraction gold-plating. I have seen it done so poorly that it was dragged down to being the equivalent to a goto statement for constructors.

Ocasio answered 16/5, 2009 at 1:6 Comment(0)
R
1

Honestly I don't find there to be many cases where IoC containers are needed, and most of the time, they just add unneeded complexity.

If you are using it just for making construction of an object simpler, I'd have to ask, are you instantiating this object in more than one location? Would a singleton not suit your needs? Are you changing the configuration at runtime? (Switching data source types, etc).

If yes, then you might need an IoC container. If not, then you're just moving the initialization away from where the developer can easily see it.

Who said that an interface is better than inheritance anyway? Say you're testing a Service. Why not use constructor DI, and create mocks of the dependencies using inheritance? Most services I use only have a few dependencies. Doing unit testing this way prevents maintaining a ton of useless interfaces and means you don't have to use Resharper to quickly find the declaration of a method.

I believe that for most implementations, saying that IoC Containers remove unneeded code is a myth.

First, there's setting up the container in the first place. Then you still have to define each object that needs to be initialized. So you don't save code in initialization, you move it (unless your object is used more than once. Is it better as a Singleton?). Then, for each object you've initialized in this way, you have to create and maintain an interface.

Anyone have any thoughts on this?

Reposit answered 16/5, 2009 at 1:6 Comment(3)
Even for small projects, putting the configuration in XML makes it so much cleaner & more modular -- and for the first time, makes code reusable (since it's no longer contaminated with glue). For proper software products, you can configure or swap for example ShippingCostCalculator or ProductUIPresentation, or any other strategy/implementation, within the exact same codebase, by deploying just one changed XML file.Recusancy
If it's implemented willy-nilly, as a general practice, I think you add more complexity, not less. When you need to swap something at runtime, they're great, but why add the obfuscation? Why keep the overhead of the extra interfaces for things that will never be switched out? I'm not saying don't use IoC for testing. By all means, use property or even constructor dependency injection. Do you need to use an interface? Why not subclass your test objects? Wouldn't that be cleaner?Reposit
You don't need interfaces at all, to do XML configuration/ IoC. I found great improvements in clarity in a small project with only ~8 pages and 5 or 6 services. There's less obfuscation since services & controllers no longer need glue code.Recusancy
T
0

I realize this is a rather old post, but it seems to still be reasonably active, and I thought I'd contribute a couple of points that have not yet been mentioned in other answers.

I will say that I agree with the benefits of dependency injection, but I do prefer to construct and manage the objects myself, using a pattern not unlike that outlined by Maxm007 in his answer. I have found two main problems with using 3rd party containers:

1) Having a 3rd party library manage the lifetime of your objects "automagically" can lend itself to unexpected results. We have found that especially in large projects, you can have vastly more copies of an object than you expect, and more than you would if you were manually managing the lifecycles. I'm sure this varies depending on the framework used, but the problem exists nonetheless. This can also be problematic if your object holds resources, data connections, etc., since the object can sometimes live longer than you expect. So inevitably, IoC containers tend to increase the resource utilization and memory footprint of an application.

2) IoC containers, in my opinion, are a form of "black box programming". I have found that in particular, our less experienced developers tend to abuse them. It allows the programmer to not have to think about how objects should relate to each other or how to decouple them, because it provides them with a mechanism in which they can simply grab any object they want out of thin air. Eg, there may be a good design reason that ObjectA should never know about ObjectB directly, but rather than creating a factory or bridge or service locator, an inexperienced programmer will simply say "no problem, I'll just grab ObjectB from the IoC container". This can actually lead to increased object coupling, which is what IoC is supposed to help prevent.

Threnody answered 16/5, 2009 at 1:6 Comment(0)
N
0

you do not need a framework to achieve dependency injection. You can do this by core java concepts as well. http://en.wikipedia.org/wiki/Dependency_injection#Code_illustration_using_Java

Narcosis answered 16/5, 2009 at 1:6 Comment(0)
M
0

IOC CONTAINER SOLVES A PROBLEM YOU MIGHT NOT HAVE BUT IT'S A NICE PROBLEM TO HAVE

http://kozmic.net/2012/10/23/ioc-container-solves-a-problem-you-might-not-have-but-its-a-nice-problem-to-have/

Mailand answered 16/5, 2009 at 1:6 Comment(0)
C
0

Personally, I use IoC as some sort of structure map of my application (Yeah, I also prefer StructureMap ;) ). It makes it easy to substitute my ussual interface implementations with Moq implementations during tests. Creating a test setup can be as easy as making a new init-call to my IoC-framework, substituting whichever class is my test-boundary with a mock.

This is probably not what IoC is there for, but it's what I find myself using it for the most..

Capital answered 16/5, 2009 at 1:6 Comment(0)
T
-8

Dependency Injection in an ASP.NET project can be accomplished with a few lines of code. I suppose there is some advantage to using a container when you have an app that uses multiple front ends and needs unit tests.

Tunnel answered 16/5, 2009 at 1:6 Comment(1)
can you give an example? How is DI different in ASP.NET as compared to any other application type?Interaction

© 2022 - 2024 — McMap. All rights reserved.