Target Audience: Developers and architects who need to choose a project architecture Prerequisites: Understanding of Tactical Design building blocks Section Purpose: Understand the philosophy of architecture patterns and make appropriate choices for your project

What is the Architecture Section?
This section covers architecture patterns for effectively implementing DDD. Good architecture enables you to build systems that protect business logic, are flexible to change, and are easy to test.

Overview Analogy Table#

Here are analogies to understand architecture patterns at a glance.

ArchitectureAnalogyCore PhilosophyOne-Line Summary
LayeredBuilding floorsSimple structure flowing from top to bottom“Separate layers by role”
HexagonalSmartphone and adaptersIsolate external world with Ports/Adapters“Protect the inside from the outside”
CleanConcentric circles of a castleDependencies always point inward“Business rules are king”
OnionOnion layersDomain model at the very center“Domain is the center of everything”
CQRSSeparate read/write countersComplete separation of commands and queries“Optimize reads and writes separately”
Event-DrivenCompany announcement systemLoose coupling and asynchronous communication“Announce what happened and react”

Why Do You Need Architecture Patterns?#

When you first start a project, it is fine to have all the code in one place. But as time passes and features are added, the code becomes increasingly complex and difficult to navigate. Architecture patterns provide methods to prevent this chaos and systematically organize your system.

Analogy: Building Design

You can compare software architecture to building design:

  • No architecture: A studio apartment where all rooms are connected. Cooking in the kitchen makes the bedroom smell, and when guests come, you have to tidy up everything.
  • Layered: A building with designated floors. Ground floor retail, second floor offices, third floor residential. Upper floors depend on lower floors.
  • Hexagonal: A central hall with multiple entrances. Whether you enter from the front door, back door, or underground parking, you arrive at the same hall. Changing entrances (adapters) does not affect the internal structure.
  • Clean: A castle with concentric circles. Moat (external world) -> walls (frameworks) -> inner keep (business logic) -> tower (core entities). You can only enter from outside to inside.

Key question: “How much do you need to protect your business logic (the tower) from external changes?”

Core Principle: Dependency Direction#

The most important principle shared by all architecture patterns is the direction of dependencies. Business logic (domain) should not depend on anything. Everything else should depend on the business logic.

flowchart TB
    subgraph Wrong["Incorrect Dependency Direction"]
        W1["Business Logic"]
        W2["Database"]
        W3["External API"]
        W1 --> W2
        W1 --> W3
    end

    subgraph Right["Correct Dependency Direction"]
        R1["Business Logic"]
        R2["Database Adapter"]
        R3["External API Adapter"]
        R2 --> R1
        R3 --> R1
    end

Philosophy of Each Architecture Pattern#

Each architecture pattern has its own philosophy and design goals.

Layered Architecture#

Philosophy: “Separate concerns so each layer focuses on its own role”

  • Background: Solving the problem of unmaintainable mixed code
  • Core Idea: Vertical separation, calls only flow from top to bottom
  • Values: Simplicity, easy to understand, rapid development

Hexagonal Architecture#

Philosophy: “Completely isolate the application core from the external world”

  • Background: Solving the problem of external system changes affecting business logic
  • Core Idea: Define boundaries with Ports and Adapters
  • Values: Testability, flexibility in technology replacement

Clean Architecture#

Philosophy: “Dependencies must always point inward”

  • Background: Maintenance issues with framework-dependent code
  • Core Idea: Strict dependency rules, concentric circle structure
  • Values: Framework independence, long-term maintainability

Onion Architecture#

Philosophy: “The domain model is king. Everything else serves the domain”

  • Background: Need for a structure to effectively implement DDD
  • Core Idea: Place the domain model at the very center
  • Values: Domain purity, DDD-friendliness

CQRS#

Philosophy: “Reads and writes are fundamentally different problems, so separate them”

  • Background: Different optimization requirements for queries and commands
  • Core Idea: Separate Command and Query models
  • Values: Optimization tailored to each, scalability

