Featured image of post 「我在 Meta 写代码,从来没这么不安过」:一条 LinkedIn 帖引爆 762 条回复,行业给出的真实答案不是「逐行 review」

「我在 Meta 写代码,从来没这么不安过」:一条 LinkedIn 帖引爆 762 条回复,行业给出的真实答案不是「逐行 review」

10 月 19 日,一个叫 rzk 的人在 Hacker News 上发了一帖,标题就一句话:《怎么处理「你在发布自己看不懂的 AI 代码」这件事?》。

他引用的是一段 LinkedIn 上的自述,作者是一位 Meta 工程师:

我在 Meta 做工程师,我从来没对自己的工作这么不安过。我这些天写的代码,整体感觉像个黑盒。这种用 AI 发布代码的新标准推进得太快,如果要逐行检查,那要花掉永远。这意味着你最终会造出一些系统,你自己并不真正理解它的全部代码。你懂高层,但不懂每个细节。也许这正在变成新标准。它违背了我作为软件工程师的每一个本能。

到 10 月 26 日,这帖是 621 分、762 条回复。我把 236 条顶层回复抓下来读完了。

读完的结论是:行业没有给出一个答案。它分成了至少四个阵营,而且这四个阵营对「问题是什么」的定义都不一样。这一点比任何单个答案都更有信息量,因为定义不同,后面的做法就不可能互相兼容。

阵营 主张 代表性做法
收设计权 结构由我来定,模型只负责填实现 先在抽象层定好职责与交互,再让模型实现空隙
换管理工具 你现在是工程经理,把管理流程装上 TDD 门槛、变更说明书、e2e 先行、只看高层不读代码
守责任边界 关键不在工具,在谁的签名在 commit 上 拒绝「没人懂」的状态;测试无法自举
别指望烂掉 抽象层一直在上移,这是同一件事的延续 往关键基础设施走;先把理解速度本身当工程问题

一、收设计权:不让模型决定结构

最高票的回答来自 bitwizeshift,他的做法是把设计权整个拿回来:

我不让 LLM 设计代码,我只让它实现我已经设计好的东西。我会花时间把想要的抽象层级和参与者全部列出来,在 UML 层面决定抽象之间怎么摆、怎么交互,然后让 LLM 去填这些空隙。

他给出的理由是这条讨论里最实用的一条经验:

我发现 LLM 在写像样的抽象上非常糟糕,不管我给多少提示和技能。它总能把活干完,但经常不可维护,而且随着需求不断变化,它需要越来越大的重构。

所以他做了个取舍,而且这个取舍很关键:

我不在乎某个单元的单个实现不够好,只要抽象是对的。最坏情况我以后换个更好的实现就行。

这句话把一个看起来无解的问题拆开了。他承认自己不懂每个单元怎么实现,但他坚持自己懂每个单元的职责和它们之间的关系。理解被分成了两层,他只要上面那层。

下面有人(davepeck)把这个观察推得更狠,而且他用了一个很准的词:

我有个朋友开玩笑说,代码是「分形地坏掉」的,意思是它在每个层级上都错,从单行代码一直到系统主接口的设计。这也大概是我用纯英文和编程 agent 聊完一大轮之后看到的结果。我们的对话覆盖了很多东西,而每个层级上都漏掉了细节。等我去看造出来的东西,误解也是分形的。

然后他补了一句我认为是全帖最有价值的补充,因为它指出了「只定 UML」的漏洞:

我同意自己设计很重要,但 UML 只是其中一个层级。最近我改用一份草稿 Python 文件(甚至一个草稿仓库),Claude 和我都往里改。别管我实际写的是 Rust。Python 读起来像伪代码,而且 pass 和 ... 让我跳过任何我不关心的部分。在任何一个我在意的层级上,我都能精确写出一个方法的签名该长什么样、一个领域模型该有哪些字段、或者它该怎么维持关键不变量。

这个做法值得单独记住。他的办法是定一份双方都能编辑、可以糊弄细节的中间文件。 架构图只能表达一层,而误解是分层的。他用 Python 的 ... 和 pass 当占位符,让这份草稿在他在意的层级上精确、在不在意的层级上留白。我试过类似的路子,用伪代码或者一份只有签名没有实现的接口文件,效果确实比画图好,因为图不会报错,文件会。

二、换管理工具:你现在是工程经理

第二阵营的论证方式完全不同。otiose_tortoise 先把前提换掉:

如果你退一步看,一直存在一群人,他们「把代码发到生产环境」,并且要为产出的软件负责,但他们从没读过它、也不详细知道它。我说的是你们的工程管理层。可能不是你的直属主管,但肯定是你的总监。

然后他把结论摆出来:

我倾向于这么看 agent:我们现在全都变成工程经理了。所以那些工具现在就是你的工具。你去把实践和框架搭起来,让 agent 用它们。

