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): fried_eggs = fry(eggs, over_easy) add(fried_eggs, plate) return plate
Now when I want my robot to just practice making breakfast, I’ll do this:
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())
The big idea is very simple: the make_breakfast function depends on eggs and a plate. In the very first version, the function got those eggs and the plate itself.
In the later versions, the eggs and the plate are passed in as inputs to the function. This makes it easier to tweak what kinds of inputs are used.
This article beats the topic of dependency injection into a pulp, but the example above illustrates everything I care to understand about the topic.
In the programming world, handing my robot the rotten eggs and paper plates might correspond 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.