clean-ddd-hexagonal

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Clean Architecture + DDD + Hexagonal

Clean Architecture + DDD + Hexagonal

Backend architecture combining DDD tactical patterns, Clean Architecture dependency rules, and Hexagonal ports/adapters for maintainable, testable systems.
结合DDD战术模式、Clean Architecture依赖规则和Hexagonal端口/适配器模式的后端架构,构建可维护、可测试的系统。

When to Use (and When NOT to)

适用与不适用场景

Use WhenSkip When
Complex business domain with many rulesSimple CRUD, few business rules
Long-lived system (years of maintenance)Prototype, MVP, throwaway code
Team of 5+ developersSolo developer or small team (1-2)
Multiple entry points (API, CLI, events)Single entry point, simple API
Need to swap infrastructure (DB, broker)Fixed infrastructure, unlikely to change
High test coverage requiredQuick scripts, internal tools
Start simple. Evolve complexity only when needed. Most systems don't need full CQRS or Event Sourcing.
适用场景不适用场景
具有大量规则的复杂业务领域简单CRUD操作,业务规则少
需长期维护的系统(持续数年)原型、MVP、一次性代码
5人及以上的开发团队独立开发者或小型团队(1-2人)
多入口点(API、CLI、事件)单一入口点,简单API
需要更换基础设施(数据库、消息中间件)基础设施固定,几乎不会变更
要求高测试覆盖率快速脚本、内部工具
从简单开始。仅在需要时再增加复杂度。 大多数系统不需要完整的CQRS或事件溯源。

CRITICAL: The Dependency Rule

核心:依赖规则

Dependencies point inward only. Outer layers depend on inner layers, never the reverse.
Infrastructure → Application → Domain
   (adapters)     (use cases)    (core)
Violations to catch:
  • Domain importing database/HTTP libraries
  • Controllers calling repositories directly (bypassing use cases)
  • Entities depending on application services
Design validation: "Create your application to work without either a UI or a database" — Alistair Cockburn. If you can run your domain logic from tests with no infrastructure, your boundaries are correct.
依赖关系仅向内指向。外层依赖内层,反之则不可。
Infrastructure → Application → Domain
   (adapters)     (use cases)    (core)
需要避免的违规情况:
  • 领域层引入数据库/HTTP库
  • 控制器直接调用仓库(绕过用例)
  • 实体依赖应用服务
设计验证标准: “让你的应用在没有UI或数据库的情况下也能运行”——Alistair Cockburn。如果你的领域逻辑可以在不依赖任何基础设施的情况下通过测试运行,说明你的边界设计是正确的。

Quick Decision Trees

快速决策树

"Where does this code go?"

“这段代码应该放在哪里?”

Where does it go?
├─ Pure business logic, no I/O           → domain/
├─ Orchestrates domain + has side effects → application/
├─ Talks to external systems              → infrastructure/
├─ Defines HOW to interact (interface)    → port (domain or application)
└─ Implements a port                      → adapter (infrastructure)
代码归属?
├─ 纯业务逻辑,无I/O操作           → domain/
├─ 编排领域逻辑 + 包含副作用 → application/
├─ 与外部系统交互              → infrastructure/
├─ 定义交互方式(接口)    → 端口(领域层或应用层)
└─ 实现端口                      → 适配器(基础设施层)

"Is this an Entity or Value Object?"

“这是Entity还是Value Object?”

Entity or Value Object?
├─ Has unique identity that persists → Entity
├─ Defined only by its attributes    → Value Object
├─ "Is this THE same thing?"         → Entity (identity comparison)
└─ "Does this have the same value?"  → Value Object (structural equality)
实体还是值对象?
├─ 具有持久化的唯一标识 → Entity
├─ 仅由属性定义    → Value Object
├─ “这是同一个事物吗?”         → Entity(按标识比较)
└─ “它们的值是否相同?”  → Value Object(按结构相等性比较)

"Should this be its own Aggregate?"

“这应该作为独立的Aggregate吗?”

Aggregate boundaries?
├─ Must be consistent together in a transaction → Same aggregate
├─ Can be eventually consistent                 → Separate aggregates
├─ Referenced by ID only                        → Separate aggregates
└─ >10 entities in aggregate                    → Split it
Rule: One aggregate per transaction. Cross-aggregate consistency via domain events (eventual consistency).
聚合边界?
├─ 必须在事务中保持一致 → 同一聚合
├─ 可最终一致                 → 独立聚合
├─ 仅通过ID引用                        → 独立聚合
└─ 聚合内包含10个以上实体                    → 拆分聚合
规则: 一个事务对应一个聚合。跨聚合的一致性通过领域事件实现(最终一致)。

Directory Structure

目录结构

