Juri Strumpflohner
Juri Strumpflohner Juri is a full stack developer and tech lead with a special passion for the web and frontend development. He creates online videos for Egghead.io, writes articles on his blog and for tech magazines, speaks at conferences and holds training workshops. Juri is also a recognized Google Developer Expert in Web Technologies

Tackle software dependencies with IoC and Dependency Injection

7 min read

Coupling between objects creates "dependency", which per se is not bad at all. You will always have some dependencies among your objects. It becomes bad when it increases abnormally since that will make maintenance a nightmare. So what you'll do is of course to reduce dependencies in your code as much as possible. This means you first have to identify potential sources of bad dependencies which could possibly be avoided.

But how to identify them? 

Well, you could just imagine a change to an object and count how many objects you'd have to adapt to your changes such that your program still runs smoothly. Another possibility is to rely on code metrics such as "Coupling between objects" from the CK OO metrics suite. That can give you quite a good overview of potential problems in your application.

What are some examples/sources of coupling/dependencies?

There is a distinction between tight coupling and loose coupling.
  • Inheritance (tight coupling)
    Good OO designs will use inheritance heavily. Especially for exploiting polymorphism, nice hierarchies are created. But pay attention, inheritance is probably one of the strongest dependencies you can create, so it should just be used where it really makes sense: "For providing special behavior to an object". When you go down in the inheritance tree, objects should become more specialized, when you go up they should become more general. Inheritance shouldn't be used for instance to remove duplicate code. There is space for discussion here, however.
    You may consider using composition/aggregation instead or take a look at the decorator pattern. Another problem with inheritance is also that methods may be added and removed which may cause problems in large systems since you have to go and search where you should go and override the behavior.

  • Composition (loose coupling)
    Composition is already "better" in terms of coupling, since it creates loose coupling.

    public class MyClass{
    private ISomeInterface anInterface;
    }
    Note the usage of an interface here. I'll come back to that later. Composition creates loose coupling because when the interface changes you "just" need to adapt the dependent MyClass.

  • Instantiation (tight coupling)
    Another very common form of dependency comes through instantiation.

    public class MyClass{
    private PersistencyManager persistencyMan;

    public MyClass(){
    this.persistencyMan = new PersistencyMan();
    }
    }
    Again, a dummy example that shows the dependency created by instantiating a new object of type PersistencyManager inside the class MyClass (it doesn't matter where).

  • Instantiation through Factories/Service locators (loose coupling)

    public class MyClass{
    private PersistencyManager persistencyMan;

    public MyClass(){
    ConfigFactory myFactory = ConfigFactory.getDefaultFactory();
    this.persistencyMan = myFactory.getPersistencyManager(); //or through configuration
    }
    }
    Here the dependency is also on the Factory. This code however creates loose coupling because the process of creating objects is "outsourced" to another object. MyClass doesn't know how the object is being build.

  • Static methods, attributes or Singletons (tight coupling)

    public class MyClass{
    public void doSomeStuff(String userInput){
    ...
    MyHelper.helpMeOutWith(userInput);
    ...
    }
    }
    Here a dependency to a static "Helper" class is created which performs some logic.
I guess I covered most of the dependencies that may occur in your code. Well, everything nice and fine, but how should one handle/avoid these dependencies?? The main aim is to...
  • minimize the dependencies in your system by aiming for loose couplings and to
  • depend on interfaces only rather than concrete classes.
Remember, managing dependencies is the major challenge in designing good structured, large applications. If you're good in doing it, you'll have a nice time during maintenance.

The "magic" of an Inversion of Control (IoC) container and dependency injection

I'm not going to target to a specific technology now but rather I'd like to address the concept of dependency injection in general. Probably I'll focus on a specific example in a later post, let's see...

While "dependency injection" is nearly self-explanatory from an understanding point of view, "inversion of control" sounds like an obscure concept. At least that was my first impression when I took a look at it a couple of years ago. Let's start from the beginning (I'll make it short; promise). I'll often briefly make a jump to unit testing since my feeling is that that's where dependencies are really uncovered.
So, what we want is to have loose coupling in our code, but somehow we will have to instantiate our objects in order to be able to work with them. According to the the list above we'd probably choose factories or service locators.
public class MyCustomerService implements ICustomerService{
private ICustomerDao customerDao;

public MyCustomerService(){
this.customerDao = (ICustomerDao)MyDaoFactory.getInstance(CustomerDao.class); //one example of retrieval
...
}

//returns true if validation and persistency succeeded, false otherwise;
//this could be more sophisticated of course, returning a number of validation problems
public boolean saveAndValidateCustomer(Customer aCustomer){
//a set of validation instructions for your customer object
...

if(isAValidCustomer){
customerDao.save(aCustomer);
return true;
}else{
return false;
}
}
}
This may be a simple business logic class (in our service layer if we want so) which takes a customer, applies some validation on it and then delegates the persistency operation to the according DAO (Data Access Object). Note, we depend on interfaces here and the according dependency to the DAO object is created through a factory. This is the way you'd to it without IoC and DI (dependency injection). Now think about a unit test for the validation logic. What are the problems?? Well..we want to test the validation instructions inside the saveAndValidateCustomer(...) method but we don't want to test the persistency operation. That's out of scope of the unit test. But as you may have noticed, there is the customerDao.save(...) operation in it. We have to mock that out because we don't want to save something down or get annoying exceptions because some DB related stuff couldn't be loaded. Good we externalized the instantiation of the DAO into our factory and hopefully this factory depends on some configuration file which in the end determines which interface gets instantiated with which concrete type.
public class CustomerServiceTest{
private ICustomerService customerService;

public CustomerServiceTest(){
MyDaoFactory.initializeWithConfig("mytestconfiguration.xml"); //test initialization
}

@Before
public void setUp(){
this.customerService = new CustomerService();
}

@After
public void tearDown(){
this.customerService = null;
}

@Test
public void testSaveAndValidateCustomer(){
Customer aCustomer = new Customer();
//initialize aCustomer by setting its properties to a valid state

boolean isValid = customerService.saveAndValidateCustomer(aCustomer);
assertTrue("The customer object should be valid!", isValid);

//continue and set the customer to an invalid state and check again
}
}
Ok, we should be safe now to execute the test. Note you have to initialize your factory with some test objects which point to empty "mock" DAOs where the save operation doesn't have any side effects.
This example was without IoC and due to the usage of a factory the process of mocking out the DAO wasn't too complex. However, don't underestimate it, you have to create an appropriate configuration file and you have to somehow adapt your unit tests to use the "test" factory. But on the other side consider the case where you would have instantiated your DAO manually using new.

