维护的真相 — 软件在腐败,除非你管住变化
这一章讲四件事: 雷曼四定律——软件为什么注定被改、为什么越改越糟、改动量为什么必须平稳、 以及为什么连「完美的需求」也拦不住演变;治症状不治病的经典反例(主走查); 维护引入错误的机制与「这次很简单」的陷阱;翻新与重写的选择法。这是全书终点: 前十一章防的每一件事,都会随时间再发生一遍。
1. 先看现象:三年的系统,没人敢动
一个运行三年的系统,问它的维护团队:
- 「这个模块为什么这么写?」——「不知道,前年改的,当时赶上线。」
- 「这里看起来是个 bug,能顺手修了吗?」——「别!上次有人顺手修,炸了三个下游。」
- 「这版能多加十个功能吗?」——「上次一次加了十一个,那个版本修了一个月。」
三个回答对应三条规律,书里都给了正式名字。维护(修改软件以满足新功能、跑得更省、修掉错误的工作) 不是开发的收尾杂活——它才是软件一生中持续时间最长的状态1。
2. 顶层全景
系统上线
│ 定律一:会被持续修改(使用催生新需求)
▼
每次修改 = 一次打乱
│ 定律二:熵增加——越改越复杂、越脆弱
▼
对抗手段一:管住每次改动的质量
│ 没坏别修 · 治病不治症状 · 别信「这次很简单」 · 改完回归测试
▼
对抗手段二:管住改动的「量」
│ 定律三:熟悉守恒——版本间改动量忽大忽小,质量就崩
▼
挡不住的那部分:定点翻新(先翻最差的)/ 有时重写
│ 定律四:系统存在本身催生新问题——演变没有终点
▼
直到重写比维护更划算,循环重启(定律一的另一面)
图说:四个定律卡在流程的四个位置:一管「会不会停」,二管「为什么变糟」,
三管「节奏」,四管「终点」。
3. 核心原理
3.1 雷曼四定律:软件的时间物理
Manny Lehman(第 01 章就出场的软件演化研究者)给大型程序总结的规律,书里引了四条2:
定律一:持续变化。 正在使用的大型系统会被不断修改——因为使用会催生新功能—— 一直改到从头重写变得更划算为止3。
定律二:软件越改越乱。 热力学里量「混乱程度」的那个词叫熵(孤立系统会自发地从有序走向无序); 把它用到软件上,持续变化让系统越来越复杂、越来越无序;变化导致不稳定, 所以所有有用的软件都在向更低的可靠性、更差的可维护性漂移4。 每次改动都在结构上留一道疤,疤多了,没人能整体看懂它。
定律三:熟悉守恒。 发布版本之间的改动量,必须相对稳定。书里的数据形态: 某个版本的变化量明显高于平均水平,它就会「性能差,可靠性差,故障率高,成本时间都超支」; 偏离平均越多,风险越大。机制有两层:一是稳定效应——改动本身引发不稳定,大量改动攒出的不稳定, 不是一个发版动作能吸收的;二是心理层——开发者对产品的熟悉感随时间衰减, 版本间隔越久、改动越多,就越是在对「陌生代码」动刀5。
定律四:存在促进演变。 最深的一条:就算你提前写出了「完美」的需求、开发中一个字没改、 系统精确满足需求——演变照样发生。因为把系统引入它要解决的环境,这个动作本身改变了环境, 环境一变,新问题就冒出来6。
四条合起来的姿态:演变不是管理失误的产物,是软件的存在方式。 管理能选的不是「改不改」,而是「怎么改、多快改、多大步改」。
3.2 主走查:那个「除以 2」的反例
原则 188 的例子是「治症状不治病」的教科书演示,值得整段走完7:
现象: 你在排查一个故障,发现某组件每次传出的值,正好是期望值的 2 倍。
解法一(发送端打补丁): 在它传出之前把值除以 2。系统立刻「正常」了。 书里判定它不 合适,两条理由:一,「总是 2 倍」未必对所有情况成立——某个分支里可能是 3 倍, 补丁一盖,错得更大;二,程序里从此存在两个互相抵消的错误——源头错着,补丁错着, 合起来看着对。后来的人读懂这两处任何一处,都会「修复」它,系统当场崩掉。 书里的判词:这会让程序在未来实际上无法被维护7。
解法二(更糟): 不动原组件,让接收方把收到的值除以 2。 上面两条毛病全在,还多一条:未来所有调用这个组件的新代码,拿到的都是没除过的值—— 每个新调用者都要自己再除一次,而没有人知道要除7。
正解: 查程序,弄清「为什么值总是翻倍」,从源头修7。
配套的兄弟原则(原则 187): 你在检查代码时「发现」一个疑似 bug——别顺手修。 很可能你修进去的是新错误;正确动作是记录并提交变更请求,让配置控制(第 11 章 3.2) 和技术评审去判定它是不是 bug、优先级多高8。
两条合起来,就是维护的第一戒律:改动的价值不在「改完看起来正常」,在「改动之后系统仍然说得清」。