模块不该按流程切,而应把最可能变化的决定藏起来
分解系统时,优先把可能改变的设计决定封装在一个模块内,而不是照处理流程把每一步各切一块。
谁在何时、何处提出
戴维·帕纳斯在1972年发表的〈系统分解为模块应采用的准则〉(On the Criteria To Be Used in Decomposing Systems into Modules)中明确讨论了这一思想。定位:《Communications of the ACM》15卷12期,第1053—1058页;两种分解比较与结论见第1056—1058页。
论文收稿于1971年、修订于1971年11月,发表于1972年12月。链接为拉法叶学院课程保存的期刊全文转录;卷期与页码另由ACM DOI记录核对,本次未直接比对纸本。
原文、核心意思与误读
“Every module … is characterized by its knowledge of a design decision which it hides from all others.”自然译为:每个模块以掌握并向其他模块隐藏某项设计决定为特征。
帕纳斯用同一索引生成系统比较两种分法。传统分法按输入、处理、输出等步骤切开,多个模块都知道数据格式和算法细节;另一种分法让每个模块围绕一项可能变化的决定建立接口。后者的价值不是文件更整齐,而是改变一个决定时,受影响的知识不必散落全局。
常见误读是“所有字段都设为私有”或“类越多越模块化”。信息隐藏关心的是别人不必知道什么,尤其是可能变化的表示、算法、设备或策略;语言中的private只是手段。另一误读是按团队名单直接切服务。若接口仍暴露内部决定,服务数量增加只会增加通信。
日常例子是报告系统让十个表格直接读取供应商CSV列名。供应商一改列名,十处同时损坏。若一个导入模块把外部格式转换成稳定的内部结构,变化集中在一处。可观察结果是一次变更需要触碰多少文件和多少负责人。
为什么落实起来仍有阻力
本篇归入A类:观点少为普通读者系统了解。没有找到可靠的总体采用率数据,以下是对执行阻力的分析。
第一,流程图在需求早期就能看见,哪些决定最可能变化却需要经验和预测。第二,短期内直接共享数据更快,封装的收益要等变化发生才显现。第三,接口所有权跨团队时,局部绩效可能鼓励把维护成本推给使用者。这些是实践推断;原文展示设计比较,不提供行业采用率。
今天做一个小实验
这是据上述思想设计的个人练习,不是原作者的标准实验,也不预先保证一定有效。
用45分钟检查一个你维护的表格、脚本或工作流程。前10分钟列出三项可能变化的决定,如文件格式、排序规则、通知渠道;用10分钟搜索每项知识散落在哪些位置;用10分钟选最分散的一项,画出一个稳定输入和输出;再用10分钟做最小包装,例如单独公式区或转换函数;最后5分钟模拟一次变化,记录需要修改的位置是否减少。练习据论文原则设计,不要求立刻重构生产系统。
什么时候不宜照搬
只有一次性使用的小脚本,新增抽象层可能比未来修改更贵。隐藏也不能变成不记录:模块内部仍需测试、文档与责任人。安全、审计和跨系统协议有时必须公开关键约束。预测错误时,边界应允许调整,而不是为了维护旧架构继续扭曲需求。