分层与依赖
分层的目标不是画框图,而是限制依赖方向:内层不知道外层,领域逻辑不依赖框架细节。下面是一套在单体、模块化单体与多服务里都适用的默认结构。
四层职责(逻辑视图)
| 层 | 职责 | 允许依赖 |
|---|---|---|
| 表现 | HTTP/UI/CLI、序列化、鉴权入口 | 应用层接口 |
| 应用 | 用例编排、事务边界、DTO 映射 | 领域层 |
| 领域 | 实体、值对象、领域服务、不变式 | 无基础设施 |
| 基础设施 | DB、消息队列、第三方 SDK 实现 | 实现领域/应用定义的端口 |
依赖规则:箭头只能向内(表现 → 应用 → 领域;基础设施通过接口「注入」领域,而非被领域 import)。
[ UI / API ] → [ Use cases ] → [ Domain ]
↑
[ Adapters: DB, MQ, HTTP client ]
与「整洁架构 / 六边形」的对应
| 术语 | 本笔记中的位置 |
|---|---|
| Entity / Domain model | 领域层 |
| Use case / Interactor | 应用层 |
| Controller / Presenter | 表现层 |
| Gateway / Repository impl | 基础设施适配器 |
端口(interface)放在靠内层的一侧;适配器在外层实现。换数据库或换 UI 框架时,理想情况是改适配器而非改领域规则。
单体 vs 模块化单体 vs 服务
| 形态 | 何时合适 | 分层注意 |
|---|---|---|
| 单体 | 小团队、探索期、强一致事务 | 用包/模块名强制依赖规则(ArchUnit、SwiftPM targets) |
| 模块化单体 | 中等规模、需独立编译测试 | 每模块公开 api 面极小 |
| 多服务 | 独立扩缩、不同发布节奏 | 每层可能变薄;契约(OpenAPI/事件 schema)取代内存调用 |
提示
默认:先模块化单体 + 清晰边界;拆服务用「发布频率 / 扩缩 / 故障隔离」驱动,而不是组织图。
常见违规与修复
| 违规 | 后果 | 修复 |
|---|---|---|
| 领域 import ORM 注解 | 换存储牵一发动全身 | Repository 接口 + 基础设施映射 |
| Controller 写业务规则 | 重复逻辑、难测 | 抽到应用/领域服务 |
| 跨层 DTO 泄漏 | API 变更破坏内部模型 | 边界处映射(Mapper) |
| 「工具包」被到处引用 | 隐形全局依赖 | 拆成端口或内联到单一适配器 |
测试策略(按层)
| 层 | 测试类型 | 目标 |
|---|---|---|
| 领域 | 纯单元测试 | 不变式、状态机 |
| 应用 | 用例测试(fake 端口) | 编排与事务 |
| 基础设施 | 集成测试 | SQL、真实 broker(可容器化) |
| 表现 | 契约 / E2E 抽样 | HTTP schema、关键用户路径 |