0%

在「不完全理解」中有效工作

最近读到 Sean Goedecke 的一篇文章——In defense of not understanding your codebase(《为「不理解自己的代码库」辩护》)。文章的核心观点和很多程序员的直觉相反:

在大型软件系统中,「完全理解整个代码库」并不是优秀工程师的必要条件,甚至是不现实的目标。优秀工程师应该学会在「不完全理解」的情况下有效工作。

这个观点,和我过去几个月一直在写的 AI Native 软件开发系列,在底层逻辑上有很深的共鸣。这篇文章试着把两边的思考放在一起,做一个梳理。


两种世界,两种文化

Sean 在文章开头提出了一个很有用的二分:软件工程里存在两种截然不同的文化。

世界 A:小型代码库文化。 Redis、个人项目、小型开源库。代码量可控,作者长期维护,架构可以全部装入脑中。这种环境里的人天然认为——「如果你不能理解整个代码库,你就无法做好修改。」追求的是对程序的完整理论模型(theory of the program,即对程序运行机制的完整心智模型)。

世界 B:大型商业系统文化。 Google 搜索后端、GitHub、大型企业内部系统。几千万行代码,数千开发者,人员流动,历史包袱,大量隐含规则。这里没人真正理解整个系统。工程师实际的工作方式是——「我理解我负责的部分 + 理解当前任务相关路径 + 根据证据做修改。」

Sean 说:第二种文化在网上讨论中被低估了。

我在之前的文章里写过一段话,现在回头看,讲的其实是同一件事:

一个 50 万行的系统,如果你的 IDE 能帮你在一秒内定位到所有需要修改的地方,且你改完有充分信心不会遗漏——那这个系统就不算复杂。反过来,一个 5000 行的模块,如果每次改一个 if 条件你都要把 3 个相关服务翻一遍才敢动手——它就是复杂的。

让我深有共鸣的是 Sean 的结论:世界 B 里的工程师,真正需要的能力不是「知道全部」,而是「知道自己知道什么 + 知道自己不知道什么 + 知道如何快速验证」。

这正是我在工程决策那篇文章里讨论的——在信息不完备的条件下,做出当前最好的工程决策。


Naur 的「Theory Building」——对了一半

Sean 花了不少篇幅讨论 Peter Naur 的经典观点:Programming as Theory Building(编程即理论构建)。

Naur 认为,程序员真正创造的不是代码,而是一个关于程序如何运行的理解模型。代码只是这个模型的表面表达。如果团队全部离开,代码还在,但没人理解——系统实际上已经死亡。所以 Naur 的结论是:理解比代码更重要,如果没人理解系统,不如重新写一个。

这个观点在直觉上很有力。但 Sean 指出它推得太远。

第一个问题:大型系统实际上无法重写。不是因为代码太多,而是因为系统里累积了大量「隐藏复杂度」——那些没人设计过、但真实存在的业务规则。比如一个订单系统运行十年后,里面藏着老客户特殊优惠、某渠道订单兼容、某银行支付限制、某地区税务规则、某历史 bug 兼容、某合作方接口要求。这些东西没有任何一份文档完整记录过。重写的时候你只能看到需求文档、数据库、接口、代码——但看不到那些「为什么这里这么写」。新系统会重新踩一遍所有的坑。

第二个问题更有意思:即使没人理解的系统,也可以被恢复。 现实中大型公司经常发生——原团队离职、服务无人维护、代码一年没人碰。然后新人接手,开始完全不了解,慢慢理解一个业务流程,理解几个模块,理解关键路径,最后可以修改。系统在没有人完整理解的情况下,被成功恢复了。

这两个反驳,和我之前讨论的一个问题直接相关。我在软件开发真正管理的是代码,还是知识?中写道:

软件开发一直依赖大量代码之外的知识。过去这些知识有一个天然的载体——团队里的资深工程师。AI 出现以后,一个很大的变化发生了:AI 不会主动问「为什么这里这样设计」,它只能看到代码。

Naur 是对的:理解确实比代码更重要。但 Sean 补充了一个关键的修正:理解不需要是完整的。 足够准确的局部理解,就足以支撑有效的修改。


Partial Understanding——全文最核心的概念

Sean 全文最重要的贡献,我认为是这个概念:Partial Understanding(部分理解),或者说 Imperfect Theory(不完美的理论模型)。

大型系统工程师真正需要的,不是全局完整的理论模型,而是局部正确、足够好用的认知模型。

比如你维护一个支付服务。你不需要知道整个公司的所有服务、所有数据库、所有业务规则、所有历史原因。你只需要知道——支付请求进入哪里、核心流程经过哪些节点、依赖哪些外部系统、你的修改可能影响什么、如何验证改对了。

Sean 用了一个很精准的表述:

优秀工程师不是「知道全部」,而是「知道自己知道什么 + 知道自己不知道什么 + 知道如何快速验证」。

读到这句话的时候,我立刻想到了我在工程决策里写的那个三层输出结构:

