Pages

Tuesday, October 22, 2013

CDI Tip of the Day: Understanding Injection Techniques

diego_cervo/istockphoto.com
I just finished reading a book Understanding SCA (Service Component Architecture) that covers SCA in detail. The book is a topic for another post. I did come across a gem in the book around Dependency Injection (DI) techniques, and how to make choices around one technique over another.

The three main techniques used for Dependency Injection (DI) are constructor, setter, and field injection. There is also reflection which I will not discuss in this article.

Constructor Injection

This technique calls for injecting the objects used in our class at object instantiation. A significant advantage of this technique is that it makes all of our dependencies explicit at compile time. This also makes testing much easier since we can use testing techniques like mock objects to test. "... Constructor-based injection also enables fields to be marked as final so they cannot be inadvertently changed later on." This can also add some additional performance gains since the object are final and the compiler can optimize this. If you allow mutators for the objects injected, then this performance perk is negated since the object can not be marked final.

A disadvantage of constructor based injection is that the constructors parameter lists can become very large. I would recommend that this approach be considered for 4 parameters, or less. Four parameters can result in 16 test cases (n X n matrix). Additionally, there may be more than one constructor, and dependency injection frameworks deal with it differently. Weld currently only allows DI on one constructor.

Advantages Disadvantages
Explicit Dependencies at compile time. Constructors can become very large
Fields can be marked final Mutable fields lose final advantage
Testing can be simplified The number of parameters produces an n X n matrix of tests

Setter Injection

The next technique is using setter based injection. Typically we have an object with setters and getters where the setter is annotated for injection. This requires that our setters be public, or protected. I would recommend making them public in the absence of reasons to do otherwise. The significant advantage to setter based injection is the ability to change the injected object at runtime. If the method is public, then it can be changed by any object. This could be an advantage, or disadvantage. Also this technique is conducive to testing as well. We can inject mock objects, or use a framework like Arquillian to handle injection during testing.

The disadvantages of using setter based injection "... are two major disadvantages to setter injection. Component (Class) dependencies are dispersed across a number of setter methods, making them less obvious and increasing the verbosity of the code because a method needs to be created for every reference In addition, setter methods make references that should be immutable subject to change because the fields they are assigned cannot be declared final." The second item may not be a disadvantage if  considered closely in your design. The former represents a significant disadvantage in terms of code clarity that has been a hallmark of EE5/6/7.

Another item to consider is that the one of the best practices for developing interfaces is to avoid putting setters in them. Interface design usually only has the getter defined, the setter is an implementation detail that is left out of the contract. This prevents the client code from altering the implementation code accidentally since it should be interacting with the interface contract.

Advantages Disadvantages
Code is more testable Results in less readable code as the number of references increase.
Injection can be changed at runtime. Fields cannot be marked final
- Mutators (setters) are typically not part of the interface contract.

Field Injection

Field based injection is often used in example code found for Dependency Injection (DI) frameworks. "The major advantage of field-based injection is that it is concise." The fields may be public, private, protected, or default. They can not be marked final. This technique avoids large lists of parameters for constructors, and adding setter methods that are not part of the interface contract. The Major disadvantage is unit testing. You need to add a setters, sub-class the object, or use reflection typically. A framework like Arquillian can be used to test, but this adds additional complexity that would not be required for using constructor, or setter injection. The brevity is both an advantage and disadvantage.
Advantages Disadvantages
Concise Difficult to test
- Fields cannot be marked final

Summary

In examining the tables of advantages and disadvantages, you may come to a conclusion that Field injection may be the best choice. This would be premature. In fact, there is clearly no one technique that is better than the other. All have advantages, and disadvantages. Clearly as a developer, or architect you must decide for a given class, or set of classes which technique will meet your requirements. A lot has been said about picking a pattern, and using it consistently throughout your project. I personally find that idea bad. Comparatively, we could say it is like picking a hammer out of a toolbox and using nails everywhere. Sometimes a bolt and nut would work much better. Don't fall into the trap of consistency over what makes sense for your project.

No comments:

Post a Comment