Dependency Injection Demystified
I’m building a robot to make breakfast.
def make_breakfast():
fridge = get_reference_to_fridge()
eggs = fridge.get_eggs(number_of_eggs=2)
fried_eggs = fry(eggs, over_easy)
cabinet = get_reference_to_cabinet()
plate = cabinet.get_plate()
add(fried_eggs, plate)
return plate
This is OK, but I realize my robot needs lots and lots of practice, and I don’t like wasting all my nice eggs and getting all my plates dirty. So, while my robot is still learning how to cook, I want to specify that it uses paper plates and some crappy expired eggs I fished out of the grocery store dumpster.
I need to change make_breakfast so that I can specify the eggs and plates when I call the function.
def make_breakfast(eggs, plate):
eggs = egg_source.get_eggs(number_of_eggs=2)
fried_eggs = fry(eggs, over_easy)
plate = plate_source.get_plate()
add(fried_eggs, plate)
return plate
Now when I want my robot to just practice making breakfast, I’ll do this:
make_breakfast(rotten_eggs, paper_plates)
And later, once testing is complete, I’ll do this instead:
make_breakfast(get_reference_to_fridge().get_eggs(number_of_eggs=2),
get_reference_to_cabinet().get_plate())
This article beats the topic of dependency injection into a pulp, but the example above illustrates everything I understand about the topic.
In the programming world, handing my robot the rotten eggs and paper plates corresponds to using mock objects during automated tests. Furthermore, it isn’t absolutely necessary to pass in objects as parameters. Instead you could imagine that my make_breakfast function queries a database, or an XML file, or some command-line switches, or anything else that allows me to specify at run time where to obtain the objects that provide the required capabilities.
Update: Somebody already wrote an article with the exact same title as this more than a year ago. That article is very thorough and argues the same point that I want to make: dependency injection is an overblown term for a good idea.
Another update: Based on a conversation with Aaron Oliver, I changed the second example so that I pass in the eggs and plate directly, rather than pass in an object that provides these resources.