边界、内聚与耦合:把系统拆得明白,质量才有落脚点

81 阅读8分钟

边界、内聚与耦合:把系统拆得明白,质量才有落脚点

所谓“架构设计的功力”,很大程度上就藏在这三个字:边界、内聚、耦合。

你可能已经能画出一张漂亮的系统图,但真正能把系统拆得恰到好处,让每个模块既高内聚又低耦合,能自由组合、还能独立演化,这件事就不是靠「加几个微服务」能解决的。

这一章想帮你做到三件事情:

  • 理解什么是系统边界、分层边界、领域边界,为什么架构师永远在“分分合合”
  • 用一个记得住的方式理解 7 种内聚和 7 种耦合,知道哪些要追求、哪些要避
  • 手上有一套能实际落地的“高内聚、低耦合”原则,面试时不只会背定义,还能讲真实案例

一、先谈边界:没有边界感的系统,很难谈质量

系统边界有多层,不同层次的边界决定了你后续的质量优化空间:

  • 领域 / 系统边界

    • 类似“国家”级别:比如你的 C2C 电商系统就是一个完整领域
    • 属于 DSSA(领域特定架构) 的范畴,常会参考业内成熟做法
  • 子领域 / 子系统边界

    • 类似“省 / 市”级别:商品域、订单域、发票域…
    • 可以用 ABSD(基于需求) 或 AT(架构思维方法)来拆
  • 分层边界

    • 类似“军区”“高校”这种横跨区域的边界
    • 比如应用层 / 接口层 / 领域层 / 基础层,都会有各自的边界和接口控制

整理边界的方法可以借用三国的比喻:

  • 孙权(继承派,DSSA):参考前人做法,延续成熟经验
  • 刘备(需求派,ABSD):调研用户需求,按业务场景规划系统
  • 曹操(定制派):根据自身资源和优势,量体裁衣做剪裁

真正落地时,大多数团队都会混合使用这三种思路。关键是:

  • 先把边界划清,再谈质量维度(扩展性、性能、可用性、性能、安全、伸缩性)才有意义

二、七种内聚:用王大锤的“相亲 7 日游”记住它们

内聚描述的是“一个模块内部的组件关系”,越靠左越高内聚:

类型特征王大锤的比喻
功能内聚模块里所有元素只干一件事“只爱一个人”
顺序内聚必须按固定顺序执行先和粉衣,后和白衣
通信内聚共享同样的输入/输出都喷香奈儿 5 号香水
过程内聚按统一流程被控制女儿国国王一声令下
时间内聚同一时间一起执行每晚 12 点跑批
逻辑内聚由某个条件/标记区分只要尖下巴我都喜欢
偶然内聚纯粹凑巧放一起完全靠缘分 = 最差

实践中尽量向左靠,功能内聚 / 顺序内聚是我们追求的目标,偶然内聚是要极力避免的。

常见应用:

  • 注册 + 登录:常见的顺序内聚(注册完自动登录)
  • 定时批任务:典型的时间内聚
  • 按 Flag 分支:容易退化成逻辑内聚,要谨慎拆分

三、七种耦合:尽量把连接“松”下来

耦合描述的是“模块之间的关系”,越靠左越低耦合:

类型特征策略
非直接耦合没有直接依赖最理想,只通过第三方间接交互
数据耦合只传必要数据DTO/VO;消息体;函数参数
标记耦合共享同一数据结构尽量拆 DTO,避免 DO 暴露
控制耦合通过控制流 / Flag能不用就不用;必要时把控制逻辑抽出去
外部耦合共同受外部变量影响限定范围,做好配置隔离
公共耦合共享全局数据尽量避免,尤其是“紧耦合型”公共变量
内容耦合直接操作内部实现坚决避免,控制 public 暴露

几个常用的降耦技巧:

  • 用接口隐藏实现(依赖倒置)
  • 减少 DTO 大小,拉开和 DO 的距离
  • 把控制流从模块间搬到调度层
  • 公共数据通过稳定接口访问(仓储层 / DAO),而不是全局变量
  • 内容耦合最危险,能 private 的都 private,public 尽量少

四、如何真正做到“高内聚 + 低耦合”

抽象原则说了一堆,落地时可以抓住这些点:

