Sunday, December 19, 2010

Inject Dependencies - Manually

In another post, “Do I Really Need a Singleton?”, I wrote about the problems introduced by the Singleton design pattern. When the single unique instance is being accessed through the getInstance() method, Singleton acts as a global variable in disguise and introduces tight coupling and unwanted dependencies. I have received two immediate questions from my readers:
  1. Should a Singleton be used only with Dependency Injection Framework?
  2. If accessing a Singleton through getInstance() creates tight coupling, creating an instance of any other class through new() also causes tight coupling. So, how should an object be created maintaining loose coupling?
As per my understanding, Dependency Injection is the answer for both the questions. But, that does not mandate the usage of a framework. Dependency Injection is a concept first and then a framework. When the application under question is small, we can always meet the needs by injecting dependencies manually, without using any framework like Spring.
In any Java application, we repeatedly encounter with two events:
  • Object creation
  • Interaction between the objects - The business logic
But, usually we mix up both of them which leads to tight coupling and unwanted dependencies which in turn makes the maintenance as well as unit testing a pain. Let me try to explain it using a very simple example:
class MyClass {

 private A a; //A is an interface
 private B b; //B is an interface

 //Object creation within constructor
 MyClass(A a, B b) {  
    a = new AImpl(); //AImpl is the concrete impl of A
    b = new BImpl(); //BImpl is the concrete impl of B
 }

 //Application logic lies within this method
 public void doSomething() {
    //Do A specific thing
    //Do B specific thing
    C c = new CImpl(); //Object creation within the method.
    //Do C specific thing
 }
}

The Problems with this class is:
  1. It has not been able to separate out the the object creation from the business logic resulting in a tight coupling.
  2. Here “programing to the implementation” has been done, not to interface. Tomorrow, if different implementations of A, B or C is required, the code inside the class has to be changed.
  3. Testing MyClass would require testing of A, B, C first.

Let me try to fix the problem:

class MyClass {

 private A a;
 private B b;
 private C c;

 MyClass(A a, B b, C c) {
    //Only Assignment
    this.a = a;
    this.b = b;
    this.c = c;
 }

 //Application Logic
 public void doSomething() {
    //Do A specific thing
    //Do B specific thing
    //Do C specific thing
 }
}

//The Factory
class MyFactory {
 public MyClass createMyClass() {
    return new MyClass(new AImpl(), new BImpl(), new CImpl());
 }
}

class Main {
 public static void main(String args[]) {
    MyClass mc = new MyFactory().createMyClass();
    mc.doSomething();
 }
}

What have been achieved here:

1. Constructor does not have a new(): 
Objects are not being created within the constructor of MyClass. The constructor is simply being used for field (A, B, C) assignments. Here the constructor asks for the dependencies as parameters, but does not create them (And that is the Simplest definition of dependency injection). However, simple Collection objects like ArrayList, HashMap OR value/leaf objects like Person/Employee (i.e the objects within the application which in turn does NOT create other objects) CAN BE created within the Constructor. Constructor should not be used for any other operation like I/O, thread creation etc.

As a thumb rule, any object should hold references ONLY to other objects whom it needs directly to get it’s work done (This is called the Law of Demeter). For exapmle, if MyClass needs some other class called X, MyClass’ constructor should directly ask for X. It should NOT ask for some other factory F which can return an instance of X. Violation of “Law of Demeter” would result in unwanted dependency between MyClass and F. So, if you find more than one Dot (.) operator be careful - something illegal is happening there.

2. Factory (MyFactory) is taking care of object creation and wiring: 
All the new operators (90%-99%) should belong to the factory. It should take care of entire object graph creation for the application and also of relating (wiring) different objects based on their declared dependencies (e.g MyClass needs A, B, C etc). It should not contain anything more - not any other logic (No I/O, thread creation etc).

Tomorrow if C starts depending on something else called D, only C and the factory would be impacted, not the entire object graph (C would have to introduce an overloaded constructor and factory would have to incorporate the object instantiation plus the object wiring related changes). 

