Organization is essential to scale. Compare the two images of cabling a data center:
A well organized wiring approach to the data center.
One of the less egregious cabling systems.
Obviously, the top image appears much more organized. I don’t think it is accidental that the better organized approach is visible in the larger data center. In order to scale, you need organization. If you have a small number of servers, a haphazard cabling scheme is less likely to impact your ability to trace and fix network problems. Such an approach would not work for a million-node data center.
The same is true of code. Without many of the visual cues we use to navigate the real world, tracking code can be very difficult. Thus, code can degenerate into chaos as fast or faster than physical devices. Indeed, the long standing name for poorly organized code is “Spaghetti Code” which is an analogy to the same kind of linear mess we can visualize with the network cables.
Dependency injection provides a tool to help minimize the chaos. Instead of wires run across the data center direct from one machine to another, the well organized scheme routes them to intermediate switches and routers in a standardized way. Just so, dependency injection provides an mediator between components, removing the need for one component to know the approach used to create the specific instance.
The guiding rule is that dependency injection separates object use from object construction.
Constructor Dependency Injection
Of the three forms of Dependency Injection that Martin Fowler enumerates, only the constructor form enforces that an object always meets its invariants. The idea is that, once the constructor returns the object should be valid. Whenever I start working with a new language, or return to an old language, I try to figure out how best to do dependency injection using constructors.
I have a second design criteria, which is that I should continue to program exclusively in that language. Using a marshaling language like XML or YAML as a way to describe how objects interact breaks a lot of the development flow, especially when working with a debugger. Thus, I want to be able to describe my object relationships inside the programming language.
With these two goals in mind, I started looking in to dependency injection in Go.