软件永远不会「完成」

读完这篇文章,你会理解为什么软件永远不会"完成"——以及这背后隐藏着五条可以预测的规律。

一个被忽视了 40 年的发现

1977 年,美国在编程上的花费超过 500 亿美元,占当年 GNP 的 3% 以上。其中 70% 不是花在开发新软件上,而是花在维护已有软件上。这个比例至今没有根本性改变。

1980 年,伦敦帝国理工学院的 Meir Lehman 在《Proceedings of the IEEE》上发表了一篇论文,试图回答一个被大多数人忽视的问题:为什么程序总是需要不断修改?他的发现远比"软件有 bug 所以要修"深刻得多。通过对多个大型系统的长期观测,Lehman 提出了软件进化的五条定律——这些定律描述的不是应该如何,而是 必然如何

四十多年后,这五条定律依然成立。它们对今天的每一次版本迭代、每一次架构决策、每一次"我们重写吧"的冲动,都有着直接的解释力。

三种程序,三种命运

Lehman 对程序做了一个精准的分类。他按程序与现实世界的关系,将程序分为三类:S、P 和 E。

S-programs(规约驱动型):功能完全由形式化规约定义,与外部世界无关。八皇后问题、求最小公倍数、排序算法——正确性可以严格证明。S-programs 是静态的:改了规约就是新程序,旧程序不需要"进化"。

P-programs(问题求解型):问题可以精确陈述,但解决方案必须在现实世界中检验。国际象棋程序、天气预报、旅行商问题——你能写出理论完整的解法,但它的"好坏"取决于和现实的比对。用户的反馈、环境的变化会驱动你修改程序,但你修改的不是程序本身,而是你对问题的理解。

E-programs(嵌入型):程序成为它所建模的世界的一部分。操作系统、空中交通管制、库存管理系统——一旦部署,程序就改变了它所处的环境。用户根据系统的行为调整自己的习惯,系统又需要适应用户的新习惯。这是一个无法逃脱的反馈环。

这个分类的价值不在于学术上的优雅,而在于它揭示了一个残酷的事实:大多数真正重要的软件系统都是 E-programs,而 E-programs 天生就需要不断变化。 这不是管理不善、需求不清或程序员能力不足的结果——这是软件与世界交互的本质决定的。

SPE 三类程序与外部世界的关系 规约 Specification 问题的抽象描述与形式化定义 现实世界 Real World 物理环境、人类行为、社会机构等不可控因素 S-programs 规约驱动 完全由规约定义 定义 (不接触现实世界) P-programs 问题驱动 抽象 + 现实验证 定义 检验 反馈修正规约 E-programs (嵌入现实世界内部) E-programs 嵌入现实世界 影响 反馈 复杂度递增 →

软件进化的五条定律

Lehman 的五条定律不是设计原则,而是观测结论。他通过长期追踪多个系统的演化数据,发现了统计上的规律性。这些规律不是物理定律那样的铁律——它们来自人类和组织的决策行为,但在实践中表现出令人惊讶的稳定性。

第一定律:持续变更

一个被使用的程序,要么持续变更,要么逐渐丧失有用性。变更或衰亡的过程会持续,直到判断重建系统比维护更划算为止。

这不是关于 bug 修复的观察。这是说,只要程序在被使用,它所建模的现实就在变化,程序就必须跟上。停下来就意味着衰亡。Lehman 在论文中明确指出:软件不像硬件那样会因为磨损而失效,软件的"失效"是因为它所服务的世界变了,而它没有变。

第二定律:复杂度递增

不断变更的程序,其复杂度会增加——除非主动投入工作来维持或降低它。

这是熵增定律在软件世界中的映射。每一次变更都在已有结构上叠加新的逻辑,新的逻辑与旧的结构之间产生张力。系统变得越来越"硬"——变更越来越困难,成本越来越高,引入错误的风险越来越大。这就是技术债务的本质:不是你不还,而是 每做一次变更,债务就自动增加一些

第三定律:自调节动力学

程序进化受一种动力学支配,使得编程过程和全局项目属性呈现自调节特征,具有统计可确定的趋势和不变性。

这是五条定律中最抽象的一条,但也是最有洞察力的。即使项目中的每个人都觉得自己在做独立决策,这些决策汇聚起来却呈现出全局的规律性。发布间隔、变更速率、系统规模的增长曲线——这些指标在统计上是可以预测的。决定这些规律的,不是某个天才架构师的设计,而是组织结构、反馈机制和系统内在属性的共同作用。