这个类比的好处在于它指出了一件容易被忽略的事:「管理不读全部代码」这件事早就有成熟的解法了。测试实践、设计文档、SLA、发布管理,这些东西存在的理由正是「人类写的代码也不完美,所以需要检查和降低风险的步骤」。它们存在的理由是让一个人不必读完所有代码也能承担结果,跟流程好不好看无关。

按这个思路往下,帖子里给出了几个很具体的做法:

cadamsdotcom 的做法是 TDD 加测试金字塔,但他强调了一个门槛,这个门槛我认为是整条讨论里最容易被忽略的一句:

如果 agent 写了测试,而且关键的是,它亲眼看着这些测试在开始干活之前失败过,那你就有很多信心。

「看着它失败过」这几个字是重点。没有这一步,测试只是代码的另一种形式,同样可能是错的、同样可能什么都没测。有了这一步,测试就变成了一份先于实现存在的、可证伪的规格。

OlivOnTech 的做法更激进,他直接放弃了读代码:

当 LLM 处理一个功能时,我会要求它做几件事,帮我在发布前抓错。写一份模板化的变更说明:与外部系统的交互、时序图、happy path、边界情况、部署检查清单、配置变更等等。我看的是高层选择,不看代码。

他还加了一个我很喜欢的机制:

LLM 会在它做了假设、以及涉及未测试假设的每一处,往代码里加 review 线程。每条都写清楚:什么没法被验证、依赖了什么前提。

这一条比「写文档」有用得多,因为它把不确定性从模型的脑子里搬到了代码旁边,而且位置精确。spacedcowboy 的做法则是把成本前置:

我觉得有帮助的是一次很长的规划会议,深入细节、把边界情况想清楚、设计测试用例。等这些都做完,就更容易让它通宵去干一个大功能。

他的项目是一个自动向量化编译器,所以他给的门槛也很高:让模型写「一大堆测试」,加上一个「在 5 个不同架构上跑好几个小时」的发布闸门。即便这样,他也很诚实:

我还是会 review 代码,但摸着良心说,我不能说我把所有东西都看过了。

三、硬分歧:责任归属,而不是工具

前面两个阵营都在解决「怎么做」。crabbone 是整条讨论里唯一把问题重新定位的人,而他的两条论证我认为最难反驳。

第一条,他区分了两个被混为一谈的状态:

「我不懂全部代码」和「没有人懂全部代码」之间有一道巨大的、不可逾越的鸿沟,但你把它们当成同一件事了。在你的情况里,你不懂全部代码没问题,因为另一个参与生产或审查这份代码的同事懂。整个公司作为一个整体仍然拥有这份理解,只是分布在多个员工身上。而这个问题问的是没有人拥有这份理解的情况。理解意味着责任。

他举了放射科的例子:一个放射科有很多医生,各自读不同病人的影像,彼此不太了解对方的工作;科主任依然为他们的工作负责,但他显然无法审查全部内容,因为时间不允许。这个系统是靠分散责任运作的。他的论点由此得出:分散的责任需要有人持有,而 AI 让那个「有人」的位置空掉了。

第二条,他拆掉了「用 AI 就像当 PE」这个流行类比:

这个说法我听过很多次,它不成立。相似是有的,但有一个根本差别。差别在于谁的签名在 commit 上,谁来承担出错的后果。PE 最多和真正写代码的人分担责任;而 AI 使用者永远为自己 agent 写的每一行代码负责。

他接着说了为什么 PE 的豁免不适用:

作为 PE,你可以跳过读下属写的全部代码,因为你的下属和雇主签了合同,会为某些事情承担法律责任。而 AI 的情况是,可能根本没有人。

然后是第三个论证,针对「那我把测试补上」这个退路:

如果你以为可以用 AI 生成测试,那坏消息是,现在你既有一份你不懂的代码,又有一份你不懂的测试。别忘了跑测试也要花时间,有些情况下比写代码还长。

最后是他给出的那个我认为最难回答的问题,关于复用:

如果你不懂这段代码在干什么,你怎么可能把它复用到别的地方去?也许一个小改动、一个泛化就能做到的事,你会因为不懂而重写一遍。

这几条合起来,指向一个和前面两个阵营不同的结论:流程和工具都可以被抄,但「谁的签名在 commit 上」抄不了。 你可以让模型写测试、写文档、写变更说明,但那份责任最终落在你身上,而它不会因为流程齐备就变轻。

四、别指望代码库烂掉

第四阵营的立场是反的,它反对的是「等这些 AI 写的代码库烂掉,我们就又值钱了」这种安慰性想法。joshmlewis 说得不客气:

这里很多评论让我吃惊。那些说「就等着这些代码库烂掉、然后我们又被需要」的人,拒绝承认我们周围正在发生的现实。如果你是这个立场,我建议你变得非常非常擅长编程,并且去关键基础设施或金融机构这类地方工作,因为大概那里是 agent 写的代码最后才会渗透到的地方。

他接着用抽象层的历史反驳「那不一样」:

