Debunking 2 major myths about dependency injection containers

There’s been lively conversations over the use and merits of dependency injection (DI) containers over the years. I’m a pragmatic software developer. I try doing what works best for any given situation. There are instances where I believe DI containers are of value and there are instances where I believe they are misused.  Here are two major misconceptions leading to what I believe is an improper use of DI containers.

  • DI containers improve testability
  • DI containers reduce coupling

DI containers improve testability

This is very common reason given when people advocate the use DI containers. The theme here is that by using a DI container one can easily swap out dependencies for mocks and stubs.  While this is true it’s also equally true that this can be done without using a DI container.

Let’s take a look at a typical DI container scenario.  The following code will use the Unity DI container and the Moq framework.

public interface IOrderRepository
{
    decimal GetOrderAmount(int orderId);
}
public class OrderRepository : IOrderRepository
{
    public decimal GetOrderAmount(int orderId)
    {
        throw new NotImplementedException();
    }
}
public class CustomerService
{
    public IOrderRepository OrderRepository { get; set; }
    public CustomerService(IOrderRepository repository)
    {
        OrderRepository = repository;
    }
    public decimal GetOrderAmountDue(int orderId)
    {
        var orderAmount = OrderRepository.GetOrderAmount(orderId);
        return ApplyTaxes(orderAmount);
    }
    private decimal ApplyTaxes(decimal amount)
    {
        //...
    }
}

[TestMethod]
public void CanGetAfterTaxesAmountDue()
{
    UnityContainer container = new UnityContainer();
    var mock = new Mock<IOrderRepository>();
    mock.Setup(m => m.GetOrderAmount(0)).Returns(20);
    container.RegisterInstance<IOrderRepository>(mock.Object);
    var service = container.Resolve<CustomerService>();
    var amountDue = service.GetOrderAmountDue(1);
    Assert.AreEqual(22.5m, amountDue);
}

And now a similar sample without using a DI container

public class CustomerRepository
{
    public virtual decimal GetBalance(int custId)
    {
        throw new NotImplementedException();
    }
}
public class InsuranceService
{
    public CustomerRepository CustomerRepository { get; set; }
    public InsuranceService(CustomerRepository repository)
    {
        CustomerRepository = repository;
    }
    public decimal GetCoverageAmount(int custId)
    {
        var balance = CustomerRepository.GetBalance(custId);

        return CalculateCoverageAmount(balance);
    }
    private decimal CalculateCoverageAmount(decimal amount)
    {
        //...
    }
}
[TestMethod]
public void CanGetCoverageAmount()
{
    var mock = new Mock<CustomerRepository>();
    mock.CallBase = false;
    mock.Setup(m => m.GetBalance(0)).Returns(20);
    var service = new InsuranceService(mock.Object);
    var coverageAmount = service.GetCoverageAmount(1);
    Assert.AreEqual(12.5m, coverageAmount);
}

These samples are very simple, however this same technique can be applied to more complex scenarios as well.  The basic principle behind this technique is simple.

  • Mock classes using polymorphism
  • Inject the mocked objects into the class being tested

I used a mock framework in these samples, but it’s not required.  I could have created a mock class that implements IOrderRepository in scenario 1. For scenario 2 I could have created a mock class that extends CustomerRepository.

DI containers are sometimes used for their service locator capabilities. A fairly common scenario occurs when putting legacy code under test.  Take this following class.

public class CustomerManager
{
 ...
 public IEnumerable<int> GetOrderNumbers()
 {
  return new OrderRepository().GetOrders().Select(o=>o.Id);
 }
}

If the task is just to put CustomerManager under test and changing any outside code isn’t an option at the moment.  Dependencies can easily be injected with a DI container by doing the following.

public class CustomerManager
{
 ...
 public UnitContainer UnityContainer {get;set;}
 public IEnumerable<int> GetOrderNumbers()
 {
  return UnitContainer.Resolve<OrderRepository>().GetOrders...
 }
}

This can also be accomplished without a DI container using any of the creational patterns.  It can be as simple as the following.

public class CustomerManager
{
 ...
 public Func<OrderRepository> OrderRepositoryProvider = () => new        OrderRepository();
 public IEnumerable<int> GetOrderNumbers()
 {
  return OrderRepositoryProvider().GetOrderAmount();
 }
}

The unit test just needs to change the “provider” and the task is complete.

I can go through a number of different scenarios, from my experience I can confidently claim that DI containers do not improve testability.

DI containers reduce coupling

It is said that DI frameworks reduce coupling by removing dependencies to concrete implementations.

We know this isn’t true as a rule since DI frameworks can resolve concrete classes.  I will also state that that there are cases where a DI container can reduce coupling.  For example, when you add a new dependency to class constructor, the calling code will not need to change in order to add this new dependency.  There are drawbacks to this as well.  These problems are not really the issue I have with the claim that DI containers reduce coupling.  My issue with the claim is two fold

  • Developers create abstractions where they are not needed
  • Having a class depend on an interface does not mean coupling has been reduced in the application.

The first point is a result of developers who misinterpret what an abstraction is.  An abstraction is not necessarily an abstract class, or an interface. Developers end up creating abstractions for things that are not actually abstract or have already been abstracted. The second point is that developers sometimes remove a dependency from a library that is only ever used in one application.  So while the library no longer has the dependency, the application still does. Removing the dependency from the library has accomplished nothing.  Let me use a few examples to clarify.

public class ChargeService
{
 ...
 public int GetChargeId(string chargeToken)
 {
  return (int)CreateSelectChargeIdCommand(chargeToken)
   .ExecuteScalar();
 }
 public SqlCommand CreateSelectChargeIdCommand(string chargeToken)
 { ... }
}

The ChargeService has a dependency on sql server.  If we want to switch database engines the ChargeService class will need to change.  To avoid this we create an abstraction.  We accomplish this by doing the following.

public class ChargeRepository
{
 public int GetChargeId(string chargeToken)
 {
  return (int)CreateSelectChargeIdCommand(chargeToken)
    .ExecuteScalar();
 }
 public SqlCommand CreateSelectChargeIdCommand(string chargeToken)
 { ... }
}
public class ChargeService
{
 ...
 public ChargeService(ChargeRepository repository)
 {
  ChargeRepository = repository;
 }
 public void ChargeCustomer(string chargetoken)
 {
  var chargeId = ChargeRepository.GetChargeId(token);
 }
}

Now that I have abstracted the calls for the database engine. If I need to change database engines the ChargeService class does not need to change, I only need to change the repository class.  I didn’t need an interface to accomplish this.

There are many cases where an interface should be used for these types of abstractions.  I’m thinking of cases like writing a library that will be used in applications outside the control of the person writing the library. However in many cases, be it misconceptions or perhaps a slight case of over-engineering, unnecessary complexity and time of development have been added to projects.

That concludes my contribution to the dependency injection discussion.  I hope to contribute more in the future by sharing scenarios where I advocate the use of dependency injection containers.  In the meantime feel free to leave a comment.  I look forward to exchanging ideas.