src/
├── domain/                    # Core business logic (NO external dependencies)
│   ├── {aggregate}/
│   │   ├── entity              # Aggregate root + child entities
│   │   ├── value_objects       # Immutable value types
│   │   ├── events              # Domain events
│   │   ├── repository          # Repository interface (DRIVEN PORT)
│   │   └── services            # Domain services (stateless logic)
│   └── shared/
│       └── errors              # Domain errors
├── application/               # Use cases / Application services
│   ├── {use-case}/
│   │   ├── command             # Command/Query DTOs
│   │   ├── handler             # Use case implementation
│   │   └── port                # Driver port interface
│   └── shared/
│       └── unit_of_work        # Transaction abstraction
├── infrastructure/            # Adapters (external concerns)
│   ├── persistence/           # Database adapters
│   ├── messaging/             # Message broker adapters
│   ├── http/                  # REST/GraphQL adapters (DRIVER)
│   └── config/
│       └── di                  # Dependency injection / composition root
└── main                        # Bootstrap / entry point
src/
├── domain/                    # 核心业务逻辑(无外部依赖)
│   ├── {aggregate}/
│   │   ├── entity              # 聚合根 + 子实体
│   │   ├── value_objects       # 不可变值类型
│   │   ├── events              # 领域事件
│   │   ├── repository          # 仓库接口(驱动端口)
│   │   └── services            # 领域服务(无状态逻辑)
│   └── shared/
│       └── errors              # 领域错误
├── application/               # 用例 / 应用服务
│   ├── {use-case}/
│   │   ├── command             # 命令/查询DTO
│   │   ├── handler             # 用例实现
│   │   └── port                # 驱动端口接口
│   └── shared/
│       └── unit_of_work        # 事务抽象
├── infrastructure/            # 适配器(外部相关实现)
│   ├── persistence/           # 数据库适配器
│   ├── messaging/             # 消息中间件适配器
│   ├── http/                  # REST/GraphQL适配器(驱动端)
│   └── config/
│       └── di                  # 依赖注入 / 组合根
└── main                        # 启动程序 / 入口点

DDD Building Blocks

DDD构建块

PatternPurposeLayerKey Rule
EntityIdentity + behaviorDomainEquality by ID
Value ObjectImmutable dataDomainEquality by value, no setters
AggregateConsistency boundaryDomainOnly root is referenced externally
Domain EventRecord of changeDomainPast tense naming (
OrderPlaced
)
RepositoryPersistence abstractionDomain (port)Per aggregate, not per table
Domain ServiceStateless logicDomainWhen logic doesn't fit an entity
Application ServiceOrchestrationApplicationCoordinates domain + infra
模式用途层级核心规则
Entity标识 + 行为领域层按ID判断相等性
Value Object不可变数据领域层按值判断相等性,无setter
Aggregate一致性边界领域层仅聚合根可被外部引用
Domain Event记录变更领域层过去式命名(如
OrderPlaced
Repository持久化抽象领域层(端口)每个聚合对应一个仓库,而非每个表
Domain Service无状态逻辑领域层当逻辑不适合放在实体中时使用
Application Service编排协调应用层协调领域层与基础设施层

Anti-Patterns (CRITICAL)

反模式(核心注意点)

Anti-PatternProblemFix
Anemic Domain ModelEntities are data bags, logic in servicesMove behavior INTO entities
Repository per EntityBreaks aggregate boundariesOne repository per AGGREGATE
Leaking InfrastructureDomain imports DB/HTTP libsDomain has ZERO external deps
God AggregateToo many entities, slow transactionsSplit into smaller aggregates
Skipping PortsControllers → Repositories directlyAlways go through application layer
CRUD ThinkingModeling data, not behaviorModel business operations
Premature CQRSAdding complexity before neededStart with simple read/write, evolve
Cross-Aggregate TXMultiple aggregates in one transactionUse domain events for consistency
反模式问题解决方案
贫血领域模型实体仅作为数据容器,逻辑放在服务中将逻辑迁移到实体内部
每个实体对应一个仓库破坏聚合边界每个聚合对应一个仓库
基础设施层泄漏领域层引入DB/HTTP库领域层无任何外部依赖
上帝聚合包含过多实体,事务缓慢拆分为更小的聚合
跳过端口控制器直接调用仓库始终通过应用层进行调用
CRUD思维仅建模数据,而非行为建模业务操作
过早引入CQRS在不需要时增加复杂度从简单的读写逻辑开始,按需演进
跨聚合事务一个事务包含多个聚合使用领域事件实现一致性

Implementation Order

实施步骤

  1. Discover the Domain — Event Storming, conversations with domain experts
  2. Model the Domain — Entities, value objects, aggregates (no infra)
  3. Define Ports — Repository interfaces, external service interfaces
  4. Implement Use Cases — Application services coordinating domain
  5. Add Adapters last — HTTP, database, messaging implementations
DDD is collaborative. Modeling sessions with domain experts are as important as the code patterns.
  1. 领域探索 — 事件风暴、与领域专家沟通
  2. 领域建模 — 实体、值对象、聚合(无基础设施)
  3. 定义端口 — 仓库接口、外部服务接口
  4. 实现用例 — 协调领域层的应用服务
  5. 最后添加适配器 — HTTP、数据库、消息中间件实现
DDD是协作式的。 与领域专家的建模会议和代码模式同样重要。

Reference Documentation

参考文档

FilePurpose
references/LAYERS.mdComplete layer specifications
references/DDD-STRATEGIC.mdBounded contexts, context mapping
references/DDD-TACTICAL.mdEntities, value objects, aggregates (pseudocode)
references/HEXAGONAL.mdPorts, adapters, naming
references/CQRS-EVENTS.mdCommand/query separation, events
references/TESTING.mdUnit, integration, architecture tests
references/CHEATSHEET.mdQuick decision guide
文件用途
references/LAYERS.md完整的层级规范
references/DDD-STRATEGIC.md限界上下文、上下文映射
references/DDD-TACTICAL.md实体、值对象、聚合(伪代码)
references/HEXAGONAL.md端口、适配器、命名规范
references/CQRS-EVENTS.md命令/查询分离、事件
references/TESTING.md单元测试、集成测试、架构测试
references/CHEATSHEET.md快速决策指南

Sources

资料来源

Primary Sources

主要资料

Pattern References

模式参考

Implementation Guides

实施指南