P38 · Architecture, Services & Distribution
layered architecture, services & distributed basics
Shape a Python system into services and reason about scaling it: invert dependencies with ports and adapters, design an in-process API with idempotency and versioning, and make distributed calls survivable with retry-and-backoff - capped by a resilient-service capstone. All-Pyodide, build-in-process; real serving, sockets and queues stay prose.
Every codebase that became hard to change got there the same way: a module that knew too much. The report generator imported the database client directly, so testing it needed a database; the billing logic knew which HTTP library was in use, so replacing that library became a project. Nothing was badly written. The dependencies simply pointed the wrong way, and this pillar is about pointing them the other way while the code is still small enough to move.
Dependency inversion is the lever, and ports and adapters is the shape. The core of the system depends on interfaces it defines — a port describing what it needs, not what a particular library provides — and the concrete adapter is injected at the edge. You will take a genuinely tangled module and refactor it that way, which is the only way the idea stops being an architecture diagram and starts being a technique. The immediate payoff is testability: the core can be exercised against a fake adapter with no infrastructure at all, which is exactly the "double only the boundaries you do not own" rule from P30 arriving as a structural property instead of a discipline.
From there the pillar designs a service that other code calls across a boundary: a request/response contract, versioning so the contract can change without breaking callers, and idempotency so that a retried call performs its effect once. Distribution closes it with the honest version of microservices — when a monolith should become several and, more importantly, when it should not — plus the primitives that make a remote call survivable, retry with backoff over an idempotent operation, so a partial failure is recoverable rather than a corruption. It is all in-process and Pyodide-run; real serving, sockets and queues are discussed rather than simulated. The capstone builds a resilient, idempotent service over an injected port.