返回 2026-07-12
⚙️ 工程

In defense of not understanding your codebaseIn defense of not understanding your codebase

seangoedecke.com·2026-07-11

In defense of not understanding your codebase

作为一名软件工程师,你需要对自己的代码库了解多深?

我猜,那些在低人员流动率的团队中维护小型代码库的人(比如 Redis 或像《见证者》这样的游戏)会说:“显然你必须完全理解它,否则你无法做好工作”。我也猜,那些在高人员流动率的团队中维护大型代码库的人(比如 Google 网页搜索后端或 GitHub)会说:“显然你不可能完全理解它,你只需要在你负责的局部领域尽力而为”。

这是两种截然不同的编程方式,有着不同的方法、实践和文化1。然而,在关于软件工程的在线讨论中,第一类人的观点被过度代表了2。我想为第二类人辩护,以反驳第一类人。在许多软件工程环境中,处于部分理解的状态并没有什么错。事实上,在大型系统中,部分理解已经是你能做到的最好程度了。

反驳“编程即理论构建”

“你必须理解你的代码库”这一观点的最佳阐述是 Peter Naur 的著名论文《编程即理论构建》。我喜欢这篇论文,但我认为它在这个方向上走得太远了。Naur 的核心观点是,当程序员开发一个程序时,代码实际上只是一个副产品,他们真正在开发的主要产品是他们对程序的“理论”。这由他们对正在发生什么以及为什么发生的直觉构成,而代码或文档只能部分捕捉到这些直觉。如果他们丢失了代码,他们可以轻松重写程序。如果他们丢失了这种理解(比如,团队经历了 100% 的人员流动),他们将很难理解这些代码。

到目前为止一切还好,但 Naur 走得更远。他说理论不应该从代码中重建。根据 Naur 的说法,你最好完全废弃这个程序,让一个新团队从头开始重建它,并在此过程中建立一个新的理论3:

仅仅从文档中重建程序的理论是绝对不可能的……[因此]现有的程序文本应该被丢弃,新组建的程序员团队应该有机会重新解决给定的问题

任何在大公司担任过高效软件工程师的人都知道,Naur 在这一点上错得离谱。至少有两个原因。

首先,你根本无法从头重建大型软件系统。足够大的系统(如果它们有用户的话)包含成千上万的奇怪情况和怪癖,这些是无法重新实现的。即使是一个对该系统了如指掌的团队也做不到:需要兼顾的东西实在太多了。成功的重写总是从将现有代码库切分成小的独立块开始,然后一次重写一个块。换句话说,重写一个软件系统涉及对旧系统进行一系列更改。如果你不能更改旧系统,你当然也无法用新系统替换它。

其次,被废弃的系统随时都在被重新启用。在一家拥有数亿行代码和数千名工程师的科技公司中,一个代码库没有任何熟悉它的人留下是很常见的4。只需要几个人在错误的时间离职,或者一个代码库一年无人维护。我不仅见过其他团队这样做,我个人也接管过被废弃的代码库,弄懂了它们,并达到了能够有效进行工作的程度。这需要时间,但为代码库建立一套新的理论是可能的。你首先要理解一个端到端的流程,然后从那里慢慢向外扩展,在此过程中进行谨慎的修改。

在足够庞大的代码库中,每个人都在用不正确的程序理论进行工作。现代软件系统的决定性特征是它们实在太大,任何人(甚至整个团队)都无法将其完全装在脑子里:没有人能理解全部。为了提高效率,你必须找到一种方法,用仅仅部分正确的理论来工作。这就是为什么我一直强调要采取立场并保持自信。如果你对某件事不确定,你不能干坐着等待一个完全理解的人来给你答案。如果你是一名合格的工程师,那个人就是你自己。你必须咬紧牙关,做出最有根据的猜测,然后承担后果。

宽容地看待 Naur,在1985年,程序的平均规模可能比今天小几个数量级,当 Naur 写到“大型程序”时,他指的并不是数千万行代码。Naur 关于大型程序的第一个例子是一个20万行的工业监控程序,第二个例子是一个编译器。1987年,编译器 GCC 的第一个版本大约有十万行代码;而到了2015年,GCC 已经超过一千四百万行。我可以相信重写一二十万行代码相对简单,特别是如果你可以重用现有的测试。但一两百万行就不是这样了。