我们作为工程师在不同抽象层级上解决问题已经很久了。AI 出现之前,我用框架把更底层的概念抽象掉了,这让我更快地做出真正重要的东西,也就是为终端用户解决问题。给我足够时间,我完全能自己写出底层的数据库适配器,把业务逻辑转换成数据库查询再转回来,但我不需要,因为有人已经把那部分抽象掉了。

这个论证的力量在于它把 AI 放回了技术史的同一条线上。每一次抽象层的上移都伴随着「这一代人不理解底层了」的担心,而这次的不同之处在于上移的幅度和速度。至于这个不同是否构成质变,帖子里没有人给出确定的答案,包括我自己。

五、我的判断:被重新定价的是「理解」这个动作

把四个阵营放在一起看,我认为它们其实在回答同一个问题,只是答案分散在四个方向:理解该由谁承担,承担到哪一层。

以前的默认设置是理解免费附赠。你写了代码,所以你懂它,理解是写作的副产品,不需要单独投入。现在这个附赠关系断了,理解变成了一项要单独投入时间、单独排期、单独设计方法的工作。762 条回复里几乎所有人都在解决同一个技术问题:怎么让理解的成本不随代码量线性增长。 有人靠压缩理解的范围(只要抽象层),有人靠把理解外包给流程(文档、测试、变更说明),有人靠守住责任的边界(拒绝进入「没人懂」的状态)。

而 crabbone 是唯一把问题定位对的人,原因是我前面说的那条:工具和流程能被抄,责任归属不能。他指出的那个空隙,恰恰是所有流程都填不上的地方。cadamsdotcom 的测试门槛、OlivOnTech 的变更说明书、spacedcowboy 的发布闸门,这些都是很好的工程实践,但它们都在回答「怎么更可能不出错」。crabbone 在问的是另一个问题:当它出错的时候,那个「懂」在哪里。 这两个问题不冲突,但后一个没有被前两个解决。

我也想把一个反面意见记下来,因为它戳中了这场讨论里一个没人愿意碰的地方。joaquieneCnix 质疑的是问题的前提:

有多少行 Meta 工程师发布的代码,是他们没时间检查的?这对我毫无意义。假设我 vibe coding 一个应用,我基本不懂代码,四万行没有注释。假设这是我的工作,月底要付账单。假设 LLM 和我一周就 vibe 完了。那我需要再花一周去检查每一行、理解所有东西。我是新手,那家伙是专业选手,所以复杂度不构成理由。那他们剩下的时间在干什么?发布更多代码?

他的推论是:如果理解真的这么重要,那专业工程师的本能应该是先去造提高理解速度的工具,而不是抱怨逐行检查太慢。这个反问没有得到正面回答,而我觉得它是这条讨论里最尖锐的未解问题。

六、想自己抄一遍的话

帖子里有几条做法可以直接拿来用,我按可操作性排了一下:

先说草稿。davepeck 的做法是用一份草稿 Python 文件或者草稿仓库,和 Claude 一起改,哪怕实际语言是 Rust。因为 Python 读起来像伪代码,pass 和 ... 可以让你跳过不关心的部分,而在你关心的层级上可以精确到方法签名和字段。

再说变更说明书。OlivOnTech 要求的字段是:与外部系统的交互、时序图、happy path、边界情况、部署检查清单、配置变更。他的审阅对象是这份说明书,而不是 diff。

第三条是让模型把假设标在代码里。同样来自 OlivOnTech:凡是模型做了假设、或者依赖了未测试的前提,就在那一处留一条 review 线程,写清楚什么没法被验证、依赖了什么。这一步把不确定性从对话里搬到了代码旁边。

第四条是测试必须先失败过。cadamsdotcom 的门槛:agent 写测试,并且它亲眼看着测试在动手实现之前失败过。没有这一步,测试只是另一份同样可能错的代码。

最后是用两个模型做交叉。koliber 的做法:一个 AI 按设计生成代码,他在旁边看着并干预它做他不想做的事,代码写完后再让另一个 AI 审这个 PR。他给出的理由是「第二双眼睛带着不同的偏见和能力」。他还有一个身份上的说服力:他做过一家创业公司的 1 号员工和 lead engineer,早年懂系统的每个角落,到管 50 多个工程师时只剩下高层理解。他明确说,如果当年有 AI,他会用它来解释团队做的事。

写在最后

这帖的价值不在于它给出了答案,而在于它暴露了分歧的准确位置。工具和流程层面的讨论已经很丰富了,而真正没有共识的是责任那一层:当没有人理解这份代码时,那个「理解」应该由什么来替代。

最后交代证据边界。文中的全部引述都来自 Hacker News 该帖的原文(story 50151036,10 月 19 日发布,我抓取时 621 分、762 条回复、236 条顶层评论),我读的是英文原文,翻译由我完成。开篇那段 LinkedIn 自述是原帖作者的引用,我没有独立核实该 LinkedIn 帖本身。样本方面需要说明:会在这类帖子里长篇回复的人,本身是关注这个问题的人,他们的做法偏向「已经在认真处理这件事」的一端,这会让「大家都在想办法」的印象被放大。

相关阅读:

By AI博士 万戈