4. 模块边界拆分原则(上):单一职责原则(SRP)、高内聚低耦合、限界上下文(DDD)
模块边界拆分是企业架构中最具挑战性的决策之一。错误的边界会导致系统耦合紧密、变更扩散、故障蔓延。本章聚焦三大核心原则:单一职责原则(SRP)、高内聚低耦合、限界上下文(DDD),为模块划分提供可操作的判断标准。
4.1 单一职责原则(SRP)
在模块边界拆分语境下,SRP 的含义是:一个模块只应对一个业务角色或一个变化原因负责。当多个职责被塞入同一模块时,任何一个职责的变化都可能迫使整个模块重新部署、测试甚至回滚,增加了故障半径。
核心判断标准: 如果一个模块需要同时为两个不同的业务方(如财务与运营)提供变更支持,且变更节奏不同,则说明该模块违反了 SRP,应当拆分。
| 对比维度 | 违反 SRP 的模块 | 符合 SRP 的模块 |
|---|---|---|
| 变更原因数 | ≥ 2 个独立业务方驱动 | 仅 1 个业务角色驱动 |
| 部署频率 | 低频(需协调多方排期) | 高频(独立发布) |
| 故障影响范围 | 一个职责的故障会连带影响其他职责 | 故障隔离在单一职责内 |
| 测试复杂度 | 需要同时 mock 多个上下文 | 仅需 mock 当前上下文 |
实践检查清单:
✅ 模块名称是否包含“和”、“与”、“及”等连接词?
✅ 模块的变更是否经常只影响其中一半功能?
✅ 模块的单元测试是否因为职责混杂而难以覆盖?
✅ 模块名称是否包含“和”、“与”、“及”等连接词?
✅ 模块的变更是否经常只影响其中一半功能?
✅ 模块的单元测试是否因为职责混杂而难以覆盖?
4.2 高内聚低耦合
高内聚与低耦合是模块边界拆分的两个互补维度:
- 高内聚:模块内部的元素(类、函数、数据)应围绕同一业务目标紧密协作,对外暴露最小接口。
- 低耦合:模块之间的依赖应尽可能少且稳定,避免循环依赖和跨模块的共享可变状态。
在故障恢复场景中,低耦合意味着一个模块的崩溃不会直接拖垮相邻模块;高内聚则确保故障定位时只需在模块内部排查,无需跨模块追踪。
常见陷阱: 很多团队误将“接口数量少”等同于低耦合。实际上,如果两个模块通过共享数据库表或分布式缓存直接读写对方的数据结构,即使接口只有一个 RPC 调用,它们仍然是紧耦合的。真正的低耦合要求 数据所有权清晰,模块之间只通过契约(API/事件)交换必要信息。
4.3 限界上下文(DDD)
领域驱动设计(DDD)中的限界上下文为模块边界提供了最直接的业务映射。每个限界上下文拥有独立的:
- 通用语言(Ubiquitous Language):团队内部统一术语,避免歧义。
- 领域模型:只包含当前上下文关心的概念,不包含无关属性。
- 数据存储:原则上每个限界上下文拥有自己的数据库或 schema。
限界上下文之间的协作通过上下文映射(Context Map)定义,常见的集成模式包括:
| 集成模式 | 适用场景 | 耦合度 | 故障隔离能力 |
|---|---|---|---|
| 开放主机服务(OHS) | 一个上下文对外提供标准化 API | 低 | 强 |
| 发布语言(PL) | 通过共享事件模型异步通信 | 极低 | 最强 |
| 防腐层(ACL) | 集成遗留系统或第三方 | 中 | 中(取决于 ACL 实现) |
| 共享内核 | 两个上下文必须共享部分模型 | 高 | 弱(需谨慎使用) |
限界上下文 vs 微服务: 一个限界上下文可以拆分为多个微服务,但反过来不成立——多个限界上下文不应合并为一个微服务。在故障恢复实践中,每个限界上下文应具备独立的部署单元和故障域。
4.4 三大原则的协同应用
在实际拆分决策中,三个原则需要综合使用:
- 先用限界上下文识别业务领域的自然边界,画出粗粒度的上下文地图。
- 再用 SRP 检查每个上下文内部是否混杂了多个变化原因,必要时进一步拆分。
- 最后用高内聚低耦合验证模块间的依赖关系,消除循环依赖和共享可变状态。
避坑提醒: 不要试图一次性完成完美拆分。建议采用“演进式架构”思路:先按限界上下文做粗粒度拆分,在后续迭代中根据 SRP 和高内聚低耦合的反馈逐步细化。过度设计的前期拆分往往比不拆分更危险。