Throw Out Your Dependency Injection Container

Dependency Injection

Dependency injection containers (aka inversion of control containers) seem to be common in most modern applications.  There is no argument against the value dependency injection, but I do have a couple arguments against using a dependency injection container.  Like many other design patterns and practices, over time the development community seems to forget the original problem the pattern or practice was solving.

Constructor & Setter Injection

Passing your dependencies via the constructor is generally a better way of injecting dependencies instead of  setters. Constructor injection gives you a much clearer definition of what dependencies are needed in order to construct the object into a valid state.  My dependencies fields are usually readonly, to prevent them from being externally set after object creation.

Regardless if you use constructor or setter injection with your container of choice, there is often one injection method that is seemingly rarely used or mentioned.  Pass your dependency to the method that requires it.

How often have you seen a constructor take a pile of dependencies via it’s constructor, to which those dependencies were used in a limited amount of methods.  I often see this when looking at CQRS Command Handlers.

class InventoryHandler
{
	private readonly IRepository _repository;
	private readonly IBus _bus;
	private readonly IValidateInventory _validation;
	
	public InventoryHandler(IRepository repository, IBus bus, IValidateInventory validation)
	{
		_repository = repository;
		_bus = bus
		_validation = validation;
	}

	public void Handle(ReceiveInventory cmd)
	{
		if (!_validation.IsAvailable(cmd.ProductId)) {
			throw new InvalidOperationException("Cannot receive inventory");
		}

		// Receive Product into Inventory
		var inventory = _repository.GetById(cmd.ProductId);
		inventory.Receive(cmd.Quantity, cmd.UnitCost);
	}

	public Handle(RemoveInventory cmd)
	{
		// Remove product from inventory
		var inventory = _repository.GetById(cmd.ProductId);
		inventory.RemoveInventory(cmd.Quantity);

		// Pub/Sub to notify other bounded context of inventory removal
		_bus.Send(new InventoryRemovedMessage(cmd.InventoryId));
	}
}

In this simplified example, IRepository is used in both Handle() methods. However, IBus & IValidateInventory are both only used in one method each.

Instead of passing the dependencies via constructor, pass the required dependencies to the method that requires it.

class InventoryHandler
{
	private readonly IRepository _repository;
	
	public InventoryHandler(IRepository repository)
	{
		_repository = repository;
	}

	public void Handle(IValidateInventory validation, ReceiveInventory cmd)
	{
		if (!validation.IsAvailable(cmd.ProductId)) {
			throw new InvalidOperationException("Cannot receive inventory");
		}

		// Receive Product into Inventory
		var inventory = _repository.GetById(cmd.ProductId);
		inventory.Receive(cmd.Quantity, cmd.UnitCost);
	}

	public Handle(IBus bus, RemoveInventory cmd)
	{
		// Remove product from inventory
		var inventory = _repository.GetById(cmd.ProductId);
		inventory.RemoveInventory(cmd.Quantity);

		// Pub/Sub to notify other bounded context of inventory removal
		bus.Send(new InventoryRemovedMessage(cmd.InventoryId));
	}
}

 

Nested Dependencies

The primary reason why I prefer not to use a dependency injection container is because it potentially masks a code smell.  Nested dependencies or over abstraction can add complexity by adding unnecessary layers.

Have you seen something similar to this before?

public class MyService(IRepository repostiory) { ... }
public class Repository(IUnitOfWork unitOfWork) { ... }
public class UnitOfWork(IDbContext dbContext) { ... }
public class DbContext(IDbConnection dbConnection) { ... }
public class DbConnection(string connectionString) { ... }

Code SmellIf you are using a dependency injection container, you may not have noticed the excessive and unneeded abstraction layers in parts of you application.  If you had to manually wire up up these nested dependencies through all the layers, it would be really painful.

Masking the pain by using a dependency injection container is making your application more complex.

Take a look at your application and see if you can remove your dependency injection container.   If you can, then what benefits did it provide?  If you can’t, ask yourself if you really need all those layers.

Greg Young: 8 Lines of Code

Greg Young gave a good talk titled 8 Lines of Code, discussing simplicity, dependencies, and magic.

Magic is always something I try and identify and stay away from in my own code, however I really failed to realize how much magic goes on in some of the libraries/frameworks that I often use.  Entity Framework and nHibernate come to mind.  You really should understand the magic happening in these libraries to use them.  Which is very problematic.

If you take the dependency ownership seriously, then a lot of folks developing the front-end of a “modern” web applications are in a world of hurt.  RequireJS, Knockout.js, jQuery, Bootstrap, etc, etc, etc…

Video is posted on InfoQ:

http://www.infoq.com/presentations/8-lines-code-refactoring

Open/Closed Principle Violation

Before I post too many SOLID principle posts, let me prefix by saying that I strongly believing that following SOLID principles as guidelines will lead to writing better Object Oriented code.

Back to Open/Close Principle

Software entities like classes, modules and functions should be open for extension but closed for modifications.

Out of all the SOLID principles, I’ve found this one to causes the most confusion and is the hardest to identify for developers.  When following any of the SOLID principles, they all have a bit of cross over that help you identify when violating one of them.  Violating Open/Close principle usually means you are also violating Single Responsibility.

Here are a few smells/tips to for identifying when you might be violating Open/Closed principle:

  • Conditional Code
  • Multiple unit tests due to multiple execution paths
  • Violation of Single Responsibility

[code lang=”csharp”]
// Something smells in here…
public int GetSpeed()
{
int speed = 0;

if (_type is Bike)
{
speed = 10;
}
else if (_type is Car)
{
speed = 70;
}
else if (_type is Jet)
{
speed = 300;
}

return speed;
}
[/code]