一个工程师在电商公司做后端,团队里待了一年多,接手了订单履约系统里一个仓库路由的子模块。这个模块不大,几千行 Python,跑了好几年,补丁叠补丁。哪个仓库有货、哪个仓库离用户近、哪家快递更便宜、爆仓期间怎么避开,这些约束没有显式声明,散落在十几个变量的赋值和一串 if-else 里,靠函数之间的隐式约定维持一致性。想查某个订单为什么被分到了远端的仓库,要从入口函数读到最底层,路径上至少拐三次。他的形容是,改一个参数像拔一根草,你不知道底下连着哪根水管。
他用 AI 把这个子模块重写了一版。仓库选择规则用类做了显式声明,路由逻辑从九十行压到四十行,代码自带注释,历史 regression case 全部跑通。他没有动模块外面的东西,改动限制在这个子模块的边界内。他觉得自己做了一件合理的事:范围可控,测试可验,旧代码里最碍眼的那块隐式反推被清理掉了。PR 发出去,被拒了。
拒他的是一位在这套系统上工作了两年多的同事。理由只有一句话:改得太大,没和我对过设计,我看不懂新版本出了问题要怎么排查。reject note 里写的是:你把自己当成消费者,把这个子模块当成你的产品来改,但它跑在我负责的系统里。出了问题半夜被叫起来的不是你。
两个人都不是坏人,也不蠢,但都觉得对方不讲理。年轻人觉得我改的是一个边界清楚的子模块,旧代码里最乱的那块隐式反推被清理掉了,回归测试全绿,范围可控,凭什么不行。为了保险,他把所有历史 regression case 跑了一遍,一个没挂。老同事觉得你拿一个不了解这些补丁背后发生过什么的工具,把这个子模块的内部逻辑整个换了,我连你改了什么都没有参与讨论,突然甩过来一个几千行的 diff,我凭什么签字。老同事的逻辑也站得住:这段代码不是我 review 的、不是我设计的,但它跑在我负责的系统里,出了问题半夜被叫起来的人是我,不是你。我不签字天经地义。他心里还有一句没说出口的话:你能一天写完的代码,review 的人也要一天才能读完。以前做这种改动要花一两周,团队预算里同时包含了写和审。现在你一天写完,团队收到了一天份的代码和一两周份的认知负债。
这场冲突的病灶不在代码质量上。老同事拒绝的真正指向是:设计选择还没在团队里达成共识,就已经变成了几千行代码。他那句话想表达的是,我还来不及说出我在乎什么,你已经替我做了决定。
做过几年工程的人都明白,系统难的不是写代码,是决定一组互相矛盾的目标里保哪个、牺牲哪个、牺牲到什么程度。调度系统里,吞吐优先还是延迟优先,内存省着用还是多缓存一次少算一次,出故障先保线上服务还是先保数据不丢。同一套调度骨架,电商团队要的是极致吞吐、偶尔丢一两台机器可以容忍;金融团队要的是每条链路可追溯、宁可慢不能丢。同一个代码库没法同时满足两种偏好。这些选择没有标准答案,只有上下文。
AI 帮你写出了代码,但它不知道你的客户 SLA 签了几分钟,不知道你老板在月度 review 里最怕看到哪个指标变红,不知道去年双十一那次全链路雪崩是因为某个隐藏假设扛不住瞬时流量炸的。这些知识不在代码仓库里,在人的脑子里。AI 只能读你已经写出来的东西,而你写出来的东西里通常没有这些信息。不是你不肯写,是这些判断太琐碎、太扎根于具体场景,没有人会在设计文档里写”我们这个模块不能丢任务,因为去年丢了一次,VP 在全员会上点过我们的名”。
旧代码虽然丑,每一处看似多余的分支背后都可能对应一次事故。它是团队集体记忆的一种储存形式,只不过格式不太好读。重构之前,要先有人把这份记忆翻译出来,让团队确认哪些是垃圾、哪些是挡箭牌。
以前人工编码慢。慢这个缺点自带一个好处:它迫使团队在中间停下来讨论。一个资深工程师要做大重构,不会一口气写完再通知大家。他会先写一份设计文档,讲清楚为什么要改、改哪些、不改哪些、风险在哪。大家吵完一轮,再动键盘。代码的产出节奏像在冰面上走路,踩每一步之前都要确认能承重。这个节奏烦人,但它保证了每一块冰都有人踩过、有人看过、有人争执过。
现在 AI 把实现成本打到接近零。你不用确认冰够厚,因为你跑得比冰面开裂还快。代码以过去十倍的速度膨胀,争议以同样的速度变成了 diff。但设计取舍的工作量一点没少,只是不再有自然的机会讨论了。团队对设计假设的对齐速度并没有同步加速。以前要花两周团队讨论才能定下来的决策,现在一个人加 AI 在周末就能把它变成几千行可运行的代码,推上来让大家在 PR 里发现。
资深同事的焦虑有明确的来源。新来一个强 senior 做大重构,代码也会陌生,但他有经历过那些事故的信用、提前沟通了意图、能解释每一个取舍的理由、也承担出问题的后果。Junior 加 AI 的组合,独缺这一整套信用链。代码的质量可能不差,但代码背后那个人的判断还没有被团队实测过。
这背后有两个更深的问题。
第一个是工程设计缺位。核心调度算法的正确性不仅仅取决于它能不能跑通历史 case。旧代码里那些恶心的分支,有一部分确实是技术债,当年赶工留下的硬编码、来不及清理的实验性逻辑。但也有一部分是事故记忆:那行看起来没什么道理的超时重试逻辑,是因为前年有一次网络抖动导致任务重复下发,当天所有机器瞬间被打满。AI 读这段代码时,看到的是一个 if 语句,看不到语句背后的那一天。更危险的是,AI 在重构时可能把这些看起来多余的逻辑当作冗余优化掉,而优化掉之后没有回归测试能抓到。触发条件是一个三年一遇的网络异常,你不可能为每一个异常写一条 case。测试能验证你知道的事,验证不了你不知道的事。
它长成那个样子,往往是因为那样写才能挡住某次已知的线上问题。显式建模资源的方向完全正确,把它做出来也确实有价值。但保住哪些旧行为、故意改变哪些旧行为、哪些行为目前无法判断先保留,这个判断不能外包给任何一个不知道上下文的人或工具。这件事和 AI 能力无关,和写代码的是谁也无关。哪怕换成组里最资深的人来做这次重构,他也得先找当年处理过那些事故的人坐下来聊一圈,才能动手。区别只在于资深的人知道自己需要聊这一圈,而 junior 配着 AI 以为自己不需要。
第二个是维护风险转移。Junior 用 AI 一天能写出过去一周的代码量,但团队的 review 能力、理解能力、出问题后接手排查的能力并没有同步提高。你做了一次架构变化,拿到了效率收益,后续维护的风险却可能落到别人身上。做出关键设计取舍的人是你,承担长期维护后果的人未必包括你。这不是 AI 特有的问题。任何一个组织里,谁决策和谁承担后果之间的错配,都是摩擦的源头。AI 只是把这种错配的频率和幅度都放大了。以前做一次大重构要花两周,一年也就干两三次,每次风险窗口虽大但低频。现在一周能推三次,每次的风险窗口都比以前开得更大,而你的同事还在用原来审两周代码的节奏来面对一周三次的 diff。
怎么解。不要试图证明 AI 写的代码比人写的好,对方反对的本来就不是代码质量。证明代码质量反而绕开了真正的问题。
把争论对象往上移一层。组织一次设计评审,会议里先不看代码。先回答这几个问题:这个系统为什么难改,原来的隐式逻辑造成了什么真实损失,新方案显式建模了哪些东西、哪些仍然没建模、为什么就停在这里,新方案保住了哪些旧行为、改变了哪些、为什么这样选择,出问题怎么 trace、怎么回滚、谁第一响应。这些问题不关心缩进、命名和函数长度,只关心取舍。取舍才是老同事真正在等的答案。
把这些共识写成文档,再把文档喂给 AI,让它按设计文档重写。AI 写代码的成本本来就低,你真正要珍惜的是团队对系统的共识。代码反正可以重写。既然 AI 写代码快到几乎免费,哪怕设计被推翻了重做一版,额外损失也不多。把这次重构当成原型,当成取经学习的实验。你花了一天用 AI 写的代码被拒了,没有被浪费。它变成了下一次设计评审里最有说服力的道具。
这件事还牵出两个更远的问题。
Junior 能不能借 AI 主导设计。可以,但要承认这是带外骨骼的能力。AI 帮你扩展可探索的设计空间,你负责压缩成明确判断。你能解释为什么选方案三、为什么不选另外九种、这个选择让谁承担什么代价。能做到这一点,你自然就有资格主导设计。做不到这一点却已经把选择变成了代码,就是你被拒的原因。带外骨骼的设计师还是设计师,但外骨骼本身不是资质。这里有一个容易漏掉的陷阱:和 AI 讨论设计的过程会给你一种参与感,让你觉得结论是自己想通的。其实 AI 在对话里不断替你补全论证、连接因果、收敛分支,你做的更像是选择题而不是证明题。主导设计的标志不是你拍板选了哪个方案,而是你能在没有 AI 在场的时候,独立解释这个方案为什么成立、它在什么条件下会失效、失效以后怎么办。如果离开了对话记录你就讲不清楚取舍的理由,那主导的人还不是你。
基本功还重要吗。逐行手写的重要性下降了,但逐层理解变得更重要了。算法和数据结构从构造能力变成评估能力。你不必比 AI 更快写出复杂数据结构,但你要能看出它的抽象是否过度、复杂度是否失控、生命周期是否危险、调度策略是否违反问题本身的约束。以前的基本功是你能不能写,现在的基本功是你能不能不被人忽悠。
回到最初那个场景。年轻人用 AI 重写完代码被拒,心里多半委屈:我明明让系统更好了。老同事拒绝的时候,心里也未必舒服:他不是在守旧,他是在守住一条他清楚怎么走的事故通道。两个人盯着同一套代码,一个看到的是可以更好,一个看到的是不能更险。AI 没有让任何一方变错,只是把一个过去被编码速度自然限流的分歧,压缩到了一个周末里集中爆发。解法不在代码里,在两个人还没一起坐下来谈过的那份设计共识里。