决策:选择方案 A。

依据:基于 Context 中的 X、Y、Z 信息。

盲区:以下信息本轮未覆盖——定时任务补偿逻辑、跨系统的 Event schema、A 团队关于退款校验的历史设计决策。

第三样东西——标注盲区——本质上就是对「我知道自己不知道什么」的结构化表达。

这不是巧合。两个独立来源的思考,在不同的话题上得出了同一类结论。这说明它触及了一个真实存在的东西:在复杂系统中,对不确定性的管理,比追求确定性更重要。


从 Partial Understanding 重新理解 Context 构建

过去几个月,我一直在探索一个问题:AI 做开发的时候,需要给它多少上下文?

我在从知识到任务上下文中讨论了 Context 的五重约束——完备性、最小性、容量限制、可获取性、不可预知性。结论是:Context 构建永远不可能完美。你只能在完备和最小之间逼近。

Context 构建——给 AI 的代码探索加一个方向清单中,我提出了五个结构化探索方向:入口、路径、影响面、历史、模式。这五个方向的本质,就是为当前任务快速构建一个局部正确的认知模型。

Sean 的文章给了我一个新的角度来理解这件事。

以前我的思路是:因为 AI 的上下文窗口有限,所以我们不得不精选 Context。但 Sean 的观点暗示了一个更深层的原因:即使上下文窗口无限大,也不需要把整个代码库装进去。 不是因为装不下,而是因为只有极少一部分信息对当前任务有用。剩下的全是噪音,不仅没用,还会稀释判断力。

这不只是容量约束——这是相关性约束

我在从知识到任务上下文里区分了两种上下文:

1
2
3
4
5
6
7
初始上下文(Seed Context):任务开始前已有的信息
- 任务描述
- 持久化项目知识(CLAUDE.md、ADR、架构图)
- 基础认知

构建后的上下文(Built Context):探索后形成的完整上下文
- Seed Context + 探索过程中获取的项目特定知识

这个二分,用 Sean 的语言重新表述就是:Seed Context(初始上下文)是你的初始 imperfect theory(不完美理论模型),Built Context(构建后上下文)是经过验证和补充之后的 refined imperfect theory(精化后的不完美理论模型)。它们都不追求完整。它们只追求对当前任务足够。


AI 时代的 Partial Understanding

Sean 的文章里有一段关于 LLM 的论述,我觉得非常精准。

很多人批评 AI 写代码不好,因为「它不会真正理解代码库」。Sean 认为这个批评太简单。LLM 确实降低了深度理解的能力(它不会像资深工程师那样在脑子里建立一个运行时的系统模型),但同时,它可以帮助快速建立 partial theory。

以前新人需要花两周——阅读代码、画架构、问老员工、调试——才能建立一个大概能用的理解。现在可以:AI 总结模块 → 生成调用链 → 解释历史代码 → 定位入口 → 辅助验证。快速获得一个 80 分的理解。

这个观点,和我之前写的「AI 是决策放大器,不是决策者」完全一致。AI 没有消除对理解的需求——它改变了理解的成本。

我在AI 时代的知识层次中讨论过,基础知识这一层 AI 是不缺的——大模型在训练过程中已经内化了大量通用工程知识。它知道 @Transactional 在自调用时不生效,知道 MQ 有 at-least-once 语义。但它不会自动把这些通用知识绑定到当前项目的具体代码上。

AI 最需要帮助的,不是「增加知识」——是「把已有的通用知识,正确地绑定到当前系统的具体位置」。

而这个过程,恰好就是 partial theory 的构建过程。你不必让 AI 理解整个系统的所有设计决策——你只需要让它理解,对于当前这个任务,哪些通用规则在哪些具体位置生效。


对我之前「知识库设计」讨论的一个重要修正

在写这个系列的过程中,我一度在思考:是否应该构建一个完整的代码知识图谱,让 AI Agent 能够理解整个项目?

Sean 的文章给了我一个重要提醒:不应该追求「整个代码库的完整知识图谱 + 全部代码理解 + 全部上下文输入」。 这是不可行的,而且可能是不必要的。

更合理的目标是:构建一个动态的工作上下文系统,针对当前任务快速构建足够准确的局部理论模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Codebase


Knowledge Layer(知识层)
- 架构摘要
- 模块关系
- 领域知识(CONTEXT.md)
- 历史决策(ADR)
- API 关系


Task Context(任务上下文)
当前需求
+ 相关模块
+ 关键代码路径
+ 影响范围
+ 已知盲区

用 Sean 的框架回头看,我在知识沉淀的第一步中提出的「两样东西就够了」——CONTEXT.md 统一语言,ADR 记录不可逆决策——本质上就是在交付一个初始 imperfect theory。它们不是为了让 AI 理解整个系统,而是为了让 AI 在开始探索之前,先拥有一个足够好的 Seed Context。

