停止使用Pull Requests
摘要
认为对于值得信赖的团队来说,Pull Requests 效率低下,并提出 T*D(Test-Driven Development, Trunk-Based Development, Team-focused Development)作为替代方案,引用了研究和行业数据。
<p><a href="https://lobste.rs/s/0532zk/stop_using_pull_requests">评论</a></p>
查看缓存全文
缓存时间: 2026/05/22 00:43
# 别再使用 Pull Requests
来源:https://a4al6a.substack.com/p/stop-using-pull-requests
> *“检验为时已晚。质量,无论好坏,已存在于产品之中。停止依赖检验来达成质量。通过一开始就把质量构建到产品中,从而大规模消除对检验的需求。”* —— W. 爱德华兹·戴明,《走出危机》(1982)
在软件团队中,拉取请求(Pull Request)已成为默认的代码审查机制。但拉取请求最初是为开源项目发明的——在那里,陌生人为那些由素不相识的维护者管理的仓库贡献代码。当由受信任同事组成的私有团队采用同样的流程时,他们实际上是把一个为低信任度环境设计的模式,导入到一个本应高信任度运作的环境中。其结果是形成了一个开发完成后的检验系统,而证据表明:它捕获的 bug 很少,却引入了巨大的等待时间,鼓励大批量提交,并将团队分裂成孤立的个体。学术研究、来自 DORA 的大规模行业数据以及日益增长的从业者共识都指向同一方向:有比事后检验更好的方法将质量构建到软件中。本文审视了相关证据,并提出了一种替代方案——T*D,即测试驱动开发、主干开发与团队聚焦开发的结合——作为从缓慢、依赖检验的工作流迈向快速流动、生产高质量安全系统的团队的路径。
- 拉取请求是为来自不可信陌生人的开源贡献而设计的。将其应用于受信任的团队是一种类别错误。
- 经同行评审的研究表明,代码审查的主要价值在于知识传递,而非发现 bug。不到 15% 的审查评论与实际 bug 相关。
- 异步 PR 工作流意味着你的代码在前置时间的 86% 到 99% 中都在*等待*。某组织在一年内花费了 13 万小时等待那些零评论的 PR。
- DORA 对 36,000 多名专业人士的研究表明,主干开发与显著更高的软件交付性能相关,而仅加快代码审查速度就能将性能提升 50%。
- 替代方案是 T*D:测试驱动开发(将质量构建进去)、主干开发(持续集成)以及团队聚焦开发(在创建过程中审查,而非事后)。
- 过渡是渐进的:先优化 PR,采用 Ship/Show/Ask 模式,然后随着信任和自动化成熟,转向结对编程和主干开发。
戴明在 1982 年写下这些关于制造业的文字,但它们却惊人地准确描述了如今大多数软件团队的状况。一个开发者在分支上孤立地编写代码,持续数小时或数天。然后他们发起一个拉取请求。代码进入队列。某个人最终查看它,留下几条评论——大多是关于命名和格式——点击批准,代码合并。整个过程看似严谨,感觉像质量控制。但证据表明,这多半是一场表演。
本文并非反对代码审查。**代码审查确实有实际价值——但这种价值在于知识传递和共同理解,而非捕捉 bug。**而阻塞性的异步拉取请求恰恰是实现这一目标的最糟糕的机制之一。
以下是经同行评审的学术研究、大规模行业数据以及跨越二十年的从业者经验的综合。呈现出的图景是一致的,并且对于许多团队来说令人不安:大多数组织实践代码审查的方式是一种昂贵的仪式,它拖慢交付,鼓励大批量提交,破坏团队凝聚力,并制造虚假的安全感。更好的替代方案是存在的,而且它们并非理论上的——它们正被全球高绩效团队成功实践。
拉取请求有一个特定的起源故事,理解它就能解释为什么它们对大多数团队来说并不合适。
林纳斯·托瓦兹在 2005 年创建了 `git-request-pull` 命令,就在发布 Git 后不久。在此之前,开源项目使用基于电子邮件的补丁工作流:贡献者将差异(diff)发送到邮件列表,维护者决定是否应用它们。2008 年,GitHub 推出了基于网页的拉取请求,极大地简化了接受来自外部世界的贡献——那些维护者不认识的人。
这对开源来说是一次真正的创新。**拉取请求被设计为一个守门机制,用于处理不信任的贡献者向不属于自己的仓库提交代码。**它解决了一个真实的问题:如何安全地接受陌生人的代码?
但随后发生了一些事。Git 成为主流的版本控制系统。GitHub 成为主流的平台。各地的团队都将拉取请求作为默认工作流——并非因为他们评估过替代方案,而是因为它就在那里,而且所有人都在用它。正如马丁·福勒所言:*“我怀疑,由于拉取请求如此流行,许多团队默认使用它们,而实际上没有它们会更好。”*
这个类别错误应该显而易见。**在开源项目中,你审查的代码来自一个你可能从未见过的人,他们在一个可能并不完全理解的代码库中工作,并且缺乏关于团队约定或方向的共同背景。**守门模式是合理的。而在私有团队中,你审查的代码来自一个参加同一个站会、拥有共同目标、并且(理论上)正是因为你信任他们的能力才被雇佣的同事。然而流程却是一样的。
蒂埃里·德·波夫直言不讳:*“拉取请求的设计是为了更容易接受来自外部世界的贡献,来自我们不认识、不可信的人。”*当你的团队在内部采用这种模式时,你正在导入一个与你现实不匹配的信任假设。
即使在开源中,拉取请求也会造成摩擦。贡献可能会等待数周或数月无人审查。维护者倦怠有充分记录。这个流程比发送电子邮件补丁*好一些*,但远非无摩擦。而在一个需要每天多次集成和部署的团队中,这种在开源中仅仅是不便的摩擦,会变成实实在在的破坏。
如果你问开发者为什么要做代码审查,最常见的答案是:发现 bug。证据表明这很大程度上是一个迷思。
最重要的数据来自微软研究院。2015 年 IEEE 的一项研究题为 *“代码审查并不发现 bug:当前代码审查最佳实践如何拖慢我们”*,发现只有极小比例的代码审查评论与 bug 有关。大多数是关于结构问题和风格。2013 年 Bacchelli 和 Bird 的一篇里程碑式论文——《现代代码审查的期望、结果与挑战》——通过观察、访谈和调查研究了微软的代码审查,得出了相同的结论:**尽管发现缺陷仍是审查的主要动机,但审查在缺陷发现方面的作用低于预期。不到 15% 的代码审查中讨论的问题直接涉及 bug。**主要益处是知识传递、增强团队意识以及产生替代解决方案。
另一项微软研究院的分析研究了五个项目中的 150 万条审查评论。变更中的文件越多,有用评论的比例就越低。开发者平均每周花费六小时审查他人的变更。包含超过 20 个文件的审查已经太大,无法有效审查。
大规模行业数据也讲述着同样的故事。一家大型科技公司在内部检查了九百万次代码审查后,引用**知识传递作为代码审查投资回报率的主要来源**,而非发现 bug。高达 75% 的代码审查评论影响的是软件的可演进性和可维护性,而非功能性。
这些都不意味着代码审查没有价值。它意味着其价值在于大多数人假设的另一个地方。**如果你的组织主要将拉取请求作为捕捉 bug 的机制,那么你正在为一个同行评审研究表明收益甚微的好处进行优化。**知识传递的好处是真实的——但阻塞性的异步队列是实现它的最糟糕的方式之一。
这是一个应该让任何工程领导者感到不安的计算。
如果一个代码变更需要 10 分钟来编写,但要等待 1 小时才能被审查,那么它在整个前置时间中有 86% 的时间在等待。如果审查需要 4 小时:96% 的时间在等待。**如果审查需要一个工作日——这很常见——那么代码有 99% 的时间在等待某个人来查看它。**
马丁·福勒引用了一个客户案例:**2020 年,该客户在等待 7000 个没有任何评论的拉取请求上花费了 13 万小时**。他们 91% 的 PR 根本没有收到任何评论。绝大多数 PR 在没有实质性审查的情况下被草率批准,然而这个流程仍然造成了巨大的延迟。
这种损害通过上下文切换进一步加剧。研究表明,开发者平均等待四天才能得到一个拉取请求的审查,86% 的拉取请求是在上下文切换条件下处理的,而上下文切换下的拉取请求比非上下文切换时慢 223%。当一个开发者发起一个 PR 然后转向其他工作时,重建原始工作的心智上下文需要 30-60 分钟——如果他们真的会重建的话。
唐·赖纳特森的《产品开发流程原理》提供了理论视角:批量大小是持有成本与交易成本之间的经济权衡,将批量大小减半会使队列减半并缩短周期时间。**拉取请求创造了一种反常的激励,促使人们采用更大的批量**:由于获得审查的交易成本很高(等待、上下文切换、审查者可用性),开发者会将更多变更打包到每个 PR 中以摊销审查成本。更大的 PR 需要更长的审查时间,对大型变更的审查效果更差,这个循环自我强化。
查丽蒂·梅杰斯从财务角度衡量了成本。一个需要数天才能部署的 6 人团队,需要 24 人才能匹配一个持续部署团队的产出——大约 360 万美元的不必要薪资成本。一个每周发布的 10 人团队需要 80 人:1400 万美元的浪费。她的目标:*“任何合并都会触发自动部署到生产环境,在 15 分钟或更短时间内完成,无需人工干预。”*
德拉甘·斯特帕诺维奇检查了超过 30 个活跃仓库的异步代码审查工作流,观察到一个反直觉的模式:**使用小 PR 配合异步代码审查的团队,其吞吐量往往低于使用大 PR 的团队。**原因在于一个反馈循环。等待审查导致高在制品(开发者在等待时拉取新工作)。高 WIP 意味着审查可用性降低。可用性降低意味着更多的异步交接。更多的异步交接意味着更多的等待。
开发者没有形成一个团队,反而变成了斯特帕诺维奇所谓的 *“N 个一人团队,通常有着不同的工程文化和编码实践。”* 这种孤立与高绩效团队所需要的恰恰相反。
切尔西·特洛伊将根本原因归结为共享背景不足。异步代码审查对审查者的时间提出了巨大需求,因为他们缺乏作者在数小时或数天内建立起来的上下文。结对编程之所以更高效,正是因为上下文传递是即时的——理解和审查的工作在相对于所做工作量压缩的时间内完成。
需要提醒的是:这些是实践者的观察,而非受控实验。因果机制是合理的但未经实证证明。有可能吞吐量较低的团队出于其他原因默认使用异步审查。但这些观察在多个独立实践者中是一致的,并且排队论中关于 WIP 积累的逻辑是公认的。
如果说实践者的论证是方向性的,那么 DORA 数据则提供了规模。
《加速》一书由妮可·福斯格伦、杰兹·亨布尔和吉恩·金撰写,基于四年在 2000 多个组织中对 23,000 份调查的研究。他们关于主干开发的发现是明确的:**在主干上进行开发(而非使用长期特性分支)与更高的交付性能相关**。高绩效团队在任何时候活跃分支少于三个,分支持续时间少于一天,并且没有代码冻结或稳定期。
DORA 能力框架将主干开发确定为一个关键技术能力。达到可靠性目标的精英绩效者使用主干开发的可能性是其他人的 2.3 倍。关键的是,该框架明确指出了 *“重量级代码审查流程”* 是一个障碍——它们推动开发者走向更大的批次并延迟合并。
2023 年 DevOps 状态报告基于全球 36,000 多名专业人士,发现**仅加快代码审查流程就能带来软件交付性能 50% 的提升**。请注意这说明了什么:问题不在于审查本身,而在于审查的速度。让审查瞬间完成——通过结对、快速周转或自动化——你就能在保留好处的同时消除成本。
一个重要提醒:DORA 研究是相关性的,并非因果性的。它表明高绩效团队倾向于使用主干开发,但并非主干开发导致了高绩效。采用主干开发的团队可能资金更充裕、技能更高或拥有更强的工程文化。但这一发现跨越多年、跨越数万名受访者的一致性,使其成为现有最强的行业证据。
由杰兹·亨布尔共同创立的 Minimum CD 倡议直言不讳地指出:**每日集成到主干是不可协商的。如果你的团队没有每天集成到主干,你就没有在做持续集成。**按常规实践的拉取请求无法通过这一测试。
ThoughtWorks 在 2021 年 4 月将 *“同伴审查等同于拉取请求”* 放入其技术雷达的 **HOLD** 环中——意思是“谨慎进行”。他们指出 PR 会造成严重的团队瓶颈,随着负担过重的审查者开始走过场,审查质量下降,并且在一个案例中,客户的一次监管审计发现拉取请求*未满足合规要求*,因为没有证据表明代码被实际阅读过。
同样来自 ThoughtWorks、著有《基础设施即代码》的基夫·莫里斯认为,拉取请求增加了为低信任度情境设计的开销,并且**拉取请求不是持续集成——持续集成是拉取请求的替代方案,而非补充**。
《持续交付》合著者戴夫·法利认为,拉取请求是基于分支开发的产物,这种开发有意将变更与主线隔离——这与持续集成的要求恰恰相反。
杰森·戈尔曼提出了最尖锐的问题:*“不要过多问‘我们怎么做拉取请求?’,而要问‘我们为什么需要做拉取请求?’”*他的答案是:**拉取请求是低信任度的症状,而非低质量的解决方案。**团队应该解决根本原因——技能发展、专业标准、结对编程——而不是将缓慢的检验制度化。
也许最值得引用的话来自杰西卡·克尔,并由肯特·贝克推广:*“拉取请求是对独自工作的改进。但并非对一起工作的改进。”*
如果拉取请求是戴明所说的检验,那么替代方案是什么?将质量构建到流程本身中又是什么样子的?
答案是三种实践的结合,我称之为 **T\*D**——有意呼应 TDD,因为所有三个组成部分共享相同的首字母和相同的左移质量理念。
编写一个失败的测试。编写最少量的
相似文章
我余下的职业生涯都要用来审查AI生成的代码吗?
一位开发者对AI生成代码的依赖日益加深表示担忧,担心自己的职业生涯将沦为仅仅审查AI输出的工作,而不再是参与创造性的问题解决和编码。
@Smartpigai: 前身是阿里集团内部官方 AI 代码审查助手,过去两年服务了数万开发者,识别了数百万个代码缺陷。 现在它开源了:Open Code Review。 它不是让 AI “随便看一眼 diff”,而是把 AI Code Review 工程化。 它…
阿里巴巴开源了其内部AI代码审查助手Open Code Review,一个工程化的代码审查CLI工具,能读取Git diff并生成带行级定位的结构化审查意见。
编码代理最糟糕的失败是过早地说“完成”
本文强调了一种编码代理常见的失败模式:它们报告任务“完成”,却留下了隐藏的问题,如测试不足、遗漏边界情况和引入错误,给开发者造成了信任问题。
@github: 你的标准。你的工具。每一次代码审查。Copilot 代码审查支持自定义代理技能和 MCP 服务器连接。…
GitHub Copilot 代码审查现公开预览支持自定义代理技能和 MCP 服务器连接,使组织能够将自己的标准和上下文带入代码审查中。
我不是一个 Reverse Centaur
Miguel Grinberg 解释了他拒绝接受由 LLMs 生成的未经请求的拉取请求,坚持需要人工参与以避免成为 'reverse centaur'。