删掉一半代码,缺陷反而变少:简化也是一种优化

有团队做过一个季度实验:不新增任何功能,只做删代码和简化。季度结束时,他们删掉了服务里将近四成的代码行,同期线上缺陷单数量下降接近四成。没有重构框架,没有引入新工具。

这件事之所以反直觉,是因为我们习惯把代码当作资产。实际上决定价值的从来不是行数,而是一行代码带来的行为。

代码是负债,只是暂时不用还

每一行留在仓库里的代码,都会被反复阅读、被测试覆盖、被依赖升级牵连、被框架迁移扫到。它还会让别人在排查问题时多绕几个弯。

所以判断一段代码值不值得留,可以问一句:如果它今天不存在,我们会主动把它写出来吗?答案是否定的那些,就是候选删除对象。

优先清理这五类

  • 死代码:任何调用链都到不了的函数、类、接口
  • 已经下线功能的开关分支,代码里仍然写着 if (featureEnabled) 两套逻辑
  • 重复的工具函数:三个模块各写了一份格式化时间的逻辑,其中两份没人调
  • 注释掉的旧实现和被注释解释「为什么不用」的大段历史代码
  • 为早已停用的老版本客户端保留的兼容分支

这五类有一个共同点:它们的存在理由都已经消失,但没有任何人负责把它们收走。

怎么确认它真的没人用

顺序不能颠倒。第一步,用静态分析工具找出所有引用点,注意排除反射调用、字符串拼装的类名、配置里写的方法名——这几类最容易漏掉。

第二步,在入口处加一行日志,把相关的调用记录下来,观察一个完整的发布周期。业务的周期性要覆盖到:月度结算、季度报表这类任务可能一个月才跑一次。

第三步,先标记为废弃并加入禁用的 lint 规则,让新代码不能再引用它,确认无新增调用之后再删除。先标记、后观察、再删除,这三步省掉任何一步都可能制造事故。

删减为什么能减少缺陷

缺陷数量和代码路径数量正相关。去掉不可达的分支,直接减少了可能的错误组合;阅读量下降,评审和排查时漏看的概率也随之下降。

还有一个容易被忽略的收益:构建和测试时间缩短。如果一个服务的单元测试从十二分钟压到四分钟,开发者的反馈循环就快了三倍,这会真实地改变他们跑测试的习惯。

批量删除时怎么控制风险

案例里的团队用了四条纪律。按模块分批,每批一个合并请求;单个请求的改动控制在五百行以内,超过就再拆;每批合并后跑一次完整回归,覆盖关键业务链路;每批上线后观察两天线上指标,异常立刻回滚。

还有一个做法值得借鉴:删除时保留一段时间的 git 历史可查,同时把「为什么删」写进提交信息。三个月后如果有人问起,答案在提交记录里,不必靠记忆。

有四类东西不能顺手删

第一类是看起来冗余的兜底逻辑。它可能在某次历史故障里救过场,删除前先翻一翻告警记录和故障复盘。

第二类是涉及数据变更的处理分支。旧字段的处理代码一旦删掉,历史数据再回放就会出错。

第三类是权限、审计、计费相关的代码。它们通常看起来不产生业务价值,删掉的后果却由法务和财务承担。

第四类是没有回归测试保护的区域。没有护栏的地方,先补测试,再谈清理。

别让「删了多少行」变成新指标

凡是能变成数字的东西都会被追指标。有人为了完成删除量,把还在使用、只是暂时没人调用的代码删掉,结果在下一个版本被紧急恢复。

更合理的度量是组合指标:代码总量趋势、构建时长、线上缺陷数的变化。三者一起看,很难通过造假同时改善。

这周可以动手的三件小事

先关掉一个已经下线的功能开关,把对应的两套分支合并成一套;再给持续集成加一条死代码检测规则,让新产生的无用代码当天就被发现;最后在季度复盘里加上一栏「删除行数」,让它成为被公开表扬的行为。

写代码的能力决定你能做多少事,删代码的能力决定你的系统能撑多久

标签:#, #, #