关于代码阅读
谈一下我自己对于「到底要不要看代码」的看法吧。
其实对我来讲,我是主张「不要一行一行去读代码」的立场的,这点在基于过程的质量控制里面就谈到过。不过这里面可能需要做一个分层,就像之前所说的一样,你需要对自己的代码进行分层。比如说特别重要的、可能会危害人生命的,那这种代码最好还是一行一行去读,对吧?第二层就是,可能涉及到大规模的金融处理,或者很重要的核心内核,那可能还是要看一下。但越往后,可以说我们日常构建的90%以上的代码都不涉及这两个方面。这种情况下,我认为尤其是在当今的时代,一行一行去读代码已经没什么意义了。
因为它会成为一个严重的效率瓶颈。像我自己一直强调说,我现在一整天就能产生一万行代码,如果我要去把它全部读一遍,那我个人就会成为瓶颈,对不对?而且在没有上下文的情况下,我去读代码更痛苦的是我。根据一些测试报告显示,人类去读代码一个小时最多也就几百行,你要把一万行看完,今天一整天就只能在那看代码,而且还顶不住。
所以我认为,不读代码是完全可以接受的。只是「不读代码」并不等于我放弃了对代码的质量控制。尤其是 AI 写的代码,很多时候会越写越偏,甚至越写越出问题。所以我还是会去读,但不是一行一行读。什么叫「还是会去读」呢?我的读,是让 AI 帮我总结,然后看大概的架构、看摘要,进行抽象性的阅读。现在可能我真的都不怎么看代码原文了,代码原文对我来讲更像是一种中间产品。我会更多地专注于整个质量控制体系的建构,就像 Harness 约束 AI 一样。
比如说,构建一个非常完善的测试覆盖。而且这种测试覆盖不能单纯由一个 Agent 来构建,因为它们会出现一个经典的老问题,就是「暗度陈仓」。什么意思呢?就是编一些「假绿」——哪怕你代码真的出问题了,它也可能最终给你显示测试通过。你说这种测试有什么意义?这就是先射箭后画靶。所以这种测试要靠什么?一是靠对抗性的审查来构建,比如专门出一个没有任何上下文的 Agent 去审它;或者让它去进行变异测试,也就是把原文故意改坏,看它测试结果还绿不绿,如果改坏了还绿,那就是假绿。为了实现这一点,最好是把写变异测试的这个过程给脚本化、自动化,而不是让 AI 去写变异测试,防止没跑过就出问题。
第二点就是增加各种各样的测试手段,像回归测试、集成测试、E2E 测试等。其中有一个很关键的点是「对齐需求」。什么叫对齐需求?就是有时候就算测试通过了,它通过的内容跟我想要的也不一样。它在程序逻辑上是合理的,也确实没 Bug,但它测的是一个错误的行为。我的规格想要的是 A 行为,它完完全全写了一个跟 A 完全不一样的 B 行为,然后让测试通过了。这就叫没有对齐我的需求和规格。
就像有些人说的,逐行阅读其实不现实,而且「假装逐行阅读」反而更糟。每次看个四五百行,你的阅读质量就会一直下降。你真的连续 Review 一天代码,看到后面会不知所云的。人在这个时候,正确率还不一定有机器高。大量的代码把你淹没了,最后你根本就不想去看,效率会变得非常低。与其搞这种没什么意义的 Review,不如去构建一个完整的、全面的、工程化的测试环境。
你可以看看 StrongDM 他们那种有点像是「黑灯工厂」、「软件工厂」的开发形式。他们的态度非常强硬,要求代码绝对不能由人编写,也不得由人进行审查。那他怎么去保证代码质量呢?就是靠我所说的,构建一个足够过硬的工程环境。这一点其实有点像什么呢?就是一个是从内部保证,一个是从外部约束。要么是从内部保证你的代码本身质量够高,写得一点 Bug 都没有;要么就是,就算有 Bug,I don’t care,我哪怕把你当成一个黑匣子都行,但我需要用各种各样的外部套件、各种各样的测试,保证你的整个行为被压制在我希望的范围之内。这就叫外部约束。
我认为这种外部约束意味着边界和塑形。一个是拿外部的框架当模子把它套进去,另一个是从一开始就捏出这个模子。这没有说谁真的一定是对是错,两边都有自己的道理。但是从效率的角度来考量,坚持去人工 Review,在我看来迟早会落后于时代,因为它的效率瓶颈实在太高了。
StrongDM 有一个很有意思的测试我还挺喜欢的,就是他们会构建一个完完全全的数字克隆环境(DTU,Digital Twin Universe 数字孪生宇宙)。他们把软件所依赖的第三方服务进行了一个行为克隆,用来检测当软件接入外部时会出现什么错误。说白了就是模拟一个真实的运转环境,去不断地对它进行测试。而且他们的测试强度很高,比如进行高容量的压力测试、故意进行攻击、制造危险的故障等。重点是,他们的测试条件都是可验证的,而且测试频率很高。
他们还有个机制叫做 Gene Transfusion(基因注入/基因移植)。不过他们这个看进去更像是把一些标准的范式提取出来,在不同的代码之间迁移相似的工作模式。它不只是用 Skill 来保证,更像是有某种特殊的依赖,或者一个固定的结构和机制。这跟我的用法是类似的,我把它理解为构建了一套可复用的、现代化的开发方法论,它在每一个地方的行为都是可复用、可迁移的,而不只是绑定在一个库上。
在文件管理方面,他们也有完整的规范。系统会完整地记录各种各样的中间记忆档,尤其是对核心文件进行管理。目录的名字是有意义的,会创建各种索引,然后把中间的状态完完整整地写回到磁盘里去。就是要使整个仓库内部的 Agent 时刻有记忆,而不是每次都重新开始。这一步是为了让 Agent 能够持久化整个环境,让它下一次开发的时候能直接捡起来继续做。这个做法其实大家最终都会往这个方向涌现。
此外,他们有两种运行模式:一种是交互式的,有 Human-in-the-loop(人类参与);还有一种是完全非交互式的,只要给出规范,它就从头跑到尾。非交互式的这个挺有意思,它写完之后,还会构建一个像吸引子一样的节点图循环。比如先实现功能,然后找到瓶颈,再去优化性能。在这个过程中,它通过一整套可验证的行为和结果,保证在这个循环中能得到明确的反馈。同时,他们还会用一个独立的 LLM 去进行评估,过程是可观察的,结果是确定性的。就像现在流行的一种图编程,通过有向无环图(DAG),从请求、计划到调用方案、尝试、成功、返回。
我可以这样理解:他们试图在构建一个能够自动化运行且自动化纠正的系统。而这种系统的关键点有两个:第一它是能从头跑到尾的;第二它是能遇到明确反馈并且能够自我纠正的。在这里,「可验证性」就极其重要了。如果你的可验证性上不来,那 Agent 就会一跑就跑没边,陷入死循环,从而出问题。另外,中间还会加上跨 Agent 的独立审查,用层层流程来保证质量。
这也印证了一个我很赞同的观点:我们现在的开发关键点,已经从「代码本身」转移到了「行为」以及「验收标准」上。也就是,什么样的代码运作状态是可验收的?什么样的行为是我预期想要的?我们其实是在设计一个个非常严格的关卡,希望 AI 能通过这些关卡,没通过就要把它补上。在这个过程中,Agent 的思维跳脱就被一定程度地限制住了。
其核心理念就是 Agent 需要纪律。我们需要去保证它工作的有效性,而这种有效性就是通过严格的过程和质量阀门(门控)来保证的。我可以不去审每一行代码,但是我一定要有可验证的指标和关卡,来确保代码确确实实是有质量的。
当然,对我来讲有些东西我是不可能不读的。比如涉及到具体功能该怎么设计,或者是整体的架构。我至少得对整个架构有理解和把握,我不可能自己设计的系统,却不知道它长什么样。我可以不关注代码层面的细节,但是宏观上的细节和架构我是一定要了解的。
所以我想,未来整个开发的趋势,应该就是不断去加强这样一套工程关卡的建设吧。
The right not to read the code | Raphael Moura StrongDM Software Factory https://arxiv.org/html/2606.13175v1