Event-Driven Architecture#

Philosophy: “Announce what happened and let interested parties react”

  • Background: Flexibility issues with tightly coupled systems
  • Core Idea: Loose coupling through domain events
  • Values: Scalability, loose coupling, asynchronous processing

Feature Comparison by Pattern#

PatternCore ConceptDifficultySuitable For
Layered4 layers flowing top to bottomEasyGetting started, simple projects
HexagonalIsolate externals with Ports and AdaptersMediumProjects with many external integrations
CleanStrict dependency rulesHardLarge-scale, long-term projects
OnionDomain model centricMediumDDD projects
CQRSRead/write separationHardComplex queries/performance requirements
Event-DrivenDomain eventsMedium~HardMicroservices, asynchronous processing

Best Practice: Which System Fits Which Architecture?#

The appropriate architecture varies depending on project characteristics.

System TypeRecommended ArchitectureReason
Startup MVPLayeredSpeed is priority, minimize complexity
Internal Admin SystemLayered or HexagonalModerate complexity, easy maintenance
E-commerce PlatformHexagonal + Event-DrivenMany external integrations, scalability needed
Finance/Insurance SystemOnion or CleanComplex domain, regulatory compliance
Large EnterpriseClean + CQRSClear rules, multi-team collaboration
MicroservicesHexagonal + Event-DrivenService boundaries, loose coupling
Legacy IntegrationHexagonalIsolate legacy with ACL
Reporting-focusedCQRSComplex query optimization

Selection Flowchart#

flowchart TB
    Q1{"Does your team have<br>architecture experience?"}
    Q2{"Is the business logic<br>complex?"}
    Q3{"Are there many<br>external integrations?"}
    Q4{"Do you need read/write<br>optimization?"}
    Q5{"Are you<br>applying DDD?"}

    Q1 -->|No| L1["Start with Layered"]
    Q1 -->|Yes| Q2

    Q2 -->|No| Q3
    Q2 -->|Yes| Q5

    Q3 -->|No| L1
    Q3 -->|Yes| L2["Hexagonal"]

    Q5 -->|No| L3["Clean"]
    Q5 -->|Yes| L4["Onion"]

    Q4 -->|Yes| L5["Add CQRS"]

    L1 --> L6["Evolve gradually as needed"]
    L2 --> L6
    L3 --> L6
    L4 --> L6

Gradual Evolution Path#

You do not need to apply a complex architecture from the start. As your project grows, you can naturally evolve the architecture.

flowchart LR
    A["Step 1<br>Layered"]
    B["Step 2<br>Domain Separation"]
    C["Step 3<br>Port Extraction"]
    D["Step 4<br>Hexagonal/Clean"]
    E["Step 5<br>CQRS/Events"]

    A -->|"When domain grows complex"| B
    B -->|"When external integrations increase"| C
    C -->|"When testing/changing becomes difficult"| D
    D -->|"When query performance/scalability needed"| E

Evolution Signals by Stage#

Current -> NextSignal
Layered -> Domain Separation“Should this logic really be in the Controller?”
Domain Separation -> Port Extraction“Changing the DB means modifying the domain too”
Port Extraction -> Hexagonal/Clean“The team is growing and we need clear rules”
Hexagonal/Clean -> CQRS“Query performance is the bottleneck”
-> Event-Driven“We need to reduce coupling between services”

Learning Order#

We recommend learning each architecture pattern in the following order.

Foundational Architecture#

OrderDocumentKey Question
1Layered Architecture“How should you structure your code?”
2Hexagonal Architecture“How should you isolate externals?”
3Clean Architecture“How should you manage dependencies?”
4Onion Architecture“How should you protect the domain?”

Advanced Patterns#

OrderDocumentKey Question
5CQRS“Should you separate reads and writes?”
6Event-Driven Architecture“How should components communicate?”

Next Steps#