跳至正文
来两杯美式
返回

DDD 复杂业务系统设计(八):整洁架构 vs 六边形架构 vs DDD 分层,我选哪一种

By 来两杯美式
发布于

前言

上一篇我们讲了 DDD 分层架构。但实际上,不只有一种分层方式

业内常见的有三种:

它们看起来形态各异,但内核是一致的。这一篇我们一起看看。

一、整洁架构(洋葱架构)

整洁架构的提出者叫 Robert C. Martin(Bob 大叔)。它的形状像洋葱:

┌─────────────────────────────────────┐
│   Frameworks & Drivers (框架)        │  ← 最外层
│   ┌─────────────────────────────┐   │
│   │ Interface Adapters (接口适配) │   │  ← 适配层
│   │   ┌─────────────────────┐   │   │
│   │   │ Use Cases (用例)      │   │   │  ← 应用层
│   │   │   ┌─────────────┐   │   │   │
│   │   │   │ Entities (实体) │   │   │   │  ← 领域层
│   │   │   └─────────────┘   │   │   │
│   │   └─────────────────────┘   │   │
│   └─────────────────────────────┘   │
└─────────────────────────────────────┘

核心原则依赖只能从外向内内圈不依赖外圈

各层职责:

职责
Entities核心业务对象,封装企业级业务规则
Use Cases应用业务规则,编排实体完成用例
Interface Adapters适配器,转换数据格式(Controller、Repository 实现)
Frameworks & Drivers框架和外部工具(Web 框架、数据库、消息中间件)

洋葱架构的核心思想

二、六边形架构(端口-适配器架构)

六边形架构的提出者是 Alistair Cockburn。它的形状是六边形(只是画法不同,内核一样):

        ┌──────────┐
        │  Port 1   │ ← 端口:业务定义
        └──────────┘

┌──────────┐  │  ┌──────────┐
│  Port 2  ├──┼──┤  Port 3  │  ← 多个端口对应外部世界
└──────────┘  │  └──────────┘

   ┌──────────┴──────────┐
   │   Application Core   │  ← 应用核心(业务逻辑)
   └─────────────────────┘

核心概念

一个端口可以对应多个适配器。比如:

业务核心不关心外部怎么实现只关心接口签名

三、三种架构的对比

虽然形态不同,三种架构的内核完全一致

维度DDD 分层整洁架构六边形架构
中心领域层EntitiesApplication Core
依赖方向自上而下由外向内通过端口-适配器隔离
业务位置领域层内圈中心
外部适配基础层Interface AdaptersAdapters
关键差异强调“层”强调“依赖规则”强调“端口-适配器”

它们本质上是同一种思想的三个表达

四、共性:三种架构都强调“内外分离”

无论是哪种架构,核心都做了同一件事把易变的外部和稳定的业务核心分开

        外圈(易变)

   ┌───────┴───────┐
   │  内圈(稳定)   │  ← 业务核心
   │  · 实体        │
   │  · 领域服务    │
   │  · 业务规则    │
   └───────────────┘

为什么这件事如此重要?

因为企业级系统的需求变化规律是:

如果业务核心和外部技术耦合

如果业务核心和外部技术分离

五、怎么选?

我的个人建议:

项目类型推荐架构
新项目、复杂业务DDD 分层(最主流,团队认知成本低)
强调测试覆盖整洁架构(依赖规则清晰,便于单测)
强调可替换性(多数据库、多前端)六边形架构(端口-适配器最显式)
团队小、业务简单别用 DDD(过度设计)

实际项目里,我几乎都用 DDD 分层。原因:

六、整洁架构的项目结构

如果选整洁架构,代码组织可能是这样:

