一段代码通常不是在某天突然变成"遗留系统"的。它更常见的路径是:第一个临时分支解决了紧急需求,第二个分支复制了这段逻辑,第三个团队不知道原有约定,于是加了另一个入口。每一步单独看都合理,合起来却让修改任何地方都变得危险。我在维护过几年的系统里反复看到这条路径——它几乎从不是某一次"写得差",而是局部变更一次次绕过共同边界。
劣化的是共同理解
格式不统一、命名不好当然会增加阅读成本,但更严重的是边界失效:状态由多个模块同时修改;相似规则在三个地方各写一遍;调用者必须知道本不该知道的内部细节。
接口层面的变化尤其容易把这个问题放大。新的模型不断接入,而最初的设计往往只考虑了一两种接入方式,后来者要么硬塞进旧的入口,要么各自开一个口子——两种做法都在悄悄改变"谁能触发什么"。后来我确实见过这种情况:一旦系统按国家或地区拆分,多国家团队被引入进来,维护成本会成倍上升,因为每个团队都会在自己的边界内做出局部合理的调整,而这些调整彼此并不知情。说到底,这不是某个模块写得差,而是旧设计和业务发展之间的冲突——设计定型时假设的边界,业务已经不再遵守,系统就只能靠不断的动态调整来填这个缺口。
速度不是设计的对立面
"业务快,所以来不及设计"常常是真的;但这不等于只能放弃一致性。设计不是在开始前画一张永远正确的图,而是每次改动前至少回答:这条规则属于谁?新增分支会不会改变已有路径?不确定的部分怎样隔离?
在变化快的阶段,最值得保住的通常不是完整抽象,而是几个最低限度的约束:明确的所有权、可追踪的入口、少量关键路径的测试,以及能说清理由的例外。
用系统减速,而不是靠英雄主义
代码审查的价值不在于找标点错误,而在于让改动者解释边界;测试的价值不在于追求覆盖率,而在于保护不能被悄悄改变的行为;重构的价值也不在于"变漂亮",而在于消除下一次必然复制的结构。
不必承诺把所有旧代码翻新。先找最常改、最常出错、最阻碍多人协作的一段链路,给它补上规则、责任和验证。代码不会永远保持干净,但团队可以让它不那么快失去可理解性。