Software Architecture Patterns

Four canonical patterns from the books that survive framework churn: Domain-Driven Design, Clean Architecture, Hexagonal / Ports-and-Adapters, and the Repository Pattern.

Four patterns from the canonical architecture books. Touched in Y1 Phase 5; deepens through Y2 backend services.

Patterns in this category

PatternFirst touchedDEEP target
domain-driven-designY1 Phase 5Y2 capstone services
clean-architectureY1 Phase 5Y2 capstone services
hexagonal-and-ports-and-adaptersY1 Phase 5Y2 capstone services
repository-patternY1 Phase 5Y2 Phase 9 (SQL persistence)

Why this category exists

Architecture patterns are the internal structure decisions a service makes that survive the language and framework choice. A service written in Python with FastAPI and one written in Go with chi can both implement DDD. Both can apply clean architecture’s dependency rule. Both can use ports-and-adapters to keep the domain testable. The patterns are framework-neutral. The value is in the decisions they encode.

The four patterns overlap in useful ways. DDD says “organize code around the business domain, not the technical layers.” Clean architecture says “dependencies point inward toward the domain.” Hexagonal says “wrap the domain in ports; adapters implement the ports for specific tech.” Repository says “abstract data access behind a domain-facing interface.” Reading them one at a time makes each feel like the answer; reading all four together reveals they’re four angles on the same insight — the domain is the load-bearing thing, and everything else is replaceable scaffolding.

By end of Year 2, every /root service should explicitly apply at least one of these patterns. The point isn’t dogma. The point is that you can articulate which trade-offs you’re inheriting and why. A senior engineer reviewing your service should be able to name the pattern within five minutes of reading the code.

How to read this category

All four patterns are entry points at Y1 Phase 5. Read all four STUB entries before Phase 5 starts. Read the full OUTLINE for at least one during the phase. Pick the one that resonates most with the language you’re using: DDD for domain-heavy code, clean architecture for framework-heavy code, hexagonal for interface-heavy code, repository for data-heavy code.

Load-bearing pair: domain-driven-design and clean-architecture. These two are the frames that shape the other two. Learn them first.

Structural techniques: hexagonal-and-ports-and-adapters and repository-pattern. These are the concrete techniques the load-bearing patterns produce. Learn them second.

By end of Y2, all four should be at OUTLINE. Only one needs to be DEEP by Y2 end — the one you actually applied to a shipped service. The other three deepen through refactoring exercises across Y2 and Y3.

How the patterns connect

The four patterns nest.

  • domain-driven-design is the framing. It answers “what does this code exist to do?”
  • clean-architecture is the structural rule. It answers “which direction do the dependencies point?”
  • hexagonal-and-ports-and-adapters is the concrete shape clean architecture produces. It answers “how do I keep the domain testable?”
  • repository-pattern is a specific application of the hexagonal port for the data-access adapter. It answers “how do I keep the domain unaware of SQL?”

You can implement DDD without clean architecture (dependency direction unclear). You can implement clean architecture without hexagonal (adapters unnamed). You can implement hexagonal without repository (data access embedded in the domain). The four compose smoothly when you apply them in this order, but each is usable on its own.

Where these show up in /root

  • Y1 Phase 5 — first touch. All four patterns introduced through the canonical books (DDD blue book, Clean Architecture, Hexagonal original paper, standard repository refs).
  • Y1 Phase 5-8rxp and pulse get refactored to apply at least one architecture pattern each. The refactor is where the pattern goes from “read about” to “applied.”
  • Y2 Phase 9repository-pattern gets its first real workout when SQL persistence hits. The refactor to keep the domain unaware of SQL is the exercise.
  • Y2 all — every service ships with an architecture pattern named in its README. Not “using Django” — “domain-first with a repository adapter for Postgres.”
  • Y3+ — the patterns fade into the background. By the time you’re operating basecamp, architecture is subsumed by platform concerns. But the discipline of naming the pattern in every service stays as a habit.

The patterns aren’t heavily re-exercised past Y2. That’s fine. Architecture patterns are load-bearing early and background later. The point is that when you write a service in Y5 (llm-gateway, services/aiops/), you apply them without thinking about it.

Anti-patterns

Anti-patternWhy
Applying all four patterns to a 200-line CLIArchitecture patterns are for services that will grow. Small CLIs (like rxp at Y1 Phase 2) don’t need them; the patterns become ceremony that slows shipping. Apply them when the domain has enough complexity to justify the abstraction.
Reading DDD blue book cover-to-cover before writing codeThe book is best read while refactoring an existing service. Reading it linearly produces a lot of vocabulary and no intuition.
Treating repository-pattern as a database abstractionIt’s a domain abstraction, not a database one. The domain should not know about SQL; the repository is one adapter, an in-memory fake is another. If you can’t swap them in tests, the pattern isn’t applied.
Applying hexagonal to trivial codeHexagonal shines when you have real ports (HTTP in, SQL out, message queue side). If your code only has one boundary, the ports-and-adapters ceremony is overhead.
Ignoring clean architecture in language-idiomatic codeSome languages (Go, especially) push against clean architecture’s inversion. That’s fine when you’re aware of the trade-off. It’s not fine when you defaulted to it because “Go doesn’t do that.”

Cross-references