What are the benefits of dependency injection containers?

For myself one of the main reasons to use an IoC (and make use of external configuration) is around the two areas of:

  • Testing
  • Production maintenance

Testing

If you split your testing into 3 scenarios (which is fairly normal in large scale development):

  1. Unit testing
  2. Integration testing
  3. Black box testing

What you will want to do is for the last two test scenarios (Integration & Black box), is not recompile any part of the application.

If any of your test scenarios require you to change the configuration (ie: use another component to mimic a banking integration, or do a performance load), this can be easily handled (this does come under the benefits of configuring the DI side of an IoC though.

Additionally if your app is used either at multiple sites (with different server and component configuration) or has a changing configuration on the live environment you can use the later stages of testing to verify that the app will handle those changes.

Production

As a developer you don't (and should not) have control of the production environment (in particular when your app is being distributed to multiple customers or seperate sites), this to me is the real benefit of using both an IoC and external configuration, as it is up to the infrastructure/production support to tweak and adjust the live environment without having to go back to developers and through test (higher cost when all they want to do is move a component).

Summary

The main benefits that external configuration of an IoC come from giving others (non-developers) the power to configure your application, in my experience this is only useful under a limited set of circumstances:

  • Application is distributed to multiple sites/clients where environments will differ.
  • Limited development control/input over the production environment and setup.
  • Testing scenarios.

In practice I've found that even when developing something that you do have control over the environment it will be run on, over time it is better to give someone else the capabilities to change the configuration:

  • When developing you don't know when it will change (the app is so useful your company sells it to someone else).
  • I don't want to be stuck with changing the code every time a slight change is requested that could have been handled by setting up and using a good configuration model.

Note: Application refers to the complete solution (not just the executable), so all files required for the application to run.


Dependency injection is a coding style that has its roots in the observation that object delegation is usually a more useful design pattern than object inheritance (i.e., the object has-a relationship is more useful than the object is-a relationship). One other ingredient is necessary however for DI to work, that of creating object interfaces. Combining these two powerful design patterns software engineers quickly realized that they could create flexible loosely coupled code and thus the concept of Dependency Injection was born. However it wasn't until object reflection became available in certain high level languages that DI really took off. The reflection component is core to most of today's DI systems today because the really cool aspects of DI require the ability to programmatically select objects and configure and inject them into other objects using a system external and independent to the objects themselves.

A language must provide good support for both normal Object Oriented programming techniques as well as support for object interfaces and object reflection (for example Java and C#). While you can build programs using DI patterns in C++ systems its lack of reflection support within the language proper prevents it from supporting application servers and other DI platforms and hence limits the expressiveness of the DI patterns.

Strengths of a system built using DI patterns:

  1. DI code is much easier to reuse as the 'depended' functionality is extrapolated into well defined interfaces, allowing separate objects whose configuration is handled by a suitable application platform to be plugged into other objects at will.
  2. DI code is much easier to test. The functionality expressed by the object can be tested in a black box by building 'mock' objects implementing the interfaces expected by your application logic.
  3. DI code is more flexible. It is innately loosely coupled code -- to an extreme. This allows the programmer to pick and choose how objects are connected based exclusively on their required interfaces on one end and their expressed interfaces on the other.
  4. External (Xml) configuration of DI objects means that others can customize your code in unforeseen directions.
  5. External configuration is also a separation of concern pattern in that all problems of object initialization and object interdependency management can be handled by the application server.
  6. Note that external configuration is not required to use the DI pattern, for simple interconnections a small builder object is often adequate. There is a tradeoff in flexibility between the two. A builder object is not as flexible an option as an externally visible configuration file. The developer of the DI system must weigh the advantages of flexibility over convenience, taking care that small scale, fine grain control over object construction as expressed in a configuration file may increase confusion and maintenance costs down the line.

Definitely DI code seems more cumbersome, the disadvantages of having all of those XML files that configure objects to be injected into other objects appears difficult. This is, however, the point of DI systems. Your ability to mix and match code objects as a series of configuration settings allows you to build complex systems using 3rd party code with minimal coding on your part.

The example provided in the question merely touches on the surface of the expressive power that a properly factored DI object library can provide. With some practice and a lot of self discipline most DI practitioners find that they can build systems that have 100% test coverage of application code. This one point alone is extraordinary. This is not 100% test coverage of a small application of a few hundred lines of code, but 100% test coverage of applications comprising hundreds of thousands of lines of code. I am at a loss of being able to describe any other design pattern that provides this level of testability.

You are correct in that an application of a mere 10s of lines of code is easier to understand than several objects plus a series of XML configuration files. However as with most powerful design patterns, the gains are found as you continue to add new features to the system.

In short, large scale DI based applications are both easier to debug and easier to understand. While the Xml configuration is not 'compile time checked' all application services that this author is aware of will provide the developer with error messages if they attempt to inject an object having an incompatible interface into another object. And most provide a 'check' feature that covers all known objects configurations. This is easily and quickly done by checking that the to-be-injected object A implements the interface required by object B for all configured object injections.


This is a bit of a loaded question, but I tend to agree that huge amounts of xml configuration doesn't really amount to much benefit. I like my applications to be as light on dependencies as possible, including the hefty frameworks.

They simplify the code a lot of the times, but they also have an overhead in complexity that makes tracking down problems rather difficult (I have seen such problems first hand, and straight Java I would be a lot more comfortable dealing with).

I guess it depends on style a bit, and what you are comfortable with... do you like to fly your own solution and have the benefit of knowing it inside out, or bank on existing solutions that may prove difficult when the configuration isn't just right? It's all a tradeoff.

However, XML configuration is a bit of a pet peeve of mine... I try to avoid it at all costs.