1.Layered, modular monolith, clean, and hexagonal architecture
All four are ways to stop business logic from depending directly on a database or a web framework. Layered stacks responsibilities top to bottom; modular monolith groups by feature instead of layer; clean and hexagonal both point every dependency inward, toward the business rules.
Key features
- Layered: presentation → service → repository → database, each layer calling only the one directly below it
- Modular monolith: one deployable process, split into feature modules with enforced boundaries between them
- Clean/hexagonal: business rules depend on nothing; infrastructure (DB, web, CLI) depends inward on the business rules through interfaces
- Hexagonal names the same idea "ports and adapters" — a port is an interface the core defines, an adapter is the concrete implementation plugged in
- None of the four dictate a specific framework — they dictate which direction an import is allowed to point
Comparing the four styles
- Presentation — HTTP views, CLI commands — talks to the service layer only
- Service — Business use cases — talks to repositories through an interface
- Repository — Data access — the only layer that imports a database driver
- Database — PostgreSQL, SQLite, or any storage the repository wraps
Command
# The dependency always points one way: presentation -> service -> repository
class OrderRepository:
def get(self, order_id): ...
class OrderService:
def __init__(self, repository: OrderRepository):
self.repository = repository # injected, not imported directly
def get_order_total(self, order_id):
return self.repository.get(order_id)["total"]All four styles exist to stop business rules from depending on infrastructure — layered stacks that rule top-down, clean/hexagonal make it a hard boundary business code cannot cross.