为你不用完全理解代码库辩护
摘要
文章认为,在大型代码库中,只具备部分理解是可以接受的,甚至常常是必要的,这与Peter Naur在《编程即理论构建》中提倡的完全理解理想相反。它辩护了在高流动性、大规模环境中以有限理解进行工作的实践。
<p><a href="https://lobste.rs/s/elhi7o/defense_not_understanding_your_codebase">评论</a></p>
查看缓存全文
缓存时间: 2026/07/12 10:48
# 为自己不理解代码库辩护
来源:https://www.seangoedecke.com/in-defense-of-not-understanding-your-codebase/
**作为一名软件工程师,你需要对自己代码库了解多少?**
我的猜测是,那些在小型代码库、低流动率团队工作的人(比如 Redis (https://redis.io/) 或者像《见证者》(https://en.wikipedia.org/wiki/The_Witness_(2016_video_game)) 这样的游戏)会说:“显然你必须完全理解它,否则你无法做好工作。”我同样猜测,那些在大型代码库、高流动率团队工作的人(比如 Google 网页搜索后端或 GitHub)会说:“显然你无法完全理解它,你只能在自己的局部范围内尽力而为。”
这是两种截然不同的编程方式,拥有不同的方法、实践和文化¹ (https://www.seangoedecke.com/in-defense-of-not-understanding-your-codebase/#fn-1)。然而,第一类群体在关于软件工程的在线讨论中代表性过强² (https://www.seangoedecke.com/in-defense-of-not-understanding-your-codebase/#fn-2)。我想为第二类群体辩护,反驳第一类群体。在许多软件工程环境中,处于 *部分* 理解的状态并没有什么不对。事实上,在大型系统中,部分理解是你所能做到的最好情况。
### 反对“编程即理论构建”
支持“你必须理解你的代码库”这一观点最好的阐述是 Peter Naur 著名的论文《编程即理论构建》(https://pages.cs.wisc.edu/~remzi/Naur.pdf)。我喜欢这篇论文,但我认为它在这个方向上走得太远了。Naur 的核心论点是,当程序员在开发程序时,代码实际上只是一个副产品,他们工作的主要产物是他们对程序的“理论”。这个理论由他们对正在发生的事情及原因产生的直觉感受组成,这种感受只能部分地被代码或文档捕捉到。如果他们失去了代码,他们可以轻松地重写程序。如果他们失去了理解(比如,如果团队经历了 100% 的人员流动),他们将很难理解代码。
到目前为止还不错,但 Naur 走得更远。他说,理论 *不应* 从代码中重建。根据 Naur 的说法,**你最好完全废弃程序,让一个新团队从头重建**,在此过程中建立一个新的理论³ (https://www.seangoedecke.com/in-defense-of-not-understanding-your-codebase/#fn-3):
> 仅凭文档重新建立程序的理论是严格不可能的…… [因此] 现有的程序文本应该被丢弃,而新组建的程序员团队应该有机会从头开始解决给定的问题。
任何在大公司担任过有效软件工程师的人都知道 Naur 在这点上大错特错。至少有两个原因。
首先,**你根本无法从头重建大型软件系统**。足够大的系统(如果它们有用户)包含了数千个 *奇怪案例* (https://www.seangoedecke.com/wicked-features/) 和不可能重新实现的怪癖。即使是一个对该系统极其熟悉的团队也无法做到:有太多 *东西* 需要处理。成功的重写总是从将现有代码库分割成小型的孤立模块开始,然后一次重写一个模块。换句话说,重写一个软件系统涉及到对旧系统进行一系列更改。如果你不能更改旧系统,你当然也就无法用新系统替换它。
其次,**被废弃的系统 *一直* 在被重新启用**。在一个拥有数亿行代码和数千名工程师的科技公司,一个代码库没有任何熟悉它的人留下来是常有的事⁴ (https://www.seangoedecke.com/in-defense-of-not-understanding-your-codebase/#fn-4)。只需要几个人在错误的时间离职,或者一个代码库被搁置一年而不维护。我不仅见过其他团队这样做,我还 *亲自* 接手过被废弃的代码库,弄懂了它们,并达到了能够有效与之协作的程度。这需要时间,但是构建一个新的代码库理论是可能的。你从理解一个完整的端到端流程开始,然后慢慢从那里向外扩展,在这个过程中进行谨慎的修改。
在足够大的代码库中,**每个人都使用着一个不正确的程序理论**。现代软件系统的决定性特征是它们实在太大,以至于任何人(甚至整个团队)都无法将其全部记在脑中:*没有人完全理解它* (https://www.seangoedecke.com/nobody-knows-how-software-products-work/)。为了有效工作,你必须找到一种方法,使用一个仅仅是部分正确的理论来工作。这就是为什么我一直强调 *采取立场* (https://www.seangoedecke.com/taking-a-position/) 和 *自信* (https://www.seangoedecke.com/what-makes-strong-engineers-strong/)。如果你对某事不确定,你不能只是坐等某个拥有完美理解的人来给你答案。如果你是一位称职的工程师,*那个人就是你自己*。你必须咬紧牙关,做出你最有根据的猜测,然后处理后果。
为了对 Naur 公平起见,有可能在 1985 年,程序的平均大小比今天小了好几个数量级,并且当 Naur 写到“大型程序”时,他指的不是几千万行代码。Naur 给出的第一个大型程序例子是一个 20 万行的工业监控程序,第二个例子是一个编译器。1987 年,编译器 GCC 的第一个版本大约有 *十万* (https://www.oreilly.com/openbook/freedom/ch09.html) 行代码;到 2015 年,GCC 超过 *一千四百万* (https://www.phoronix.com/news/MTg3OTQ) 行。我可以相信重写一二十万行代码相对简单,特别是如果你可以重用现有的测试。但对于一两百万行来说就不是这样了。
### 理论构建只是众多权衡之一
LLM *经常被引用* (https://ratfactor.com/cards/naur-vs-llms) 为一种坏的工具,因为它阻碍了正常的理论构建过程。我认为这过于简单化了。像许多软件工具一样,LLM 是一把双刃剑:它们使得构建对软件的详细脑内理论变得更加困难,但它们允许你快速构建一个部分理论,并且它们可以帮助你更有效地利用那个部分理论。这是一个复杂的权衡,我仍在思考中。
抛开 LLM 不谈,我确信,说任何干扰你对软件理论的东西都一定是坏的,这种说法是愚蠢的。以下是一个部分清单,列出了其他使得维护理论更加困难的事情:
- 允许其他人向你的代码库编写代码
- 必须实现法律要求的功能,如可访问性和数据保护
- 允许你的同事离职或在团队间调动
- 为了安全补丁而升级软件版本
- 引入库或其他依赖
就像软件中的大多数事情一样,“维护代码库的理论”是众多价值之一。有时它是最重要的价值,你为此牺牲其他价值;其他时候,你为了速度、法律合规性或政治原因而权衡取舍它⁵ (https://www.seangoedecke.com/in-defense-of-not-understanding-your-codebase/#fn-5)。
几乎所有的工程师——尤其是“纯正的” (https://www.seangoedecke.com/pure-and-impure-engineering/) 工程师——都更偏好维护一个准确的软件心智模型。这更有趣,压力更小,并且感觉更像“真正的工程”。这就是为什么许多工程师在业余时间参与开源项目,以便自己在小代码库上工作:为了进行那种能够维护代码库准确 Naur 理论的工程工作。我不认为这有什么问题。
然而,在工作中,*你被付钱来做一份工作* (https://www.seangoedecke.com/where-the-money-comes-from/)。换句话说,他们付钱给你是为了让你采纳 *他们* 的那套工程价值观。希望人们都理解,无论你个人多么关心性能,有时你不得不在工作中编写慢代码(例如,为了按时完成项目,或者为了适应某些尴尬的需求)。维护代码库理论也是同样的事情。
---
如果你喜欢这篇文章,可以考虑 *订阅* (https://buttondown.com/seangoedecke) 电子邮件更新以获取我的新文章,或者 *在 Hacker News 上分享* (https://news.ycombinator.com/submitlink?u=https%3A%2F%2Fwww.seangoedecke.com%2Fin-defense-of-not-understanding-your-codebase%2F&t=In+defense+of+not+understanding+your+codebase)。
以下是一篇相关的预览文章,它与本文共享标签。
> 构建智能体,而不是管道 在计算机程序中使用 LLM 只有两种方式:作为管道的一部分,或者作为一个智能体。换句话说,要么你在代码中表达程序的控制流,要么你给 LLM 一些工具并允许它自己管理控制流。以下是你如何将一个简单的“总结一堆信息并通过电子邮件发送给我”的程序结构化为一个管道:继续阅读... (https://www.seangoedecke.com/build-agents-not-pipelines/)
---
相似文章
迈向可理解的软件
本文批判了当前的编程实践和对大语言模型的依赖,反而主张通过更好的抽象、文档和软件栈来使代码更易于理解和维护。
以理论构建的视角阅读编程
本文推荐 Peter Naur 的著作《编程即理论构建》,主张编程的本质在于构建和传达对软件的心理模型,而不仅仅是编写代码。
编程作为理论构建(1985)
这篇彼得·诺尔(Peter Naur)于1985年发表的论文指出,编程本质上是一种理论构建活动,程序员需要深入理解问题领域,而不仅仅是生成代码。
理解的乐趣与力量
对深刻理解代码与系统之乐趣与力量的反思,并警惕过度依赖LLM和捷径会削弱真正的精通。
@MaximeRivest: 只有当愿意接受可能无法完全理解它们创建的过度复杂的系统时,编码代理才能加速我们的工作...
本文讨论了AI编码代理如何要求工程师接受他们可能无法完全理解所创建的复杂系统,并借鉴了自然资源管理等其他领域的经验。