Ohhnews

分类导航

$ cd ..
foojay原文

AI写代码时代,工程师的经验从何而来?

#ai编程#软件工程#经验积累#工程判断#人才培养

Bart Butler,Proton 的 CTO,发布了一份内部备忘录,称手写代码是一门已经过时的技能,就像背电话号码一样。他确实说过工程和专业知识并未消亡,但编程可能正在消亡。这份备忘录广为流传,而相当一部分反应都类似于 Lars Faye 在 LinkedIn 上提出的问题:如果没人写代码,下一批资深工程师从哪里来?

Butler 关于代码的看法很可能是对的:在方向足够明确的情况下,代码正是 AI 工具最擅长写的部分;但就程序员本身而言,他的错误在于省略。

备忘录说对的地方

首先,全文公开这份内部备忘录相当有胆量。“最佳实践取决于成本”这一说法是正确的,而且被低估了:过去那条“端到端测试太多是不划算的”规则,本质上是一条关于编写和维护这些测试的成本的规则;如果这项成本下降,权衡关系就会改变。

对 Java 来说,几十年来我们一直设法把单个单元测试的成本压到接近零:JUnit 和 TestNG 在很大程度上已经嵌入我们的潜意识。Butler 的意思是,同类的使用方式也会向上应用一层,用到写代码的工具上,直到我们不再争论是否应该用 AI 辅助写代码,就像我们不再争论是否该用 IntelliSense^1^ 来帮助写代码一样。

他还说,工程师带来的是模型所缺乏的一生的经验、判断力和理解力。对于他目前手下的工程师来说,这是真的。

被省略的部分

正如 Faye 先生所指出的,这份备忘录没有说明下一批工程师的一生的经验从何而来。Butler 所依赖的专业能力,懂得该对一项设计提出哪些问题,懂得它哪里感觉不对,懂得某种形态会招来哪些失败模式,懂得什么时候“它能跑”并不等于“它完成了”。这种经验历来只有一种获得方式:在代码中反复经历自己错了,并且承受你不得不与之共处的后果。人们不断提到的摩擦,正是那种摩擦。按键可以替代,但通过艰难方式学习留下的伤疤不能。

工程师可以通过两种方式学会什么有效、什么无效。

第一种是拒绝运行——大概可以这么说。某个东西说“不行”,而你必须先弄明白为什么,才能继续。在 JVM 上,这主要是 javac 和测试套件:类型检查器不会编译你错误的想法(但愿如此!),红色的测试条不会让你发布它(同样,“但愿如此”。我就假装自己从没听过“测试没问题,照样发吧”这种话)。

JVM 本身在内存方面是出了名的宽容,这正是 Java 开发者如此依赖编译器和测试的原因;平台拿走了一种拒绝机制,生态又建起了另外两种^2^。

第二种是阐述。你写下自己思考过什么,这意味着你必须先思考过。Knuth 在 1984 年称之为文学编程,他的主张是,程序员应该像随笔作家一样思考,让程序读起来像文学作品。Java 一直相当明确,也一直相当有结构,最近在这方面还变得好多了;你应该能够这样写代码:让自己也能享受阅读它,但这需要自律。

Butler 的备忘录既没有考虑拒绝,也没有考虑阐述。智能体不会拒绝;编译器会拒绝,同事会反驳,而 LLM 会附和(见 The Floor and the Multiplier)。而且,工程师不再写阐述了。

只不过,有趣的是,他们某种程度上仍然在写阐述。“仓库级上下文文件、共享技能和提示词”就是文学编程,只不过读者被换掉了:读者成了 LLM,而不是程序员。解释现在成了人类唯一要写的东西,而且它是为模型写的。Knuth 想让人类读那篇随笔。Butler 想让机器读。一个只写 AGENTS.md、从不写代码的工程师,是否还能学会该思考什么,这是一个开放问题,而且很可能就是这个领域未来所面临的全部担忧。## 权宜之计

对于这个普遍性问题,我没有什么好的建议。不过,有三种做法能把人放到问题会被提出的位置上。没有人能强迫别人学会该思考什么;你只能确保他们站在事情发生的地方。

一种可能是复述 diff。在智能体的改动合并之前,由人用自己的话说出它做了什么,以及为什么是这种形态。如果说不出来,就说明没理解,这就是检验是否具备代码素养的红线测试。这保留了人工审查,但颠倒了它的目的:它抓的是人的无知,而不是智能体的错误(见注 3)。

接下来,先预测,再观察。这是我最想力推的一条。当测试失败(变红)时,人要在任何人(包括智能体)碰代码之前,说出修复方案是什么,以及什么会让测试变绿。当你准备用 JMH 时,先写下你预期的数字,再运行基准测试——哪怕只是猜测。当你打开 GC 日志时,先说出你预计停顿会是什么样。

预测出错,正是过去在代码里出错所带来的那种摩擦;而且这种摩擦在自动化之后依然存在,因为智能体无法替你预测而不使这件事失去意义。预测是你提前向自己提出的问题,而预测与结果之间的差距,正是品味被建立起来的地方。如果结果让你意外,那很好!这正是你在学习,低风险而高价值。

最后,刻意约束。给定无限时间和无限多的猴子,你可以解决任何问题,但猴子们不太可能理解它们创造出的《哈姆雷特》。给自己设定一组限制,比如依赖、内存、代码行数、构建时间,然后看看会发生什么。平台不会再强制这些限制,所以只能靠规范来强制。这是人为的,但它会促使你思考自己在做什么,而这种思考会带来判断力,而判断力才是教会你的东西。

这些做法都要求程序员在机器给出答案之前先承诺一个答案。巴特勒的备忘录没有这样做。这些做法并不完美,但它们是我所发现的、朝着正确方向迈出的一步——我认为如此——而朝着正确方向迈步,总比茫然挣扎,或怀疑自己是否选错了职业要好。


注释

  1. 这里的 IntelliSense 指 IDE 的代码补全功能;这个说法已经足够通用,就像用“ketchup”来指“catsup”一样,但如今它的含义已经宽泛到连 vim 这类编辑器也能做代码补全,而且很可能一路也把它叫作“intellisense”。
  2. 我为 Commodore 64 写程序,是为了乐趣和怀旧;挑战之一在于,6510 通常只有三个寄存器和 64K 内存可用,而且它不会运行你没认真思考过的程序。“多少内存、什么样的运算、多少个周期”这些问题会很早而且经常被提出,除非你极其希望程序执行得慢得要命。JVM 从不问这些问题;这是我们做出的取舍,而且是个好取舍,但这也意味着,这些提问必须来自别处。
  3. 我写作和评审时也这么做:我让大语言模型解释我写了什么,如果它说出了让我意外的东西,那就说明我写得不好。我只能回去重画图纸!……代码也是一样。因为这个过程,我已经扔掉过多篇文章和解决方案;虽然你不会感谢我,因为你从没见过它们,但你很可能会感谢我。如果你见过它们的话。