软件行业推行的细粒度PR规范可能适得其反
来源标题:The software industry: annealing, but wrong
近期不少团队要求每个PR限改少量文件和不超500行代码,理由是便于人工审查和测试。但作者指出,这种做法让审查者的上下文切换次数成倍增加。他用模拟退火作类比,认为流程从高能量大步调整逐步收敛到小步微调,初衷虽好却可能走偏。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
软件行业:退火,但方式错了
近几个月,我听说有几个团队采用了一条挺有意思的策略:每个 pull request 不超过几个文件,行数不超过一定数量(比如 500 行)。只做一件事,并且做好。要便于人工审查。要通过测试套件的完整测试。这些都是好要求,对吧?这当然是高质量的软件工程。
而且,结果往往确实不错。把一个 6000 行的功能或修复拆成十二个 500 行的 PR,确实更费事,但每个 PR 显然都更容易审查。出了 bug 还能用 git bisect 定位!也许还能单独 revert 掉破坏东西的那个改动。
……同时也让你的审查者多了 12 倍的上下文切换,因为他们得逐个顺序审查。¹ 但这不过是软件质量的代价嘛!对吧?
大体上说,是的。我在这里的类比是模拟退火。在这个过程中,你以高能量开始解决问题——做大改动,快速穿越问题空间——然后慢慢降低能量水平,让你的“跳跃”越来越小。在真实的物理退火中(比如用于冶金),结果是更强、更稳定、更结晶化的结构。在模拟退火中,你用它来找到不那么显而易见的解:先快速探索解空间,然后聚焦到看起来最有希望的区域。
在软件里,这个类比很清晰:没错,你一开始可以大跳,但一旦系统更成熟了,你就应该小步走。大跳会破坏结晶结构。大跳会引入 bug。
对破坏结晶结构的恐惧,听起来比“对变化的恐惧”更酷
退火驱动的直觉,主要问题出在事情确实需要快速变化的时候。它不是为这种情况设计的。你通常不会造好一把锤子,然后某天决定要把它改成别的形状。但每一天,都有听起来很有说服力的理由,让你的软件变成另一种形状。退火是变革的敌人。
现代 AI 驱动的编码(讽刺的是,LLM 的训练过程与退火颇为相似)才不在乎你的退火、你的风险管理和你对变化的恐惧。你想让改动多大、多相互关联,它就能产出多大、多相互关联的改动,你想多快地在解空间里跳跃,它就能多快地跳。而它带来的结果,完全符合数学的预测:输出更不强健、更不连贯、更容易失败。LLM 不怕变化,因为等后果显现的时候,这个 LLM 实例早就没了。
但是,突然能够拿一个庞大、成熟的代码库,随心所欲地探索任何大规模改动,这是一种全新而特别的感觉。大多数改动最终被证明是坏主意……能快速丢弃坏主意当然很好。但有些最终是好主意。然后呢?那就遵循你的开发流程。把大改动拆成 500 行的补丁。一个一个审查。研究你已经做过了!你知道这是值得的。
并非每一个大步骤都能拆成小步骤
但问题不在于值不值得——有些改动根本不适合拆成小步。
在 Aperture 的早期开发中,我想实现基于金额的支出配额:在你所有的 LLM 后端上,让某个团队、个人或节点在单位时间内最多花费 $x。但要实现这个,我们首先得加入定价信息(很奇怪,LLM 供应商就是不肯告诉你查询花了多少钱),这意味着要给 provider 定义分配价格;然后我们还得把配额分配给特定的 identity+model+session 组合。而配额是 Aperture 最早的核心价值主张之一。我们必须有它,但我们必须先把这一整套东西都做出来。
于是,我做了一个巨大的改动,涵盖三大块:第一,用于给 session 应用属性的 Grant 语法;第二,一个结合多个来源和一堆混乱启发式的查询成本估算器;第三,真正的配额强制执行系统。每一部分都不完美,但我们需要三部分齐全,才能让任何东西跑起来,然后才能去打磨它们。这就是高能量大跳跃的阶段。最后出来大概有 12000 行代码。
当然,我不是什么怪物。全部跑通之后,我把它拆成了三部分:grants、pricing、quotas。² 否则它真的会变成一团无法审查的乱麻。但话说回来,在现实中,我也不可能按照那种人为的顺序来开发配额功能。Grant 结构是随着我对定价和配额执行的理解而演进的。最初的配额语义很糟糕,所以我回退到数据结构,这影响了定价如何导入,进而改变了配额的存储方式。代码审查者不必操心这些,但我得操心。
幸运的是,因为 Aperture 是新的,团队里每个人都理解:在实现这一系列功能时,三个 4000 行的补丁比二十四个 500 行的补丁更好。后来不可避免地发现每一部分都不太对、需要更多 bug 修复时,大家也还算宽容。新软件就是这么造出来的。这就是退火阶段。
但真正难的是它和核心 Tailscale 之间的理念差异。Tailscale 背后有 7 年多的成熟积累。它已经退火很久了,以极高的质量、加固、耐久性——随你怎么称呼——而闻名。如果你在核心 Tailscale 里开始玩这种花样,东西绝对会坏,几百万用户绝对不会买账。所以,大多数情况下,我们不这么干。
但再次快速前进的感觉,真是太美妙了。有些人把这种分析简化成“创始人模式”,说这是性格问题,但其实不是。这是在正确的时间、为正确的工作使用正确的工具。有时你需要快,有时你需要慢。
¹ 当然,你可以并行审查。但你自己试试看,在审查一个 PR 的同时深入思考另一个 PR 的细节。
² 实际上,因为我是个不折不扣的怪物,我大概拆成了 15 个 commit 吧。
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。