重构、技术债与兼容性:功能能用以后怎样继续改

收藏功能运行了半年,现在要加收藏分组。你发现每个页面都复制了一遍保存逻辑,改一个字段要找五个地方。继续复制似乎最快,彻底重写又可能停工很久。维护工作的难点,是在保持用户可用的同时逐步改善结构。

1. 先区分改变结构和改变行为

把重复代码提取成一个函数,而用户仍得到同样结果,这是重构。把收藏上限从 100 改成 200,则改变了行为。两者可以在同一任务中发生,但最好分成能看懂的小步骤。

“重构”不等于任意重写,也不意味着顺便改变错误处理和返回格式。如果新结构导致过去允许的操作被拒绝,就需要重新检查是否已越过保持行为的边界。

2. 先给旧行为加一层保护

面对没有测试的代码,先找它对外暴露的输入和结果,写下当前真实行为。某些行为可能并不理想,但它们帮助你知道哪些变化是意外引入的。确认确实是缺陷时,再单独约定新预期。

对于收藏逻辑,可以先记录重复保存、取消不存在项和失败提示,然后一次只提取一段代码。每一步通过检查再继续。把五个页面一次全部改成新框架,会让出现问题时难以知道是结构变了还是行为变了。

3. 技术债为什么像欠账

为了尽快验证产品,团队暂时采用一个简单但维护成本较高的做法,之后每次修改都要多付时间,这种额外成本常被称为技术债。它不等于“所有我不喜欢的代码”,也不是只有故意偷懒才会出现;需求变化和认识不足也会造成债务。

可以写一张具体的债务卡:收藏规则在三个入口重复,每次变更需要同步三处,已发生一次遗漏;建议收拢共用用例;预计影响三个页面,需回归重复与取消行为。比“代码质量差,需要重构一周”更容易决定优先级。

4. 按后续成本安排偿还

如果某段代码几乎不会再改,立刻重写的收益可能很小。如果每周都碰到同一处重复逻辑,先整理它可能让后续功能更便宜。安全漏洞和数据损坏风险还可能需要更紧急地处理,不能只计算节省多少开发时间。

不必等一个“重构月”才开始。可以在做新需求前先完成小规模结构调整,再增加新行为;也可以在修复缺陷时消除导致同类错误的重复。不过不要无限扩大修改范围,让本来一天的任务变成没有结束条件的重建。

5. 兼容性是对使用者的承诺

如果接口原来返回 saved: true,新版突然改成 state: "saved",旧客户端可能无法理解。能否升级,要看调用方实际依赖的约定,而不是服务端自己觉得字段更漂亮。

语义化版本通常以主版本、次版本、修订号表达公开 API 的不兼容变更、兼容功能和兼容修复,但前提是定义了公开 API,并遵守相应规则。版本号不是自动兼容证明,尤其不能简单认为所有 0.x 升级都安全。

即使只新增枚举值,也可能让严格穷举的旧客户端失败。升级前检查旧客户端的用例、数据格式和部署顺序;需要过渡时明确弃用期限,给出迁移说明。

练习与参考答案

“把所有重复代码都合成一个超级函数”是不是一定更好?不是。两段表面相似的代码可能承担不同业务规则,强行合并会增加条件分支和互相牵制。先判断它们是否因同一种原因变化,再决定共享到什么程度。

阅读依据