维护者的困境

Lobsters Hottest 新闻

摘要

一篇探讨开源维护者所面临挑战的博客文章,包括拉取请求积压、AI工具对代码审查的影响,以及在质量与倦怠之间取得平衡的困境。

<p><a href="https://lobste.rs/s/gfjzwa/maintainer_s_dilemma">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/05/22 16:35

# 维护者的困境 来源:https://spf13.com/p/the-maintainers-dilemma/ 受保护的分支要求代码合入前必须由第二个人审查变更。这条规则的存在是因为人会犯错,第二双眼睛能捕捉到第一双遗漏的问题。但如果其中一位审查者是机器人呢?如果两位都是呢? 目前,我可以让AI在我的仓库中发起一个拉取请求,然后自己合并它。或者我可以自己写代码,让AI来审查。在这两种情况下,分支在技术上都是"受保护"的。但这现在到底意味着什么? 这些都是值得探讨的问题。但它们往往吸引了所有注意力,而一个更紧迫的问题却无人问津。此刻,在我的各个仓库里,有许多来自他人的开放拉取请求——他们花了时间理解代码库、编写测试、提交整洁的补丁。我还没有审查它们。讽刺的是,我没审查恰恰是因为我非常在意。我知道在一个项目上花时间发起拉取请求是件大事,尤其是在一个热门项目上。我知道每一个请求都值得一次诚实的审查,而这需要时间——对于我作为志愿者维护的项目来说,我没有那么多时间。每一个有资金支持的维护者的开源项目背后,都有数百万个项目只有一个 unpaid 的人类在盯着不断积压的待办事项,纠结着是周末花时间分类问题,还是合上笔记本电脑出去走走。 AI 工具现在可以进行可靠的代码审查、编写补丁和分类问题。问题不再是它们是否足够好用。真正的问题是,"好用"在什么时候会变成"责任",以及依赖它们是否会破坏一些我们不容易重建的东西——维护者与贡献者之间的信任、来自经验的判断力,以及围绕这种交流形成的社区。 ## 118 个开放的拉取请求 上周我查看了 GitHub 通知,然后关掉了标签页。Cobra (https://cobra.dev/) 有 243 个开放 issue 和 118 个开放拉取请求。Afero (https://github.com/spf13/afero) 有 114 个 issue 和 55 个 PR。这两个项目都是我创建的。我已经好几个月没有认真审查过任何一个 PR 了。 尽管作为审查者我无所作为,但这些项目仍在积极维护中。Cobra 驱动着 kubectl、GitHub CLI、Hugo (https://gohugo.io/) 以及数十万其他工具。当你输入`kubectl get pods`或`gh pr list`时,Cobra 负责解析你的命令。Afero 存在于 Hugo 中,存在于 Cobra 本身中,存在于数十万个其他项目中。Cobra 上一个粗心的合并就可能破坏 Kubernetes 工具链。Afero 上一个糟糕的审查可能打开一个文件系统漏洞,静默地传播到所有下游项目。 我创建 Cobra 是因为 Hugo 需要特定的 CLI 用户体验,而现有的库都无法支持。我把它分离出来作为一个独立项目,想着其他人可能会觉得有用。我从没想过十年后我还在维护它,也没想过这两个项目会成为这么多其他项目的关键基础设施。我只是想为自己和几个朋友做些有用的东西。但是,开源代码是否意味着我有义务无限期地维护它?每发布一个新项目,我花在现有项目上的时间就更少。有些 PR 已经等待了多年。Afero 的`BasePathFs`有一个报告的安全漏洞,自 2025 年 6 月以来一直开放着——直到写这篇文章时,我才意识到它的存在,因为积压的工作实在太 overwhelm 了。 维护的数学题行不通。这是开源界众所周知的问题(相关 XKCD (https://xkcd.com/2347/))。贡献的数量增长快于维护者的数量,而审查每个贡献所需的时间随着项目的复杂度和影响力而增长。有些项目会吸引志愿的协作者,但这带来了另一个问题:没有人明确负责,所以每个人都挑选自己感兴趣的部分,其余的就放着。Cobra 有意保持缓慢变化——太多项目依赖它,不能随意合并任何东西——因此每个变更需要更彻底的审查,而不是更少。我的许多其他项目处于维护和废弃之间的灰色地带。我会描述为围绕最关键路径的优化维护,但这种区别对我而言比提交了修复八个月却从未收到回复的人重要得多。 这不只是我的问题。GitHub 托管着超过 4.2 亿个仓库。我很幸运能成为安全开源基金 (https://spf13.com/p/cobra-viper-join-github-secure-fund/) 的首批成员之一——这是一笔真正的投资,带来了真正的改变。但即使扩展到几批,它也只覆盖了大约 200 个项目。OpenSSF (https://securityscorecards.dev/) 每周扫描一百万个关键项目。Tidelift (https://tidelift.com/) 支付维护者费用。所有这些加起来,你覆盖了几千个项目。这是有意义的工作。但相对于实际的覆盖面,这只是一个四舍五入的误差。 百分之九十六的代码库包含开源组件 (https://www.blackduck.com/resources/analyst-reports/open-source-security-risk-analysis.html),它们所依赖的基础设施是由那些盯着永远清理不完的积压工作、想着这个周末是彻底 burnout 还是干脆不再检查的人维护的。这还不算维护者的内疚感——知道人们依赖你的工作,你有能力帮忙,但你跟不上。 ## 机器人入场 黄铜发条自动机在烛光书桌旁检查卷轴,背后是一排等待的卷轴 我在几个仓库里尝试了 AI 工具——在 fileflow (https://github.com/spf13/fileflow) 和 pathologize (https://github.com/spf13/pathologize) 上使用 Jules (https://jules.google.com/),这两个项目依赖较少,有更多尝试空间。同时我也在 Afero 上运行 GitHub Copilot (https://github.com/features/copilot),Afero 依赖更多,但其模块化架构让我可以在不触及其他项目依赖的关键路径的情况下扩展新的后端。 我放开 Jules,看着一封封邮件带着新的 PR 到达。看起来很有希望。然后我去坐游轮了。在海上时,Jules 继续工作,每天打开更多的拉取请求,因为我没有合并第一批。等我回到家时,两个项目上有超过 120 个 PR。我留出一个上午来审查它们,结果发现它们大致代表了五个不同的变更集,每个变更集在几周内每天提交一次。这些 PR 本身没有错,Jules 确实发现了真正的问题。但也没有一个完全正确;每个都需要在合并前进行调整。在指导下,Jules 做了调整,整体方向显示出希望。但到目前为止,这个实验带来了更多的维护工作,而不是更少:我必须逐一检查这 120 个 PR 是否真的是重复的,然后关闭它们。这个本应减少积压的工具反而增加了积压。 Jules 还以我的名义(而不是以 Jules 的名义)创建了这些 PR——这引发了关于归属和问责的问题。从仓库的角度来看,我是这些变更的作者。但我一行代码都没写。如果其中某个补丁引入了 bug 或漏洞,提交历史指向的是我。大多数贡献者协议在设计时并未考虑这种情况,标准的 CLA 也没有区分人类编写的代码和人类指示 AI 代写的代码。 目前,Jules 似乎没有记忆自己之前的工作,也无法检查开放的 PR。它扫描仓库,发现一个 issue,打开一个 PR,然后停止。如果你不合并它,Jules 下次会找到同一个 issue,再打开一个 PR。它无法知道你已知道这个问题,并且出于自己的原因没有合并:也许你不同意这个修复,也许它优先级较低,也许你在船上,几周内都不会处理。这些上下文对工具来说是不可见的。Jules 发现了一个真正的漏洞——文件操作中的 TOCTOU bug 是真实的安全问题——它标记出来是正确的……一次。 GitHub 拉取请求列表,显示 fileflow 和 pathologize 上几十个重复的 Jules PR 对于机械性的工作——标记问题、更新依赖、起草模板回复——这些工具确实有用。但 Jules 和 Copilot 无法告诉我那 55 个 Afero PR 中哪些根本不属于这个项目。这种判断需要了解代码库的过去和未来,而不仅仅是当前状态。 这些工具只能从可见的东西出发:代码、开放的 issue、PR 历史。维护者则从可见和不可见的东西出发:从未写进注释的上下文、没人记录下来的约束、塑造 API 的内部讨论。这两者之间的差距正是人类判断最不可替代的地方,也是 AI 最盲目之处。 Russ Cox(我曾与他在 Go 团队共事)在最近关于 AI 贡献的讨论 (https://groups.google.com/g/golang-dev/c/4Li4Ovd_ehE/m/8L9s_jq4BAAJ) 中说得很好:"人们吹嘘那些从未被人查看过、以创纪录速度生成的有数十万行代码的代码库。仔细一看,这些代码库无一例外地更像跳舞的大象,而不是有用的工程制品。" 关于新颖代码,他说得对。但我一直在思考编写新软件和维护现有软件之间的区别。依赖更新不是跳舞的大象。对过期的 issue 进行分类不是创造性行为。告诉贡献者"谢谢,我们不接受对这个 API 的更改"只是维持运转。而现在,对于数百万个项目来说,灯是关着的。 不过,这不是最大的挑战。大多数人没有意识到的是,评估和合并变更比编写新代码要困难得多。理解一个变更如何融入现有代码库、它的历史以及未来计划,需要部分不可见的知识——不在代码里,不在注释里,不在 issue 里。它在维护者的脑子里。而且其中一些是深度的创造性工作,需要任何模型都无法复制的判断力。 ## "保护"实际上保护什么 Go 项目对我来说真的很美——细致的审查,在发布前持续数月的设计讨论,经过 15 年打磨的审查文化。那是理想状态。但 Go 在许多方面都极其特殊,大多数项目无法复制:由 Google 资助的全职贡献者、构建一个旨在持续 50 年的语言的使命、罕见的外部截止日期压力。 Go 团队最近有一长串讨论 (https://groups.google.com/g/golang-dev/c/4Li4Ovd_ehE/m/8L9s_jq4BAAJ),关于是否接受 AI 编写的贡献——Russ Cox 上面那句话也源于此。这些是我共事多年的人——同样的审查、同样的提案、同样在同一个白板前的争论。读着那串讨论,我能听到他们的声音。我也能看到他们每一个人都是对的,而这正是问题所在。 Rob Pike 率先发言,毫不含糊:"这是一个非常危险的滑坡。小心你的第一步。我建议直接说,不行。" 这就是 Rob。直接、有原则、通常正确。然后 Alan Donovan 指出了令人不安的现实:"我怀疑我们今天收到的 CL 中,有很大一部分已经包含了 LLM 生成的代码片段,无论作者承认与否。" 换句话说,马已经跑了。 Russ Cox 写了关于这个问题我见过的最深思熟虑的回复。他的核心观点:"我们能做的最重要的事情是保持我们围绕代码审查和代码质量的常规流程……当部分或全部代码借助 AI 工具编写时,这个标准仍然必须适用。" 以及:"当你使用 AI 工具工作时,你的责任不会减少。" 这些立场每一个都合理。但每一个都共享一个假设,这个假设暴露了困境的核心:它们假设有人类可供审查。 Go 能负担得起说"保持同样的标准",因为它有 Google 资助的全职贡献者。它有审查者。它有打磨了十多年的审查文化。Rob 可以说"直接说不",因为 Go 有足够多的人对重要的事情说"是"。 Afero 没有。大多数开源项目没有。当 Rob Pike 说"不"时,Go 项目继续运转。当我说"不"时,PR 就只是搁在那里。这是两种不同的"不"。 这里有一个光谱,你落在哪里取决于你实际在什么之间做选择。在实践中,维护者面临五种选择: 1. 人类编写,人类审查。 2. AI 编写,人类审查。 3. 人类编写,AI 审查。 4. AI 编写,AI 审查,人类点击合并。 5. AI 编写,AI 审查,AI 点击合并。 沿着这个列表每走一步,通常是用严谨换取速度,用信任换取吞吐量。但对于大多数项目——当然包括我的许多项目——还有第六种选择,不在这个列表上:人类或 AI 编写,无人审查。 ## 我们真正在保护什么 人类的双手和黄铜发条的手在黑暗中彼此伸向对方,之间有微光闪烁 当维护者审查贡献者的 PR 时,存在一种不成文的契约。贡献者花费数小时理解代码库、编写测试、提交整洁的代码。审查者花费数小时评估它、提出反对意见、建议改进。两个人都学到东西。审查者了解了项目的一个新角落。贡献者变得更熟悉代码库的风格。一种关系形成了。这种交流很大程度上是开源成为社区而不是供应链的原因。 Bryan Cantrill 在 Oxide 公司关于LLM使用的内部政策 (https://rfd.shared.oxide.computer/rfd/0576) 中精确地描述了这种契约:通常,"假设读者和作者中,作者承担了更大的智力劳动。" 当写作是由 AI 生成时,"这个社会契约就被撕毁了。" 代码审查也是如此——我们期望审查者投入努力,因为作者投入了努力。如果两者都没有,审查还有什么意义?Oxide 的答案是,无论如何,人类仍然负责;工具不吸收责任。这是正确的直觉。但它假设真的有人在那里承担责任。 对于大多数项目,没有人在。社会契约不是被 AI 打破的——它已经被沉默打破了。六个月前提交了一个干净、测试完备的补丁却从未收到回复的贡献者,体验的并不是理想的退化版。他们体验的是虚无。 一个从未实现的完美社会契约,是否比一个不完美但确实发生的要好? AI 在一天内回复,可能比人类永远沉默更尊重人。 ## 前方的实验 我决定去尝试。我看着 Afero 上的 55 个开放 PR 已经够久了,知道深思熟虑已经变成了另一种形式的忽视。 AI 工具会让我更投入吗?让我有时间专注于真正需要我的决策?还是会让体验更疏离——人类元素再减少一度?我不知道让 AI 而不是人类审查 PR 是什么感觉,也不知道当双方的努力都减少时,问责是否还成立。这就是实验。 Russ 在那串讨论中还说了另一句话,我反复回想:"最重要的事情是保持思考。工具很容易让你关闭大脑,但如果你小心避免那个陷阱,你就能产生好的作品。" 这就是我试图走的路线。让 AI 处理数量。保持负责。

相似文章

AI正在摧毁开源,而它甚至还不够优秀

Jeff Geerling

本文讨论了AI生成的代码和代理AI如何以低质量的拉取请求和错误报告淹没开源维护者,导致像curl这样的项目取消漏洞赏金,并导致维护者受到骚扰。

我不再需要你的 PR

Lobsters Hottest

一位开源维护者解释为何现在更偏爱由 LLM 生成的代码,而非社区 PR:AI 辅助能降低风险与摩擦,将贡献价值转向反馈、缺陷报告与设计讨论。

最终瓶颈

Armin Ronacher

一篇反思性博客文章,探讨了代码生成中AI加速如何压倒审查流程,在软件工程中创造了新的瓶颈。并与历史上的工业瓶颈进行了类比,建议将抑制输入作为必要回应。