One of the most common deficiencies large software systems exhibit is 'Tight Coupling'. A tightly coupled system is when some or all of the modules within the system are highly dependent on one another. It is usually contrasted with the related software quality metric 'Cohesion'. A low level of coupling is usually a sign of a good quality in the design and architecture of the system.

Having said that its important to make one thing clear: Some coupling and dependency between modules will always be needed especially among object oriented programming techniques, what is important is that the dependencies are controlled and only injected when necessary. But why is tight coupling so bad?

Lets consider three modules A, B and C:

  • A uses a service from B
  • B uses a parameter from A
  • A uses a service from C
  • C uses a parameter from B

If a change is required in A, there is a big probability that modules B and C would have to be modified too. This is what we call the 'ripple effect' among modules. The problem with the above is that the modules are too dependent on the implementation of each other since they use each other's functionalities. This can be solved by the concept of 'Information Hiding'. This is where Inversion of Control and Dependency Injection come in play.

Inversion of Control is a software engineering technique credited to Martin Fowler in which all the modules are designed very loosely coupled (weak/low level of coupling) and the coupling is done later at run time. Therefore at compile time the modules within the system have no dependencies on each other directly but use contracts instead to know what is expected and returned from each of the other modules. This is sometimes called the 'Hollywood Principle' ie "Don't call us, we'll call you". Inversion of Control can be achieved through various techniques, one of which is Dependency Injection.

In Dependency Injection, Interfaces are used to define the signatures and return types of modules. Concrete classes in which the 'Services' are utilized make a reference only to the interfaces without knowing how these will be implemented. Independency Injection can be achieved through two techniques:

  • Setter Injection
  • Constructor Injection

In the Constructor Injection, the interface being utilized in a particular method/class or in the case of MVC a controller is declared in the constructor. The methods within the interface can be used as if the implementation of the interface is known although in reality this implementation might not even exist yet as shown below:

public class Customer {
    private IOrderDao orderDao;
public Customer(IOrderDao orderDao) { if (orderDao == null) throw new ArgumentNullException("orderDao may not be null"); this.orderDao = orderDao; }
public IList GetOrdersPlacedOn(DateTime date) {
// ... code that uses the orderDao member // get orders from the datasource ... } }

On the other hand in the Setter Injection, the interface is treated as a property where a 'set' and a 'get' are defined for the Interface within the method and the public property is called as shown in the example below:

public class Customer {
    // Should not be called directly;
    // use the public property instead
    private IOrderDao orderDao;
 
    public Customer() {}

    public IOrderDao OrderDao {
        set { orderDao = value; }
        get {
            if (orderDao == null)
              throw new MemberAccessException("orderDao" +
                             " has not been initialized");
            return orderDao;
        }
    }
public IList GetOrdersPlacedOn(DateTime date) { //... code that uses the OrderDao public //... property to get orders from the datasource ... } }

Finally one might ask, but how will the implementations of these interfaces will be assigned to each interface since there might obviously be more than one implementation? That's the magic of Inversion of Control and Dependency Injection, special "containers" and libraries can be used to define which Interface is implemented with which implementation at runtime depending on some particular events or behaviors. Therefore Injection of implementations can occur through these special libraries at run time and only when specifically needed.

We will go into more detail on different Dependency Injection Libraries in the following weeks, what is important at this stage is that you get a firm grasp of what these two concepts are and the benefits of using them when designing your systems. 

Thanks for reading,

Shaun