“The most flexible systems are those in which dependencies refer only to abstractions and not concretions”
An application is almost always comprised of some core business logic triggering real-world outcomes through a set of utilities. A report generator exporting to a spreadsheet or railway traffic system controlling stop-lights being two such examples.
The flow of control of a program is often from core logic to more specialized utilities, such as I/O.
If the source code dependencies flow in this same direction, however, it can result in tight coupling of business logic with lower-level concerns. As low-level implementations are likely to change often, this will be a source of volatility within an application.
To protect against volatility, we want any high-level concerns to depend on abstractions rather than concretions — that is, interfaces rather than implementations. Interfaces change much less frequently than their instantiations, and so referencing these will shield a client from uncertainty.
Of course, something has to know about the dirty detail of implementation, and that’s where dependency injection helps.
Rather than core logic knowing what to use directly, you inject it with “an implementation” ensuring the source is as ignorant as possible to those low-level concerns. The grubby wiring can be tucked away in a few key places, such as factories or dependency injection frameworks, e.g. Spring.
To conclude this principle, it’s worth reiterating a few points listed by Uncle Bob concerning the DIP:
- Don’t refer to volatile concrete classes.
- Don’t derive (inherit) from volatile concrete classes.
- Don’t override concrete functions.
- Never mention the name of anything concrete and volatile.
Originally published at Better Programming