分层架构
分层架构是所有软件架构的基础模型,是"稳定核心 + 可替换实现"的结构化设计方式。无论是 DDD、六边形架构、整洁架构,都可视为分层架构的演进形态。
第一性原理:变化隔离机制
本质机制:变化隔离
软件系统的根本矛盾是变化。分层架构的核心价值在于将变化限制在特定层内,阻断变化传播链。
未分层:变化A → 影响B → 影响C → ...(级联扩散,无法管控)分层后:变化X → 只影响相邻层 → 影响边界确定,可控可预测 ↑ (前提:边界未被破坏)机制实现
分层架构通过以下约束实现变化隔离:
- 边界明确——每层有明确职责,不允许跨层交互
- 单向依赖——上层依赖下层,不存在反向依赖
- 接口抽象——层间通过预定义接口通信,隐藏实现细节
效果:变化被封装在单一层内,同层实现可互相替换而不影响调用方。
核心原则:若上层依赖下层内部实现细节,系统退化为紧耦合
边界
分层架构有效性依赖以下前提:
- 系统存在需要保护的核心模块(如核心业务逻辑)
- 层间有**清晰稳定**的接口边界
- **性能损耗可接受**(每层调用带来开销)
- 团队需要**明确分工边界**
代价
分层架构存在固有代价:
| 代价 | 影响 |
|---|---|
| 性能损耗 | 每层调用增加延迟 |
| 复杂度增加 | 需要管理更多接口和边界 |
| 过度工程化风险 | 简单场景分层成本超过收益 |
分层模式:严格分层 vs 松散分层
核心定义
| 模式 | 约束 | 本质 |
|---|---|---|
| 严格分层 | 只能调用直接下层 | 链路依赖,逐层传递 |
| 松散分层 | 可调用任意下方层 | 跨越中间层,直达底层 |
严格分层:变化传播路径线性,可追踪松散分层:变化传播路径网状,不可预测选择原则
| 权衡维度 | 严格分层 | 松散分层 |
|---|---|---|
| 核心价值 | 变化影响可预测 | 调用路径更灵活 |
| 适用条件 | 依赖拓扑稳定优先 | 性能/简单性优先 |
| 架构健康 | 退化风险低 | 退化/腐化风险高 |
| 维护成本 | 高(需持续约束) | 低(依赖人工约束) |
本质选择逻辑:当"变化影响可预测"更重要 → 严格分层;当"调用灵活性"更重要 → 松散分层
分层的目标
| 目标 | 对应机制 | 价值体现 |
|---|---|---|
| 关注点分离 | 每层只关心本层的问题,不跨层思考 | 降低复杂度 |
| 隔离变化 | 变化被封装在层内,不跨层传播 | 技术变化不影响业务 |
| 可替换性 | 同层实现可互相替换,不影响调用方 | 提高扩展性(可替换基础设施、可添加新表现方式) |
| 可测试性 | 业务逻辑可独立于外部依赖测试 | Domain 可做纯单元测试 |
| 可演进性 | 基础设施可插拔,协议可适配 | 系统能以最小代价适应前端、技术栈变化 |
分层架构的常见问题 & 反模式
污水池
本质:请求穿透多层但每层仅做传递,未执行实际业务逻辑。
判断标准:若大部分请求属于穿透式调用,说明分层不适合当前场景。
为什么会发生:①明知违规但图省事的认知捷径;②大部分请求属于CRUD穿透时,业务本身不需要分层,但团队出于惯性继续坚持;③解决污水池的方法是开放某些层,但这又破坏了层隔离,形成两难。
应对:
- 少部分穿透请求可接受
- 超过阈值则应放松分层约束,允许跨越中间层
- 或合并职责过少的层级
层次过犹不及
问题:为追求"完美分层"增设过多层级,导致性能损耗和复杂度爆炸。
为什么会发生:①层级崇拜——认为"层数越多越专业";②忽视代价——每增加一层就增加调用延迟和复杂度;③完美主义倾向——追求"完美"设计来展示专业性,缺乏何时停止的判断标准。
改进:按变化速度而非物理层数分层,确保每层有足够职责以证明其存在的合理性。
贫血领域模型
本质:Domain 层仅有数据无行为,所有业务逻辑堆积在 Application/Service 层。
危害:
- 业务规则分散,难以维护
- 领域模型失去封装性
- 系统退化为事务脚本模式
为什么会发生:①面向过程思维惯性——大多数开发者从生涯开始就接触三层架构,没有机会使用继承和多态等面向对象特征;②数据库建模先入为主——对象被当作数据载体,而非行为封装体;③技术推力——早期规范和框架鼓励将对象当作数据载体;④便利性诱惑——把逻辑放Service层比塞进领域对象更简单直接。
应对:将业务规则下沉到 Domain,让领域对象自己管理自己的状态和规则。
基础设施反向依赖领域
本质:领域层依赖了具体技术实现,而非通过接口抽象。
危害:
- 技术变化冲击核心业务
- 领域层难以单元测试
- 架构僵化
为什么会发生:①早期快速上线压力——业务逻辑直接依赖具体技术实现,省去接口抽象的额外工作量;②抽象逃避——在领域层定义接口增加前期复杂度,短期看不到价值;③依赖链反转正确做法要求先设计接口,但增加了初始设计成本。
改进:通过依赖反转
边界失效(越界访问)
本质:层间边界被打破,出现跨层调用或循环依赖。
危害:边界失效 → 变化传播失控 → 架构腐化。
为什么会发生:①新成员不了解层间依赖规则;②快捷方式诱惑——"直接绕过去更快";③缺乏检测工具——没有静态分析工具强制执行架构规则;④累积效应——一次越界导致后续效仿,边界名存实亡。
应对:使用 lint 工具构建静态架构规则,防止越界访问。
过度分层 vs 过度合并
| 极端 | 表现 | 后果 |
|---|---|---|
| 过度分层 | 每层职责过小,调用链路过长 | 性能损耗,调试困难 |
| 过度合并 | 多个职责堆积一层 | 紧耦合,难以变更 |
平衡原则:每层应有明确且足够的职责,层间接口应稳定且有意义。
架构选型指南
| 决策维度 | 方向 | 推荐分层程度 |
|---|---|---|
| 业务复杂度 | 高 | 完整分层(Domain 稳定层关键) |
| 业务复杂度 | 低 | 轻量分层(避免过度工程化) |
| 性能要求 | 高 | 简化分层(减少调用链路) |
| 变化特征 | 核心业务稳定 | 完整分层(保护稳定核心) |
| 变化特征 | 基础设施多变 | 简化内部结构(可替换) |
本质决策逻辑:分层程度 = f(业务复杂度, 性能敏感度, 需要保护的核心)
分层架构治理的核心问题
| 问题 | 表现 | 治理手段 |
|---|---|---|
| 越界访问 | 上层直接调用非相邻下层内部实现 | 静态分析工具检测调用链 |
| 循环依赖 | A→B→C→A | 依赖拓扑分析 |
| 反向依赖 | Infrastructure → Domain | 接口抽象 + 依赖反转检测 |
| 职责模糊 | 某层仅做透传,无实质逻辑 | 污水池检测(穿透比例) |
测试策略
| 测试策略 | 适用层级 | 原则 |
|---|---|---|
| API 测试 | Presentation | 无业务逻辑,只验证协议适配与序列化 |
| 集成测试 | Application | 编排多 Domain 服务,验证事务边界与流程 |
| 纯单元测试 | Domain | 业务规则核心,不依赖外部基础设施 |
| Mock 测试 | Infrastructure | 技术实现多变,隔离外部依赖确保可替换 |
核心原则:测试策略取决于层内逻辑的可测试性和变化频率——稳定层(Domain)应纯单元测试,易变层(Infrastructure)应与具体实现解耦。
架构模式对照
核心架构模式
| 架构 | 核心思想 | 依赖方向 | 适用场景 | 复杂度 |
|---|---|---|---|---|
| 分层架构 | UI → Service → DAO → DB(传统) Presentation → App → Domain → Infra(现代) | 上层→下层 | 小型/中型项目、快速原型到业务分层 | 低→中 |
| 六边形架构 | 端口与适配器,内外分离 | 外围→内核 | 多前端、多数据源 | 高 |
| 整洁/洋葱架构 | 业务规则居中心,万物依赖内向 | 外围→内核 | 复杂业务逻辑 | 中高 |
关键区别
| 维度 | 分层架构 | 六边形/整洁架构 |
|---|---|---|
| 依赖管理 | 上层依赖下层 | 外围依赖内核 |
| 业务逻辑位置 | Service层 | Domain层(实体/用例) |
| 基础设施位置 | DAO层 | Adapter实现 |
| 可替换性 | 差,换DB需改Service | 好,替换Adapter即可 |
| 测试性 | 需mock DAO | 可独立测试Domain |
适用判断
- **分层架构**:小团队、需求稳定、快速迭代
- **六边形/整洁架构**:复杂业务、多数据源、需要频繁更换外部服务
核心目标:实现高内聚、低耦合,业务核心不依赖技术栈。
关联内容(自动生成)
- [/软件工程/领域驱动设计.html](/软件工程/领域驱动设计.html) DDD 的分层架构是分层架构在领域建模中的具体实践,Domain 层作为稳定核心
- [/软件工程/架构/架构治理.html](/软件工程/架构/架构治理.html) 维护层边界、防止越界访问是架构治理的核心议题
- [/软件工程/软件设计/代码质量/整洁代码.html](/软件工程/软件设计/代码质量/整洁代码.html) 整洁架构是分层架构的演进形态,明确依赖方向必须指向稳定层
- [/软件工程/架构模式/表现层.html](/软件工程/架构模式/表现层.html) 表现层是分层架构的经典层级之一,负责协议适配与参数校验
- [/软件工程/微服务/服务建模.html](/软件工程/微服务/服务建模.html) 微服务内部采用分层架构实现业务逻辑与基础设施解耦
- [/软件工程/软件设计/代码质量/软件测试/软件测试.html](/软件工程/软件设计/代码质量/软件测试/软件测试.html) 分层决定了测试策略:Domain 纯单元测试、Infrastructure Mock 测试
- [/软件工程/架构/系统设计/架构设计.html](/软件工程/架构/系统设计/架构设计.html) 分层是架构设计中的核心决策,决定了系统的结构化程度
- [/软件工程/架构模式/基本模式.html](/软件工程/架构模式/基本模式.html) 接口抽象、替换性等基本模式是分层架构实现层间解耦的基础
- [/软件工程/架构/演进式架构.html](/软件工程/架构/演进式架构.html) 分层架构是渐进演化的起点,完整分层是保护稳定核心的手段
- [/软件工程/软件设计/代码质量/编码规范.html](/软件工程/软件设计/代码质量/编码规范.html) 编码规范是维护层边界、防止越界依赖的执行保障
- [/软件工程/架构模式/Web框架.html](/软件工程/架构模式/Web框架.html) Web 框架是分层架构的典型实现,框架选型影响层间交互模式
- [/软件工程/架构模式/响应式架构.html](/软件工程/架构模式/响应式架构.html) 响应式架构与分层结合可提升系统的稳定性与可扩展性
- [/数据技术/数据分层.html](/数据技术/数据分层.html) 数据分层与代码分层同构,都遵循稳定性梯度原理
- [/软件工程/架构/架构.html](/软件工程/架构/架构.html) 软件架构是分层架构的上层概念,定义系统整体组织原则