Clean Architecture with Python • Sam Keen & Max Kirchoff
Sam Keen, author of 'Clean Architecture with Python', discusses with Max Kirchoff how to pragmatically apply architectural principles to Python. They explore the critical link between architecture and testability, thoughtful dependency management through layered design, and how these principles enhance modern AI-assisted coding workflows by providing clear structure and scope.
The core promise of Clean Architecture is a thoughtful approach to dependency management. It’s not a rigid framework but a set of principles that can be adapted to a project’s context. The goal is to avoid the “dependency hell” that can fester in applications over time, leading to sharp edges and maintenance challenges. The architecture is designed to be adaptable, encouraging developers to apply principles as needed rather than adopting an all-or-nothing approach.
Keeping it Pythonic
A key challenge is applying architectural principles often associated with statically-typed languages like Java to a pragmatic and simple language like Python without losing its “Pythonic” feel. The goal is not to “turn Python into Java.” Instead, the book leverages Python’s native features to support clean architecture:
- Type Hints: A whole chapter is dedicated to using Python’s typing system to create clearer interfaces and contracts.
- Abstract Base Classes (ABCs) and Protocols: These are used to define interfaces and enforce dependencies without rigid class inheritance, staying true to Python’s flexible nature.
The approach is not a binary choice. It lays out the full spectrum of principles, but also guides on how to “thin down” the layers for different contexts, such as a simple API versus a full-stack web application, avoiding accidental complexity.
The Dependency Rule and The Onion Architecture
Clean Architecture is built on foundational concepts from Domain-Driven Design and SOLID principles. A central tenet is the Dependency Rule, visualized as an onion with four primary layers:
- Domain: The innermost layer contains the core business logic and domain objects. By definition, this layer has no dependencies on outer layers or external libraries.
- Application: This layer orchestrates the use of domain objects to perform specific business use cases. It depends on the Domain layer but remains independent of frameworks or UI.
- Adapter/Adaption: This layer acts as a bridge, converting data and requests between the application layer and external tools like databases, web frameworks, or third-party APIs.
- Framework: The outermost layer, containing the specific implementations and tools (e.g., Django, Flask, SQLAchemy).
The rule is simple: dependencies only point inward. The Framework layer can depend on everything, but the Domain layer depends on nothing. This structure isolates the most valuable part of the application—the business logic—from the volatile details of implementation. The ultimate recalibration is realizing that frameworks and libraries are just “details,” while the codified domain knowledge is the true asset.
Architecture as the Enabler of True Testability
A powerful indicator of architectural health is “test friction.” If tests are difficult to write, it’s often a signal of underlying architectural problems. As the book states, “Tests are nothing more than clients of our code.”
Clean Architecture directly enables the Test Pyramid, which advocates for a large base of fast unit tests and progressively fewer, more complex integration and end-to-end tests.
- Unit Testing the Core: Because the Domain layer has no external dependencies, writing unit tests is trivial. There’s no need for hundreds of lines of mocks to simulate databases or frameworks; you simply instantiate an object, change its state, and assert the result.
- Testing with Interfaces: The Application layer codes against interfaces (e.g., a “Persistence Interface” via the Repository Pattern) rather than concrete implementations. This makes it easy to swap in an in-memory fake or a simple mock for testing, keeping tests fast and isolated from infrastructure like a running database.
This approach helps avoid the “test ice cream cone” anti-pattern, where a project is dominated by slow, brittle, and expensive end-to-end tests because the architecture makes unit testing impossible.
Clean Architecture in the Age of AI
While the book was written before the explosion of agentic coding assistants, its principles are highly relevant to AI-driven development workflows. AI models, despite large context windows, struggle with “context rot” and lose effectiveness when given a massive, unstructured codebase.
Clean Architecture provides two key benefits for working with AI:
- Scoping Problems: The layered structure allows a developer to focus the AI on a specific, well-defined task. For example, you can instruct an AI to “work on the domain objects” or “implement the PostgreSQL adapter for this persistence interface.” This reduces the context and leads to more effective and consistent results.
- A Plan for the AI: It provides a “rule book” for the AI to follow. This allows a human architect to define the high-level structure, domain models, and interfaces, and then delegate the more boilerplate or “less exciting” implementation work to an AI, ensuring the output aligns with a coherent architectural vision.