我在知识沉淀的第一步里写的那张表——六层知识的覆盖情况——从 Sean 的视角来读,透露了同一个道理:基础知识不需要覆盖(AI 已经有了),代码自动覆盖(它就是知识本身),历史决策和架构设计被 ADR 覆盖得最好,而业务逻辑层(最易变的)覆盖不全。这不是设计的缺陷——这是故意为之。在投入产出比最高的地方动手,把不可逆的、代码里看不到的东西记下来。剩下的,在每次任务中动态构建。

Knowledge Base 的目标不是让 AI 记住整个代码库,而是帮助 AI 更快形成正确的局部认知模型。 这和 Sean 的 imperfect theory 是同一件事,只是换了说法。


对后端工程师的几个启发

结合 Sean 的文章,和自己这一段时间的思考,我觉得有几个启发值得写下来。

1. 不要沉迷于「完全理解项目」

很多工程师进入老项目的第一反应是:「我要把整个项目搞懂。」结果半年过去,还是不敢改。

更有效的方式是任务驱动:我要修改退款流程 → 找到入口 → 追踪一次完整调用链 → 理解相关模型 → 修改。你在做的过程中自然构建了理解,而不是在理解之后才开始做。

这和之前在改代码这件事,为什么总是比想象中难里讨论的「未知的未知不能靠仔细来预防」是一脉相承的——你不可能在每次改动前读完所有代码。你只能在做的过程中,逐步逼近。

2. 高级工程能力的本质不是记忆,是导航

  • 初级:「我知道代码在哪里。」
  • 高级:「我知道如何快速找到代码在哪里。」
  • 专家:「我知道哪些地方值得怀疑,哪些地方不能动,以及如何验证我的假设。」

这里的每一级提升,都是在 partial understanding 的质量上提升——不是知道得更多,而是判断得更准。

3. AI 时代,工程师价值的锚点更加偏向「建立局部模型」

未来的差距可能不在于谁能让 AI 写出更好的代码——代码生成的速度和质量会继续提升。差距在于:谁能更快地为当前任务构建出那个足够准确的局部认知模型。

回头看决策与实现里那句「人负责决策,AI 负责实现」——人在循环中不可替代的价值,不是写代码,而是判断:改哪里、怎么改、影响谁、如何验证。这四个判断的质量,直接取决于你为当前任务构建的 partial theory 有多准。

4. AI Agent 的未来形态可能不是「全知全能」

这一点我觉得特别有意思。很多人想象未来的 AI Agent 会是一个「理解整个代码库的超人类程序员」。但 Sean 的文章暗示了一个不同的方向——未来优秀的 AI Agent 可能也不会有整个代码库的完整理解。它会像一个优秀的人类工程师一样:根据任务动态构建当前需要的局部理解。

如果是这样,那 Context Engineering(上下文工程)——如何设计 AI 获取、组织和使用上下文的方式——就不再是一个过渡性的技巧,而是一个长期存在的基础问题。

我在Context 构建那篇文章的结尾写了一句话:「这套方向清单是给现在的 AI 用的。随着模型越来越强,AI 自己就会追调用链、查 git log、搜使用模式……到那时候,结构化探索就不再是一个独立步骤了。」这个判断仍然成立——AI 的自主探索能力会越来越强。但它能探索的始终是代码层的东西。那些代码之外的知识——设计意图、历史约束、隐式假设——只要没有被显式记录,AI 就仍然需要人的引导。

Context Engineering 会随着模型能力增长而自动消失。但 Knowledge Engineering——把隐式知识外化、让它可以被 AI 消费——不会。


总结

Sean 这篇文章不是鼓励「不学习代码」。它真正想说的是:

大型软件工程的现实不是「理解全部然后修改」,而是「在有限理解下建立足够准确的局部模型,并持续验证」。

这句话放在我过去几个月写的系列里,读起来像是整个系列的一句总结。

  • 软件开发管理的对象是知识,不是代码——因为代码本身不足以支撑决策。
  • 知识有六层——但一次任务只需要其中的极少一部分。
  • Context 构建永远不完美——所以要在不完备中逼近完备,在不确定中做出当前最好的决策。
  • CONTEXT.md 和 ADR 不是为了让 AI 理解一切——是为了让 AI 在探索之前拥有一个足够好的 Seed Context。
  • 五个探索方向不是流程规定——是一张帮你构建局部理论模型的地图。

而 Sean 的文章,给这个系列的底层逻辑加上了一个理论基础:Partial Understanding 不是一种妥协——它是大型软件工程的唯一现实。接受它,然后让自己在它里面变得越来越有效。


这篇是我 AI Native 软件开发系列的第十篇。前九篇:软件开发管理的对象是知识知识的六个层次从知识到上下文的筛选工程决策——在不确定中做最好的选择Specification——把决策翻译给 AIExecution 与闭环知识沉淀的第一步Context 构建——五个方向决策与实现——研发流程重构。如果你有不同的理解或者实践经验,欢迎一起讨论。