理论构建是众多权衡之一

LLMs 常被引用为一个糟糕的工具,因为它阻碍了正常的理论构建过程。我认为这过于简单化了。像许多软件工具一样,LLMs 是一把双刃剑:它们使得构建详细的软件心智理论变得更加困难,但它们允许你快速构建部分理论,并能帮助你更有效地利用那部分理论。这是一个我仍在思考的复杂权衡。

暂且不谈 LLMs,我确信,认为任何干扰你对软件理论的东西都必然是坏事的这种说法是愚蠢的。以下是其他一些使得维护理论变得更加困难的事物的不完全列表:

  • 允许其他人在你的代码库中编写代码
  • 必须实现法律要求的功能,如无障碍访问和数据保护
  • 允许你的同事辞职或在团队之间调动
  • 必须为了安全补丁升级软件版本
  • 引入库或其他依赖项
  • 就像软件中的大多数事情一样,“维护代码库的理论”是众多价值之一。有时它是最重要的价值,你会为此牺牲其他价值;有时你会为了速度、法律合规或政治原因5而将其权衡掉。

    几乎所有工程师——尤其是“纯粹”的工程师——都倾向于在脑海中对其软件保持准确的模型。这更有趣,压力更小,而且感觉更像“真正的工程”。这就是为什么许多工程师在业余时间从事开源项目,以便自己处理小型代码库:为了在工程工作中能够维持对代码库准确的 Naur 理论。我认为这没什么问题。

    然而,在工作中你是拿钱办事的。换句话说,他们付钱给你,是为了让你采纳他们的工程价值观。大家应该都明白,无论你个人多么在乎性能,有时在工作中你不得不写出运行缓慢的代码(例如,为了按时完成项目,或者为了适应某些别扭的需求)。维持代码库的理论也是同样的道理。

  • 我在《纯粹与非纯粹的软件工程》一文中对此进行了详细论述。我认为,我们在软件行业中反复发生的许多争论,都是由追求全面理解的纯粹文化与接受部分理解的非纯粹文化相互碰撞所引起的。 ↩
  • 开源工程师更热衷于在博客上分享他们的工作,纯粹的工程内容通常也更令人印象深刻(因为协调问题在大型专有系统中占据主导地位),开源项目可以合法地被撰写讨论,而专有系统则不能;而且即使你可以合法地写,讨论大型代码库也是不可能的,因为这需要太多的特定上下文。 ↩
  • 我重读了 Ryle 的《心的概念》(Naur 在文中多次引用)的相关章节,我认为 Ryle 对理论构建的看法更为宽容。对 Ryle 而言,理论构建或诀窍是在你做事时自动发生的。认为你可以仅仅通过代码、纯粹靠钻研来掌握一个现有的代码库,这与 Ryle 的观点完全一致。 ↩
  • Naur 说道:“以免这个结论显得不合理,可以注意到,完全死掉的程序需要复活的情况可能很少发生,因为很难想象复活工作会被分配给那些对原团队所掌握的理论一无所知的新程序员。” 要真是这样就好了!
  • 一些工程师可能会说,维持理论是核心价值,因为没有它,你就无法实现其他任何价值。我不同意这种看法。对于可读性、可维护性、正确性或许多其他工程价值,你同样可以这么说。我们一直在对这样的“核心”价值进行权衡。
  • 如果你喜欢这篇文章,可以考虑订阅我的新文章邮件更新,或者在 Hacker News 上分享它。

    这是一篇与本文共享标签的相关文章的预览。

    构建智能体,而非流水线。在计算机程序中使用 LLM 只有两种方式:作为流水线的一部分,或者作为智能体。换句话说,要么你在代码中表达程序的控制流,要么你给 LLM 提供工具并允许它自己管理控制流。以下是你如何将一个简单的“总结一堆信息并发邮件给我”的程序构建为流水线的方式:继续阅读...

    需要完整排版与评论请前往来源站点阅读。