Dependency Inversion Principle
Depend on abstractions, not concretions.
Intent
High-level modules (policy) and low-level modules (details) both depend on abstractions. Details implement those abstractions.
Problem
Research wants John’s children. If it walks relationships.relations tuples directly, it is glued to how storage is laid out. Change the list → break research.
Solution
Introduce RelationshipBrowser.find_all_children_of.Relationships implements it. Research only talks to the browser.
Structure
| Piece | Role |
|---|---|
Research | High-level use case |
RelationshipBrowser | Abstraction |
Relationships | Low-level store |
Person / Relationship | Domain bits |
Compare code
Violation — dig into relations storage
python
class Research:
def __init__(self, relationships: Relationships):
for r in relationships.relations:
if r[0].name == "John" and r[1] == Relationship.PARENT:
print(f"John has a child called {r[2].name}")Compliant — this repo
python
class Research:
def __init__(self, browser: RelationshipBrowser):
for p in browser.find_all_children_of("John"):
print(f"John has a child called {p}")Walkthrough
Quick check
Which change follows DIP?
Run locally
bash
uv run dipExpected:
text
John has a child called Chris
John has a child called MattSource: main.py · tutorial README
Takeaway
- Policy must not scrape infrastructure internals
- Share an abstraction both sides depend on
- Details implement the abstraction — they don’t own the high-level