评论区那个故事比正文还戳我。一个 AI 代理清理掉了一个"看似死亡"的验证分支,跑完一切正常——然后那个分支捕获的,是一条来自旧支持工单的时区边缘情况。
分支死了,工单没死。
聊回那 200 行。上个月 dev.to 上 Gamya 写了她把数周前快速迭代时攒下的 200 行 AI 生成 Swift 代码全删了的事,文件照常工作,甚至效果更好。
这个结果我不意外。AI 写代码的通病就是多写——重复逻辑、针对不可能情况的防御性检查、只调用一次的辅助函数。它没有"这行到底有没有存在必要"的责任感。多写几行不会出事,少写几行倒可能"看起来错了"。所以人审 AI 代码,最赚的动作就是删。读十遍你也分辨不出哪几行是多余的,删一遍就全露馅了。
但删这个动作,比看起来危险。
Gamya 删到一个"看似无用"的函数时翻车了——那个函数处理的是一个只在特定操作序列下才会出现的 nil 值。删完觉得神清气爽,然后某个用户操作序列下的边缘情况就坏了。她后来在评论里确认:这个 nil 检查是测试没覆盖的承重代码,它一直在那堵着墙,只是没立碑。200 行里绝大部分是垃圾,这个判断没错。唯一出问题的,恰恰是"看起来"和"实际"差距最大的那一小块。
评论区有人说了一句话:删除是最好的代码审查。作者回了一句同样好的:删除键迫使你做出二元决定。读代码的时候你可以骗自己"大概懂了吧",删的时候你骗不了——要么留,要么删,没有中间态。
不过我想补一句反向的:二元决定不保证你判断准确。删了没塌,不代表你懂了,只是运气站在你这边;塌了,也不代表你删错了——塌是好事,承重墙的位置从此被你记住了。她说她从删除中学到的东西比写代码时更多,我信。
作者有个比喻画得也准:每行未经理解的代码都是一笔债务,利息会在日后修改和调试的时候复利。她没有因为这次翻车就拒绝 AI 代码,而是把接受 AI 建议重新定义成"主动背负的债务",定期回读,定期删。这个姿态我服。债务这个概念好用就好用在逼你算账——你接受了什么,就得为理解它付利息。赖账的后果是利息滚到某一次 debug 到半夜,才发现还不起。
我还想多挖一层:AI 生成的代码里藏两种债务。一种是不必要的,删了就是赚;另一种是承重的,你不知道它承重,因为你对这段代码没有历史记忆。Gamya 那个 nil 检查大概率是某天有用户序列触发了崩溃,某次迭代补了一行兜底——当时看起来就是"防御一下",没有注释,没有测试。工具不知道历史,这不是工具的错,是你没把历史交代清楚。可问题在于:AI 生成代码时,连它自己也不知道这行将来要扛什么。工具不知道历史,但它会把历史以报错的形式还给你。
文章末尾 Gamya 注明这篇复盘用了 AI 辅助语法和结构。看到这一行我笑了半天。不是讽刺,是觉得这个循环挺完整的。
最后留一条自己的规则:再看到"这段代码好像没用"的时候,别忍,删掉,跑一遍测试。塌了,那块承重墙就是你的了。
本期缴税:删除是最好的代码审查,唯一的审查标准,是删完以后它会不会塌。
