Layered & Hexagonal Architecture
A track of P38 · Architecture, Services & Distribution.
Keep a growing codebase changeable: refactor a tangled module into ports and adapters so the core depends on interfaces, not concretes, and inject the concrete adapter at the edge - dependency inversion, the lever the whole pillar builds on.
You want to unit-test the report generator. You cannot, because it constructs
its own database client in __init__ — there is no seam to put a fake into, so
"testing" it means having a database, and the test everyone eventually writes
instead is the one that asserts almost nothing. The code is not badly written.
It simply points at a concrete thing where it should point at an idea.
The lever that keeps a growing codebase changeable is where its boundaries sit. This track is layered and hexagonal architecture in practice: depend on interfaces, not concrete classes, so the core stays pure and the details stay swappable.
You refactor a tangled module — one that constructs its own dependency and so can't
be tested or repointed — into ports & adapters. The core declares a port (a
Protocol) describing what it needs; a concrete adapter implements it; and
dependency injection wires the adapter in at the edge. The dependency now points
inward, toward the domain, so a test injects a fake and exercises real logic with no
I/O, while production injects the real one and nothing in the core changes. That one
inversion — depend on an abstraction, inject the concrete — is what the rest of the
pillar (services, resilience, the capstone) builds on.