1. 低耦合设计的关注点

  • 模块间传输的数据越多,耦合越高
  • 传控制信息比传数据耦合更强
  • 接口越复杂(参数多、结构多),耦合越高
  • 重用实现细节(而不是抽象接口),耦合会越来越紧

2. 落地策略

  • 接口 + 依赖反转:面向接口编程,把实现细节藏在模块内部
  • 单处定义 / 命名分离:避免出现 “User” 到处都是却语义不明
  • 禁止全局变量:模块间数据传递全走 DTO
  • DAO 层 / Repository:领域层不直接操作底层数据库 / 中间件
  • 适配器 / Anti-Corruption Layer:领域层和中间件之间加一层适配
  • 限制公共耦合范围:即便共用资源,也要用松散方式(消息 / 事件)

3. 高内聚三原则

  • 功能聚焦:单一职责,模块只解决一类问题
  • 接口隔离:外露的接口越少越好,最好遵循六边形架构那种有限接口数量
  • 一切向功能内聚靠拢:遇到逻辑内聚 / 偶然内聚及时拆分

五、王大锤踩坑记:两个“血泪教训”

1. 一个模块同时服务 CEO / CFO / CTO,结果全挂了

大锤做了一个“员工管理报表模块”,同时满足:

  • CEO:工时 / 加班宣传
  • CFO:工资发放
  • CTO:代码效率监控

然后 CEO 改了工时计算逻辑(对外营销),被 CFO / CTO 的系统直接污染:

  • 账面看起来员工都超负荷,加班工资爆炸
  • 代码效率报告骤降一半,CTO 要裁人

根因

  • 违反单一职责,多个高变业务放在同一模块
  • 偶然内聚,把互不相关的报表强行捆绑
  • 没有考虑后续变更的频率和利益相关方

可以怎么解?

  • 把 CEO / CFO / CTO 的诉求拆成不同模块
  • 引入规则引擎,让“工时报表”可配置,避免硬编码
  • 让工资 / 绩效模块只依赖稳定数据,不受外部宣传逻辑影响

2. 模块依赖环:CFIH 互相引用,导致任何改动都得全量发布

大锤把系统拆成了多个模块(C、F、I、H…),但 CF IH 之间形成了有向环:

  • 只要改其中一处,其他模块都得跟着改 / 跟着发
  • 违反依赖无环原则

解决方案

  1. 合并模块:如果功能确实高度相关,干脆合并成一个模块
  2. 依赖反转:把 H 对 I 的依赖转换为 I 对接口的依赖,H 实现接口
  3. 稳定依赖:抽出一个稳定模块(如用户认证服务),其他模块依赖它

一图胜千言:

I -> H  (原有依赖)
   ↓
抽出接口 IFoo,放在 I 里
H 实现 IFoo

这样就不会形成环,模块可以独立演化。


六、面试高频题怎么答?

  1. “如何划分系统边界?”

    • 提到 DSSA(领域经验)、ABSD(需求驱动)、定制剪裁
    • 最好结合自己项目讲一个「怎么结合需求 vs 领域知识」的案例
  2. “如何定义模块?”

    • 先抛「高内聚、低耦合」的原则
    • 结合一个实际模块设计案例,讲内聚类型 + 耦合控制技巧
    • 别忘了强调“曾踩过的坑”和“怎么化解”
  3. “中间件 / 数据库经常升级,怎么减少主业务改动?”

    • DAO / Repository 层隔离
    • 适配器层 / Anti-corruption Layer
    • 接口 + 依赖反转,让领域层不直接依赖具体中间件
    • 同时提提「稳定依赖原则」会加分

小结:架构的第一步,是把关系捋清楚

边界、内聚、耦合听起来像基础概念,但它们决定了你的系统能否:

  • 随业务变动快速调整
  • 在局部故障时保持可控
  • 在多个质量维度(扩展性/性能/可用性/安全/伸缩)上真正发挥空间

你可以从现在开始练习:

  • 画系统时,不只画“有哪些服务”,还标清楚它们的边界和耦合关系
  • 为每个模块写下它的内聚类型,问自己能不能再向左靠一点

当你习惯用这些维度审视系统时,系统会变得更简单、更清晰,也更容易在质量维度上做提升。下一章,我们就正式进入五大质量维度的核心内容:扩展性、性能、可用性、安全、伸缩性,继续把这套方法走实。+