Thursday 14 May 2015

Injection Helps The Medicine Go Down


The dependency inversion principle is composed of two parts,
"High-level modules should not depend on low-level modules. Both should depend on abstractions."
"Abstractions should NOT depend on details. Details should depend on abstractions."
What this boils down to is that a class should be loosely coupled to the functionality it utilises and that it should never be concerned with the implementation of this functionality. 
This situation is best achieved by an interface driven design to establish a contract between classes that hides complexity and implementation detail and simply allows classes to utilise each other without concern for what's going on "under the hood". 
These drivers lead to the concept of "inversion of control" and dependency injection.
Public Recipe
By having a class publicly state its dependencies (either in its constructor or as parameter methods) the complexity of the design becomes much more visible.
If a class ends up with a constructor that takes 10 arguments this could well indicate that its doing too much or that the composition of the dependencies isn't right.
Loose Attachment 
Only relying on interfaces and having no concern for concrete implementations means your classes will be very loosely coupled to there dependencies, this leads to several major benefits.
  • The class being injected into becomes completely isolated from changes in the implementation of its dependencies, they can easily be "swapped out".
  • It becomes trivial to inject mock dependencies making the class much easier to test, giving thought to the interfaces ahead of time also makes a TDD approach much easier to achieve.
  • It allows developers to work concurrently with one writing the implementation of a dependency and one writing the class that will eventually consume the functionality, both are forced to consider up-front the required functionality and the API that will be used to access it.
Its Just a Factory
Having sung the praises of an interface driven design using dependency injection a word of caution about its implementation.
On most platforms there are a multitude of different tools available to implement dependency injection, however I've seen many developers be put off by the complexity of some of these tools.
When you boil it down there are only three requirements to implement dependency injection.
  1. Make sure all classes rely on abstractions to provide the functionality they need to use (i.e. stick it behind an interface).
  2. Make sure all classes have there dependencies satisfied by public methods (i.e. no more use of "new").
  3. Implement some kind of factory to satisfy dependencies and choose the concrete implementations to use.
Through experience I've realised its much simpler to roll your own solution to meet these requirements, it will lead to a lightweight implementation that properly matches your strategy for dependency injection. Too often when using external tools its difficult to see past the functionality that you'll never use to see the simplicity of what is actually required.
So don't be scared of the needle, injection is a great way ensure your code is getting everything it needs.

No comments:

Post a Comment