com.example.course
├── domain                  # 实体
│   ├── Course.java
│   └── ...
├── usecase                 # 用例
│   ├── CreateCourseUseCase.java
│   └── PublishCourseUseCase.java
├── adapter                 # 适配器
│   ├── in                  # 输入适配器(Controller)
│   │   └── CourseController.java
│   └── out                 # 输出适配器(Repository、Message)
│       ├── CourseRepositoryImpl.java
│       └── EventPublisherImpl.java
└── framework               # 框架配置
    └── SpringConfig.java

七、六边形架构的项目结构

com.example.course
├── domain                  # 领域核心
│   ├── Course.java
│   ├── port                # 端口(接口)
│   │   ├── in              # 输入端口(用例接口)
│   │   │   └── CreateCourseUseCase.java
│   │   └── out             # 输出端口(仓储接口)
│   │       └── CourseRepository.java
│   └── service             # 业务核心实现
│       └── CreateCourseService.java
├── adapter                 # 适配器
│   ├── in                  # 输入适配器
│   │   └── CourseController.java
│   └── out                 # 输出适配器
│       ├── CourseRepositoryImpl.java
│       └── KafkaEventPublisher.java
└── application             # 启动类
    └── CourseApplication.java

注意端口的方向

八、整洁架构 vs 六边形 vs DDD 分层的实际差异

我用一个表格说清楚到底有什么不一样

场景DDD 分层整洁架构六边形
业务代码位置domain/domain/ + usecase/domain/
仓储接口位置domain/repository/domain/port/out/domain/port/out/
仓储实现位置infrastructure/adapter/out/adapter/out/
应用服务位置application/service/usecase/domain/service/(实现 port/in
外部替换改实现类改适配器改适配器

真正的区别在于命名和组织业务内核完全一致

九、我在线上做的一个案例

我们之前做一个在线教育平台,架构选型是 DDD 分层,但借鉴了六边形架构的端口-适配器思想

这样业务核心不关心消息怎么发、WebSocket 怎么推换消息中间件只换适配器

这就是三种架构融合使用的典型场景

十、决策树

你的项目需要什么?
├── 团队小、业务简单
│   └── 别用 DDD,三层架构足够

├── 业务复杂、团队中等
│   └── DDD 分层 + 依赖倒置(推荐)

├── 业务复杂、要支持多前端/多数据库
│   └── DDD 分层 + 端口-适配器(六边形思想)

└── 业务极其复杂、强调可测试
    └── 整洁架构(洋葱)

总结

这一篇我们讲了:

下一篇我们讲中台——在线教育平台的“通用能力”到底应该共享什么。


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
查看系列全部文章
  1. 01.DDD 复杂业务系统设计(一):为什么从“领域”开始,比从“数据库”开始更靠谱
  2. 02.DDD 复杂业务系统设计(二):领域与子域,把“学校/课程/学员”拆成三件事再说
  3. 03.DDD 复杂业务系统设计(三):限界上下文,为什么“课程”在教务和市场是两种东西
  4. 04.DDD 复杂业务系统设计(四):实体与值对象,把“学员”和“地址”放进代码的两种姿势
  5. 05.DDD 复杂业务系统设计(五):聚合与聚合根,一个“选课单”应该装多少东西
  6. 06.DDD 复杂业务系统设计(六):领域事件,让“作业提交”自动触发批改进度
  7. 07.DDD 复杂业务系统设计(七):分层架构,你的“业务代码”应该待在哪一层
  8. 08.DDD 复杂业务系统设计(八):整洁架构 vs 六边形架构 vs DDD 分层,我选哪一种
  9. 09.DDD 复杂业务系统设计(九):中台,在线教育平台到底应该共享什么
  10. 10.DDD 复杂业务系统设计(十):从战略到微服务,一张图跑通 DDD+中台+微服务
  11. 11.DDD 复杂业务系统设计(总结):从领域到微服务,一张图看懂 DDD 落地全流程

上一篇
设计模式之装饰者模式:动态增强,比继承更有弹性
下一篇
设计模式之桥接模式:抽象与实现分离,各自独立变化