Dependency Inversion
High-level policy should depend on a stable abstraction rather than directly construct a low-level detail. Both policy and detail agree on the boundary contract.
What you’ll understand
- High-level policy should depend on a stable abstraction rather than directly construct a low-level detail. Both policy and detail agree on the boundary contract.
- Inject a sender that fulfills the message contract instead of constructing a provider inside policy code.
- Evaluate the tradeoff: An abstraction boundary adds wiring and requires contract tests. Dependency injection is one implementation technique; the principle is the direction of dependency.
Useful first: Classes and Objects
The idea and when to recognize it
High-level policy should depend on a stable abstraction rather than directly construct a low-level detail. Both policy and detail agree on the boundary contract.
- Requirement: Receipt delivery policy should work without depending on a concrete email provider.
- Change to anticipate: Substitute SMS delivery without editing the receipt service.
- Design goal: Inject a sender that fulfills the message contract instead of constructing a provider inside policy code.
Start with the concrete problem
Receipt delivery policy should work without depending on a concrete email provider.
Substitute SMS delivery without editing the receipt service.
| Direct implementation | Revised design |
|---|---|
| Constructing the email SDK in the receipt method prevents substitution and isolated testing. | Inject a sender that fulfills the message contract instead of constructing a provider inside policy code. |
| The baseline case can hide the problem. Compare the extension and boundary fixtures before accepting this design. | An abstraction boundary adds wiring and requires contract tests. Dependency injection is one implementation technique; the principle is the direction of dependency. |
Responsibilities and contracts
Inject a sender that fulfills the message contract instead of constructing a provider inside policy code.
- ReceiptService: Depends on the sender contract. Public operations: send(message)
- Sender: Defines message delivery. Public operations: send(message)
- EmailSender: Implements the same contract. Public operations: send(message)
Read the design
Select a participant to inspect its responsibility and public operations. Follow the labeled relationships; an arrow indicates direction, while the legend distinguishes ownership, substitution, and temporary use.
Preparing the design walkthrough…
Follow the interaction
Choose a supplied workload and compare the direct and revised implementations. Step through the same operation in both languages. Object values are recorded after each highlighted statement; previous steps remain unchanged.
Preparing the design walkthrough…
Implementation and expected output
Read the complete example alongside its input and expected output. The implementation selector changes the displayed program; the language selector preserves your current scenario and playback position.
Preparing the design walkthrough…
Try the idea in another setting
An order policy can depend on a repository contract realized by an in-memory test repository and a database implementation.
- Name the new client contract before adapting the example.
- Identify which state belongs to each object and who controls its lifetime.
- Write one normal case and one boundary case before extending the design.
Tradeoffs and interview takeaways
An abstraction boundary adds wiring and requires contract tests. Dependency injection is one implementation technique; the principle is the direction of dependency.
Common mistake: Constructing the email SDK in the receipt method prevents substitution and isolated testing.
- Explain the choice: Inject a sender that fulfills the message contract instead of constructing a provider inside policy code.
- Challenge your choice: An abstraction boundary adds wiring and requires contract tests. Dependency injection is one implementation technique; the principle is the direction of dependency.
- Describe a requirement that would make the simpler implementation sufficient.
Design challenge and knowledge check
Preparing the design walkthrough…