第四定律:组织稳定性守恒

在程序的生命周期中,编程项目的全局活动率在统计上是不变的。

往一个成熟的项目里加人,并不会让产出等比例增加。项目存在一个"饱和"状态——超过这个状态,额外的人力不会转化为有效的额外产出。这和 Brooks 在《人月神话》中的观察一致:人与月的不可互换性不是管理问题,而是复杂系统内在的约束。

Lehman 进一步指出,这种稳定性来自组织本身的惯性。工会、审批流程、决策时滞、个人对变化的抵抗——所有这些因素共同作用,使得组织的产出率趋于稳定。这不是效率低下的表现,而是系统自我保护的机制。

第五定律:熟悉度守恒

连续发布版本的内容(变更、新增、删除)在统计上是不变的。

每次发布能吸收的变更量是有限的。试图在一个版本中塞入过多的变更,结果几乎必然是质量下降、交付延迟、后续版本需要大量修复。Lehman 用数据证明了这一点:变更量超过平均值两倍的版本,无一例外地出现了严重的质量问题。

第一定律:持续变更驱动系统演化的核心动力 第二定律:复杂度递增不可避免的副产品 第三定律:自调节动力学全局约束,呈现统计规律 第四定律:组织稳定性守恒人力资源上限 第五定律:熟悉度守恒变更吸收上限

一个真实的案例

论文中最有说服力的部分是一个代号 "System X" 的案例分析。System X 是一个通用批处理操作系统,Lehman 获得了它连续 19 个版本的完整演化数据。

第 20 版的计划是加入一个大型交互式终端支持功能(ITS),涉及 750 个新模块,预计变更约 6000 个模块,18 个月完成。表面看很合理。

但 Lehman 用进化动力学模型分析后,发现了多个危险信号。ITS 的互连比(Interconnection Ratio)只有 2.4,而同类变更通常在 8.2 左右——这意味着设计者很可能把 ITS 当成了一个独立模块,低估了它与其余系统的耦合程度。按趋势外推,第 20 版的模块变更比例将达到 64%,远超历史平均水平。增量增长超过平均值的 5 倍,是推荐上限的 2.5 倍。

Lehman 的建议是:不要一口气发第 20 版。先做一个清理版本,修补第 19 版的遗留问题,为 ITS 的引入打好基础;然后发一个受限发布,只在选定站点部署 ITS;最后做一个正式的通用发布。

历史验证了他的判断。最终包含 ITS 的版本实际变更了 58% 的模块,第一次发布严重延迟,质量不佳,超过 70% 的模块在后续版本中不得不再次修改。

这个案例的核心启示不是 Lehman 多厉害,而是:当你用数据驱动的方式规划版本时,可以预见风险。当你只凭直觉和业务压力规划时,你只是在赌。

站在 40 年后

Lehman 的论文发表于 1980 年。今天回看,有些东西变了,有些没有。

变了的是工具链。我们有 Git 做版本控制,有 CI/CD 做自动交付,有云基础设施做弹性伸缩。但没有变的是:软件仍然需要持续变更,复杂度仍然在持续增长,往一个迟缓的项目里加人仍然于事无补。

更值得注意的是,Lehman 的 SPE 分类在今天有了新的含义。现代的 SaaS 平台、AI 系统都是典型的 E-programs——它们不仅服务于用户,它们 塑造 用户的行为,然后又需要适应用户被塑造后的新行为。推荐算法改变了人的阅读习惯,社交平台改变了人的社交方式,然后这些系统又需要适应"被它们改变后的用户"。Lehman 在 1980 年画出的反馈环,在今天比任何时候都更紧密。

结合 软件工程哲学 中 Brooks 的"没有银弹"论断——本质复杂度决定了软件永远不可能"一次做对"——和 Lehman 的定律,我们可以看到一个完整的图景:软件永远不可能"做完"。理解这一点,不是为了悲观,而是为了制定更聪明的策略——与其追求完美的初始设计,不如建立 可持续的演化能力


Lehman 在论文结尾写道:软件规划不能再仅仅基于表面的业务需求和市场考量,不能再仅仅依赖管理者的局部视角和直觉。四十多年过去了,这句话仍然是大多数软件项目最常违反的规则。

下一次你面对一个"加个功能而已"的版本计划时,不妨问自己:这个变更会触及系统多少模块?上一个版本的变更量是多少?这次的增量是不是超过了历史平均的两倍?如果你能回答这些问题,你就已经在用 40 年前就应该被广泛使用的方法做软件规划了。