But still the example above needs a lot of logic just for retrieving the dependencies. IoC solves this. The concept goes down to the so-called hollywood principle: "Don't call me, I'll call you". Basically you don't retrieve you dependency but the dependency will be given, injected, to you at runtime. Thats why it's called "inversion" of control. It's not you that controls the setting of the instances directly, but the container does it. There are two different forms:
Constructor injection
public class MyCustomerService implements ICustomerService{
private ICustomerDao customerDao;

public MyCustomerService(ICustomerDao customerDao){
this.customerDao = customerDao;
...
}

public boolean saveAndValidateCustomer(Customer aCustomer){
...
}
}
or
Setter injection
public class MyCustomerService implements ICustomerService{
private ICustomerDao customerDao;

public MyCustomerService(){
...
}

public boolean saveAndValidateCustomer(Customer aCustomer){
...
}

public void setCustomerDao(ICustomerDao customerDao){
this.customerDao = customerDao;
}
}
The resulting test case is really simple!
public class CustomerServiceTest{
private ICustomerService customerService;

@Before
public void setUp(){
//in the constructor injection case:
this.customerService = new CustomerService(new MockCustomerDao());

//in the setter injection case:
//this.customerService = new CustomerService();
//this.customerService.setCustomerDao(new MockCustomerDao());
}

@After
public void tearDown(){
this.customerService = null;
}

@Test
public void testSaveAndValidateCustomer(){
//same as before
}
}
Simple, isn't it? Unit testing becomes really simple in such cases. Normally when people claim their unit tests are too complex and therefore not done it is usually a sign they have too tightly coupled code and they therefore fail to mock out their dependencies.

Now, the way your dependencies get injected into your classes depend on the specific technology of the Inversion of Control container you're using. Generally the IoC container controls the lifecycle of your objects. You can configure your dependencies either through configuration files (usually in xml format) or through annotations inside your classes. It's just a matter of personal preferences. As mentioned I'll not go into those details now, maybe that will follow in a later post. Below there are some reference to popular dependency injection libraries.

Dependency Injection libs

Spring (Java)
Guice (Google, Java)
GInjector (Google, GWT, Java)
Spring.net (.Net)
Unity (.Net)

    Questions? Thoughts? Hit me up on Twitter
    comments powered by Disqus