Programmatic Dependency Injection

Why dependency injection?

Testability

In practice this where the most return of investment is. Allowing the code to be unit testable in practice is the reason most projects use DI.

Separation of construction from its use

Design attribute which is useful in reuse and clarity.

Ability to configure construction at deployment

While this is really handy in practice this is rarely exercised and when done it is for very small set of components.

What one additionally gets by using dependency injection frameworks?

Ease of construction objects with all their dependencies

Once we are bought into DI concepts we can use them quite extensively in a layered architecture. In such architectures a higher layered component1 really becomes a composite of components from lower layers. Constructing such objects by hand can be tiresome if it has to be repeated. DI frameworks act as a factory working based on the configuration of the components, taking away this responsibility from using code.

Construction strategy

DI frameworks enables one to define scope of the component objects, allowing object per thread, web request, etc or a singleton.

Aspects

The components configured for the framework can make use of aspect oriented programming facilities. These aspects when configured get weaved into the components to take care of orthogonal requirements.

The reason we have separated out the benefits is to clearly identify which ones we are going after when choosing a particular technique for dependency injection. We can adopt a technique which allows all three of above and for all components. This blanket approach provides uniformity and avoids change. This also comes with significant down sides. One such approach is to use XML based dependency injection configuration. Lets look at what are the downsides of doing so.

Dependency injection and Hibernate are two most game changing frameworks in enterprise Java which rescued us from the container managed world of EJB and Entity Beans. The primary reason for such frameworks worked because they made unit test possible.

Spring (Windsor in .NET), Hibernate both promote XML based configuration of objects*. Modern IDEs like Eclipse/Intellij treat such configuration files as code artifact providing most of its services like refactoring, intellisense, etc. This has made XML the default approach to configure our objects. This approach though suffers from issues which can be alleviated by using programming language instead.

Cannot debug XML

When we use XML in place of programming language refactoring and debugging become two immediate causalities. While smart IDEs take care of refactoring, these XML files still cannot be debugged. Inability to do so makes troubleshooting difficult.

Pollution of configuration

Use of XML has created a false design paradigm which goes like, "I don't need to compile". Avoiding compilation is good when compilation is an overhead. One of the situations you would want to do this, would be to change the behavior of a deployed application, may be in production. But this is rarely done, thankfully. This points out that it is not really configuration of the application and it being in XML doesn't add any value for a deployed system. This doesn't mean that it cannot be used like configuration especially in case of Spring, but those would be far fewer in number. In-fact interleaving deployment configuration with object dependency configuration makes it difficult to understand what really is configurable, hence these "configuration" should be separated from deployment configuration, if not avoided completely. Configurations should be defined keeping the operation's user in mind.

Burden to load entire configuration

Both Spring and Hibernate XML based configuration approach make following the principle of minimum single test time difficult, if not impossible, for certain class of unit tests. This happens because the configuration loading are not demand based or lazily loaded. So even if one needs handful of configurations in one's test it would still parse and load the entire configuration. Relying on XML based configuration ties one down the features provided by vendor.

XML is not programming language

Since XML is not a programming language:

  • The mistakes are not caught at the time of compilation but when the unit test or application is run. Other than simple syntactic errors this also hides the violation of modularity in XML. A configuration defined in wrong module might still work at runtime because they get aggregated before running. Although the IDEs complain about it but I have rarely seen green editor box principle adhered to.
  • They don't lend itself well for creating domain specific abstractions and eliminating semantic duplication. Being dependent on the features provided by the vendor leads to verbose XML configuration files.

Programmatic dependency injection

Dependency Injection (DI) is a concept which is implemented by frameworks like Spring and Windsor. This means that you can do DI without using any special framework. This doesn't imply that you do not need these DI frameworks at all. You may need them for features these framework provide over the of basic DI abilities.

Constructor based DI is arguable better than setter based and service locator approaches. Following this approach, programmatic DI depends on constructor chaining and providing empty constructors. Let us look at LoanService for an example of this.

public LoanService() {
    this(new ProductService(), new CustomerService(), new Loans());
}
public LoanService(ProductService productService, CustomerService customerService, Loans loans) {
    this.productService = productService;
    this.customerService = customerService;
    this.loans = loans;
}

The same applies to its dependencies like ProductService, CustomerService and so on.

public ProductService() {
    this(new LoanProducts());
}
public ProductService(LoanProducts loanProducts) {
    this.loanProducts = loanProducts;
}

The client of CustomerService instead of asking the container for an instance of it can do a simple new CustomerService() to retrieve an instance. While this doesn't get one everything one might need.....

Programmatic dependency configuration

While programmatic dependency injection is simple it might not suffice in every code base. In such cases one can choose to use the framework like Spring. Spring and likes, provide two kind mechanism for configuring the dependencies of components XML or programmatic. Strangely it is believed that XML based configuration is easier to express compared to programmatic configuration2. In fact quite contrary to it programming languages are better suited when it comes to expressing the intent. Let take a simple example:

Constructor/Setter/ServiceLocator

Auto wiring encourages large constructors

Are validators dependencies?

<<Code sample for comparison between program and XML>>

1 Bean or service are other names used for it

2 http://www.digizenstudio.com/blog/2007/01/14/programmatically-build-a-spring-application-context/

References

http://martinfowler.com/articles/injection.html

http://picocontainer.org/