For a large application of course there may be multiple factories. Here, thumb rule is one factory should instantiate all the objects with same life span.

3. Object creation is separate from the business logic: 
MyClass is now a Business Logic Holder. It does not have any new(). Even, it does not have any knowledge about the concrete implementations it is using for the business logic (i.e it knows about A but not about AImpl - “program to interface and not to implementation”).

You must have started thinking that I started this discussion with the context of Singleton. How does the manual dependency injection take care of a Singleton? How does it create a Singleton (minus the tight coupling, hidden dependency etc) and access it when needed? Surprisingly, we already have three Singletons in our example - AImpl, BImpl, CImpl. If the factory takes care of creating only one instance of a Class (by invoking new() only once), its a Singleton. Isn’t it? Then the factory may pass that unique instance in the form of dependencies to all other objects those need it.

4. So, where are we? MyClass, the business logic holder needs A, B and C for it’s business. It does not create them but asks for them (the dependencies). The factory (MyFactory) creates those dependencies and wire them to MyClass. But, who creates, the factory? Of course, the main method (the application launcher :-)). Let me repeat the story again, the main method first instantiates the factory, the factory in turn instantiates the object graph, each Object declares their dependencies and finally the main method itself sets the ball rolling - launch the application by invoking doSomething() of MyClass, ie. the objects starts talking to each other executing the usual business.

Let me repeat it once more: Create the factory, create the application using the factory and then start the application! For a large scale application the same thing can be achieved with a Dependency Injection framework like Spring, Google Guice etc. Of course they will come with lot of other benefits, in addition. But, for a small to medium scale application, dependency injection can be hand crafted making the app loosely coupled, more maintainable and of course unit test friendly.

Further Reading:

1. This post is strongly influenced by the writings of Misko Hevery published in his personal blog as well as in Google Testing Blog. Some more interesting articles can be found here, here and here.

2. Dependency Injection Demystified



Technorati short code : RV6SU2CB76BW

5 comments:

  1. I wrote about how to implement simple Dependency Injection using Annotations and Java Reflection,
    Part1, Part2

    ReplyDelete
  2. Yes, singletons can result in unwanted dependencies and coupling. I have seen this happen multiple times and I have a hard time refactoring some code where this was done because of the dependencies (the amount of code touched caused the refactoring to have an undesirable impact on a codebase because of the number of classes and projects touched, so the refactoring was postponed).

    That is not the only evil of global variables and singletons can (but don't necessarily) address some of those other evils - at least partially.

    Also, as you point out, you can use interfaces and use a factory to create instances of those impls, but this can also couple you to the factory(s) which themselves can act like global vars in some senses.

    DI/IOC solves some of these issues to a greater degree, but using interfaces for the factories can help to.

    ReplyDelete
  3. Quick note - in your first example, you had a and b created in the constructor and c created in the doSomething method, which implied that a and b were needed for the entire class and c was only needed to doSomething().

    In your second example, you changed this so that all three are required by the constructor. To me, the change that preserves the original meaning better would actually to have been to pass a C into the doSomething() method in the DI version, which exposes the dependency of just that method and allows a user of MyClass to delay the decision of which C to use until they need to doSomething() (and potentially avoid the creation of an un-needed object if doSomething() is never called).

    Other than that, nice article. Too many people seem to forget that manual dependency injection exists and that you don't need to subscribe to the XML config mess that seems so prevalent with wiring up some DI frameworks :)

    ReplyDelete
  4. Simple but correct.

    Many times dynamic languages users - especially Python and Ruby - say "we don't need dependency injection". This is wrong: it may be true that they don't need a DI framework or IOC container - but it's mostly a matter of taste.

    DI is just a design pattern. It doesn't need a library or framework by itself - even though it may be handy; I think that if you don't feel the need for an IOC container, either your app is very small or you are not injecting as much as you should.

    ReplyDelete
  5. I like the idea of Factory method, It gives more control on maintenance part of software life cycle. even Josua Bloach has suggested importance of static factory method in Effective Java. I have also blogged about factory method pattern in Java, let me know how do you find it.

    ReplyDelete