跳到主要内容
越干净的 diff 越像迷彩服

越干净的 diff 越像迷彩服

摸鱼办主任
摸鱼办主任

· 阅读约 6 分钟

上周我 review 一个 PR,十四个文件,命名规范,注释齐整,PR 描述写得比我年终总结还周到。我看了四分钟,点了 Approve。

【此处应有掌声。没有也行,反正线上也不会给你鼓掌。】

先声明一句:这个例子不是我的,是从 John 那篇发在 dev.to 上的文章里借来的,我把它套在自己身上讲,因为套上去毫无违和感——这才是最吓人的那部分。

人对绿色按钮是有肌肉记忆的。

diff 里一旦没有那种“这里我也不知道自己在写什么”的痕迹,脑子就自动切进批处理模式:滑、滑、看到测试文件绿油油、Approve。全程比泡一杯速溶咖啡还快。

评审者的状态机其实只有三个态:读懂了、假装读懂了、看见绿色勾。

第三个是吸收态,进去就出不来。想出来只有一个办法——线上报警。

说回我那次四分钟的 review。第三分钟我其实已经不看代码了,我在想中午吃什么。第四分钟我点 Approve,一部分原因是它写得确实比我好,我有点不好意思挑刺。

这心态可以概括成一句话:反正它是 AI 写的,出事了也不是我写的。

可惜 on-call 名单上印的是我的名字。

所以问题不在你懒。问题在这个 diff 是专门长成你疲劳时最不想细看的样子——它不骗你,它只是刚好符合你放行的所有外观特征。

【寻人启事】

特征:在 review 时会主动追失败路径的人。已知行为:会问“这个操作中途挂了会怎么样”。最后一次出现:不详。

悬赏:一次不用回滚的发布。

顺便,评审容量是这栋楼里唯一不 scalable 的东西,它的上限由人的耐心和膀胱共同决定。PR 数量翻倍,评审的人还是那几个。

AI 在局部真的写得很好,类型对、命名对、单文件逻辑顺。它漏掉的是那种写不进函数签名里的东西:幂等、事务边界、权限范围、失败了一半怎么退回来。

这些玩意儿有个共同特征——它们不在任何一个文件里。所以它们也不在模型的视野里。

那篇文章给的例子,我复述一下骨架:一个升级订阅的接口,外部扣费没带幂等键,积分是内存里读出来加一下再写回去,订阅表和用户表分两次落库。上线之后三连击——网络重试重复扣钱,并发请求丢更新,第二次写库失败,于是钱扣了、套餐改了、积分没到。

用户被扣了两次钱,我们的日志一片绿。

CI 从头到尾没红过一次,因为它压根不知道“钱”是什么。

有人会说,先灰度发布啊。

灰度发布只稀释概率,不稀释错。重复扣费这件事,在 10% 的流量里依然是 100% 的重复扣费,只是账单薄一点、投诉晚两天。

更妙的是测试。同一个 prompt 让它写实现也让写测试,于是测试断言的正好是实现干的那些事:mock 掉 billingClient,mock 掉 db,断言用户积分加了 500。通过了。

自己出卷子自己考,还考了满分。

这种测试的正经名字叫镜像测试,实际作用是给 diff 镀一层绿光,让评审者点 Approve 的时候更放心。测试在这儿不是护栏,是迷彩服上那片最逼真的叶子。

说到幂等,我现在看到这三个字有点心梗。

不是因为它难,是因为它太容易被写成一行注释——// idempotent,端端正正摆在那儿,像个符。

符是给自己看的,键是给系统看的。这中间差着一次重复扣费。

顺带说个题外观察:需求方其实是最幂等的系统——同一个需求提七次,结果和第一次一模一样,但每次都要重新评估一遍。

那篇文章还给了一份审查清单:单 PR 逻辑改动控制在 250 行以内、堆叠拆 PR、先审计测试。清单本身没毛病,清单的宿命是被打印出来贴在工位隔板上,然后没人看。

评论区比正文狠。有人指出它那个修复方案里,外部收费成功、本地事务失败照样回滚不了,读一下幂等键记录也不等于加锁;还有人建议去实现之外找真值来源。这些我不展开——展开就成另一篇了,打住。

那份调研说,日常用 AI 写代码的团队接近九成。

这数字我信。剩下那一成,我猜有一半在装作不用。

真正的坑在这儿:PR 数量翻倍,评审容量不变,于是“我们 PR 吞吐提升了 40%”这句话翻译过来是“我们把核验这一步压缩了 40%”。

把 PR 速度当生产力指标,相当于给技术债开了自动续费。

每月一号准时扣款,不提醒,不退订,也不开发票。

评论区有人用 understanding debt 概括这件事,我觉得这个词比原文标题好。库存是看得见的,债是利滚利的。代码合进去了,理解没跟上,这笔账就挂在下一个半夜被叫起来的人身上。

而那个人大概率是三个月后的你,且那时的你已经不认识这段代码了。

【明日天气】局部地区有静默故障,概率一成,建议随身携带幂等键出行。

我自己也点过那种 Approve,点完还在心里夸了一句:这次 AI 写得真不错。

后来我想明白了:AI 确实有时候会显灵,一口气把补偿逻辑、幂等键、回滚全写对。但显灵不是能力,显灵是抽样。

抽到好的那次,你以为自己升级了。抽到坏的那次,你在凌晨三点渡劫,渡到一半才发现雷早在 merge 那天就劈下来了。

所以现在看到“AI 这次写得真好”,我第一反应不是高兴,是它这次在哪儿偷了懒。通常在没看的那些文件里。

还有一层更土的现实:在本来就烂的代码上让 AI 生成新代码,本质是屎上雕花。区别只是雕得快了三倍,花也更像花。

真出事那天,复盘会上会有人说:这个 PR 当时不是 review 过了吗。

是的,review 过了。四分钟。

(友情提示:下次看到特别干净的 diff,先别夸,数一下它跨了几个系统边界。数不出来的时候,那玩意儿通常已经在路上了。)

评论区扣个“我也点过”,我们下条再见 🫠