<!-- title: 深模块与浅模块：给软件复杂度记本账 -->
<!-- domain: programming -->
<!-- video: https://www.youtube.com/results?search_query=A+Philosophy+of+Software+Design+John+Ousterhout -->

# 深模块与浅模块：给软件复杂度记本账

## 为什么是这堂课

程序员圈子里有个残酷的共识：绝大多数项目不是死于「功能做不出来」，而是死于「改不动了」。需求明明只改一行，你却要在八个文件里旅行；接手一个老系统，读三个月代码才能敢加一个 if。这种痛，大多数课程选择回避，因为它听起来「不够工程」——没有框架、没有语法、跑分也测不出来。

但这堂课正面回答了它。演讲者是斯坦福大学教授 John Ousterhout——Tcl/Tk 之父、Raft 共识算法的共同作者、创办过 Electric Cloud 等公司的老兵。他在 Google TechTalks 做的这场演讲《A Philosophy of Software Design》，把他 2018 年出版的同名著作浓缩成大约一小时的内容，讲透了一件事：**复杂度不是一个形容词，而是一笔可以记账、可以审计、可以管理的资产**。

放在 2026 年重看，这堂课不但没过时，反而更扎心了：AI 生成代码的速度越来越快，单行代码的成本趋近于零，而复杂度的累积速度却在肉眼可见地变快。当写代码不再稀缺，「能不能看懂、敢不敢改」就成了新的瓶颈。这时候，一个花了四十年写系统的人把「复杂度」拆开来给你看，值得你认真听一小时。

## 视频背景卡片

| 项目 | 内容 |
|------|------|
| 视频标题 | A Philosophy of Software Design — John Ousterhout |
| 频道 | Google TechTalks |
| 时长 | 约60分钟 |
| 播放量 | 百万量级（以YouTube页面实时数据为准，撰稿时未能联网核验） |
| 核心主题 | 软件复杂度的定义、根因，以及一套系统性的设计对策 |

## 核心内容拆解

### 1. 复杂度终于有了一个「工作定义」

这堂课最大的贡献，是把「复杂」这个人人会用、没人说得清的词，钉成了一个可操作的定义：**复杂度，就是理解和修改一个软件系统的困难程度**（视频原话大意：任何让软件难以理解、难以修改的东西，都是复杂度）。

它有三个典型症状。第一是**变更放大（change amplification）**：一个概念上的小改动，要在很多地方各改一遍。第二是**认知负载（cognitive load）**：为了完成一个简单任务，开发者必须先装进脑子里一大堆前置知识。第三也是最阴险的，是**未知未知（unknown unknowns）**：你不知道完成这个任务还需要知道什么，直到系统在生产环境替你叫出声来。

而复杂度只有两个根因：**依赖（dependencies）**——某段代码不弄懂另一段就没法改；**晦涩（obscurity）**——关键信息不在它该在的地方，藏在命名里、藏在隐式约定里、藏在「隔壁老王知道但代码里没写」的地方。

【延伸】这个定义妙就妙在它是「会计学」式的：复杂度不是审美判断，而是成本科目。三症状两根因，等于给了你一张资产负债表，后面所有设计手段，都是往这张表上「减负债」。

### 2. 压垮系统的是增量，不是巨石

课程里有个反直觉的论断：**项目不是被一个巨大的糟糕决定毁掉的，而是被成千上万个「小小的妥协」压垮的**。每次赶工期加一个特判，每次「先这样、以后重构」埋一个坑，单看都无辜——毕竟每个补丁都很小。但复杂度是增量的（complexity is incremental）：它像冰山，水面下那部分是几十年、几百个 PR 慢慢冻出来的。

Ousterhout 给这类人起了个外号：**tactical tornado（战术龙卷风）**。这种人产出惊人，永远在冲刺，每个需求都「做完了」，但他路过之处寸草不生——系统每被他扫一遍，复杂度就上一个台阶。视频原话大意是：战术龙卷风不是坏人，他只是把「能跑」当成了唯一的目标函数。

【延伸】这就是为什么「我们团队都是聪明人，系统还是烂了」如此常见。复杂度账本不记智商，只记决策的对外成本。聪明人加特判的速度，往往比普通人还快。

### 3. 战略编程：给自己留一到两成的「投资仓位」

既然最大的敌人是增量的妥协，对策就藏在对称的位置上：**从「能跑就行」（tactical programming）切换到「战略编程」（strategic programming）——把「代码不仅要工作，还要让未来的改动变便宜」当作首要目标**。

具体的仓位建议是：投入大约**10%~20% 的开发时间**做设计投资（视频给出的大致量级）。这意味着偶尔拒绝最短路径：多花点时间想接口、补注释、收敛一个烂抽象。短期看，你可能比「怎么快怎么来」慢一两个星期；长期看，这些投资会在每一个后续需求上返利。

【延伸】我自己的判断是：这个「一到两成」最实在的用法不是拉长工期，而是**给重构一个合法的记账科目**。很多团队不是不知道系统在烂，而是「还债」在排期里永远排不上——因为这看起来不是「做功能」。Ousterhout 的框架把它从情怀问题变成了投资回报问题。

### 4. 深模块：接口与功能的「汇率」

全课最核心的设计原则只有一个词：**深（deep）**。最好的模块，是**用最简单的接口，封装最强大的功能**——接口描述成本除以功能价值，这个「汇率」越高越好。

反面教材是**浅模块（shallow module）**：接口又长又啰嗦，实现却薄得像纸。课程里用了 Java IO 的经典例子：想读一个文件，你可能要自己拼 `FileInputStream`、`BufferedReader` 一层层包装，每层的构造函数和异常都在向你收费——接口面积巨大，实际功能却只是「读文件」。正面对照是 Unix 文件系统的抽象：open、read、write、close、seek 五个调用，背后藏着磁盘驱动、缓存、块分配一整座冰山。另一个极端例子是垃圾回收器：接口面积几乎为零（你根本感知不到它），承担的却是内存管理这种重量级功能。

由此推出两条红线：**pass-through method（传话筒方法）**——方法只是原样转调下一层，不增加任何价值，是浅模块的典型气味；以及**类不是越小越好**——为了「一个类只干一件事」把系统切成大量碎片，往往是在批量生产浅模块。

### 5. 不同层，不同抽象

深模块原则还有一个纵向版本：**每一层都应该提供与其他层不同的抽象**。调用者往下一层走，看到的世界应该换一套词汇，而不是同一套概念的复读。

视频里点名了常见的反模式：一个层只是机械转发（调 A 变成调 A'），或者一层「夹心饼干」同时暴露两层的概念，逼着调用者同时理解两层才能干活。这和上一条是同一枚硬币：**信息隐藏（information hiding）**——每个模块把最难的设计决策锁在自己肚子里，对外只露一个稳定的、小而深的接口。模块之所以「深」，正是因为它替你扛住了会变的细节。

【延伸】这在微服务时代反而更重要也更难：跨网络的调用把「接口」变成了永久契约，一个浅的远程接口就是一笔带利息的债务。很多团队的「服务拆分」，拆出来的其实是一堆网络化的浅模块。

### 6. 注释是设计工具，不是道歉信

这是课程里最有争议、也最有个人风格的部分。Ousterhout 直接对立了一种流行教条——「好代码不需要注释」（后来那场著名的论战就埋在这里）。他的主张恰恰相反：**注释是消除「晦涩」这个复杂度根因的第一工具**，因为依赖和晦涩二者之中，「晦涩」才是更隐蔽的杀手——它制造未知未知。

他的实操建议非常具体：**注释要描述代码本身说不出来的东西**——为什么这样做、参数的约束和单位、调用的前提条件；并且**先写注释、后写代码（write the comments first）**。注释在这个过程中不是文档，而是低成本的「设计草稿」：如果一段逻辑你用注释都讲不清楚，那多半是设计有问题，代码只会把讲不清放大成讲不清还跑得动。

【延伸】把这条和深模块原则连起来看：接口注释就是你模块的「对外报价单」。写不出简短清晰的接口注释，基本可以断定这是个浅模块——你收的费比提供的功能多。

### 7. 把错误「定义掉」，再谈「设计两遍」

课程的后半段是两个务实的收尾。第一是**错误处理**：异常处理是复杂度的重要来源，而高手的第一反应不是「如何处理错误」，而是**「如何让这个错误根本不存在」——把错误定义掉（define errors away）**。他举的例子是 Tcl：读取一个不存在的变量，直接返回空字符串而不是抛错，于是调用方永远不需要写那几行防御代码。设计接口时，先想想哪些错误场景可以语义上消除，再谈怎么报错。

第二是**设计两遍（design it twice）**：拿到一个设计问题，别满足于第一个想到的方案——至少做两个截然不同的设计，摆在一起比较。第一个方案往往是你最熟悉的路径，而第二方案会逼你发现第一方案的隐含假设。视频原话大意：两版对比下来，最终方案常常比第一直觉好得多，而花的时间远比重构省。

### 8. 【延伸】一场迟到四十年的算总账，和一个新变量

说点课程之外的事，帮读者把这堂课放进 2026 年的坐标系。

其一，这堂课背后那本书，这几年在软件圈掀起了一轮不小的争论：它和 Uncle Bob 的《Clean Code》在函数长度、注释价值、TDD 等问题上几乎处处对着干。据 Hacker News 和多家技术媒体的报道，2025 年初，Ousterhout 与 Robert C. Martin 还在 GitHub 上进行了一场公开的多轮辩论，把「深函数还是小函数」「注释是不是必要的evil」摆上台面，引发社区大量讨论（辩论原文可在 GitHub 上搜索两位作者的名字找到，细节未经本人逐一核验）。我的看法：这场争论没有裁判，但 Ousterhout 的框架更容易「记账」——他给的是可执行的判断标准（接口/功能汇率），而不是风格戒律。

其二，也是我更想强调的：**AI 编程让这套框架从「重要」变成了「保命」**。当代码生成的边际成本趋近于零，产出速率不再由打字速度决定，而由「人类能理解多少、敢改多少」决定。AI 最擅长批量生产的东西恰恰是浅模块——一层层 wrapper、一次次机械转发。让 AI 写实现、人类守住接口的深浅，可能是未来几年工程师最重要的分工线。这笔账，Ousterhout 十年前就替你列好了科目。

## 知识结构图

```mermaid
flowchart TD
    A["软件复杂度：难理解也难修改"] --> B["三大症状"]
    A --> C["两大根因"]
    B --> B1["变更放大：一处改，处处改"]
    B --> B2["认知负载：读懂一行要备一摞课"]
    B --> B3["未知未知：不知道自己不知道"]
    C --> C1["依赖：模块互相咬住"]
    C --> C2["晦涩：关键信息藏在暗处"]
    C1 --> D["战术编程：能跑就交付"]
    C2 --> D
    D --> E["增量式腐烂：每个补丁都无辜"]
    E --> F["战略编程：留一到两成时间做设计投资"]
    F --> G["深模块：小接口，大功能"]
    G --> G1["信息隐藏：细节关在门里"]
    G --> G2["不同层，不同抽象"]
    G --> G3["把错误定义掉：让异常无处发生"]
    F --> H["注释先行：注释是设计工具"]
    H --> I["设计两遍：第二版常好一倍"]
    E -.->|AI时代加速| J["代码越生成越快，账欠得越快"]
```

## 实战启示：给团队装一套「复杂度记账法」

这堂课最值钱的地方，是它给出的每一条都能变成例行公事。给你一套可以直接抄的清单：

**第一，每周五做 15 分钟「复杂度三问」。** 这周我改某个需求时，动了几处才算完？（变更放大）新同事接手时，需要先弄懂哪几件本不必懂的事？（认知负载）有没有哪次线上问题，根因信息藏在没人想到的地方？（未知未知）三问都不疼，这周的账就是平的。

**第二，给核心模块做一次「深浅审计」。** 打开你最常改的模块，数一数：调用它需要理解几个参数、几个返回值、几个异常？它实际替你扛住了多少细节？接口行数远超功能描述，就是浅模块实锤——别急着拆，先想想能不能把细节收回门内。

**第三，试一周「注释先行」。** 下一个新模块，强迫自己先把接口注释写完再写第一行代码。写不顺的那些接口，多半设计有问题——这时候改设计，成本是一杯咖啡；上线后改，是一次发版事故。

**第四，改一个 code review 的问题。** 把「这个 PR 逻辑对吗？」升级成两问：「它让系统更深了还是更浅了？」「它新增的每个错误分支，能不能在语义上定义掉？」——第一条管账本，第二条管利息。

**第五，也是 AI 时代的分工姿势。** 让 AI 写实现、写测试、写文档，但**接口的深浅必须由人签字**。AI 可以替你搬砖，不能替你记账。

## 延伸学习路径

1. **书本体《A Philosophy of Software Design》**——课程只是索引，书里有完整的案例和反例（已有中译本《软件设计的哲学》，可在豆瓣读书搜索）。
2. **《Clean Code》对读**——把两本书的观点摆在一起各打五十大板，比单读任何一本收获都大；两派分歧的现场版见下一条。
3. **Ousterhout 与 Uncle Bob 的 GitHub 公开辩论**——2025 年初进行的多轮交锋，GitHub 搜索「Ousterhout Uncle Bob discussion」可定位原文（据社区报道，细节以原文为准）。
4. **raft.github.io**——Raft 共识算法官网，Ousterhout 团队的工程作品；对照课程看，体会「深接口」在分布式系统里长什么样。
5. **课程视频本体**——YouTube 搜索「A Philosophy of Software Design Ousterhout」，Google TechTalks 频道的第一条结果即该视频。

## 一句话总结

深模块不是天才的灵感，而是一笔笔记出来的账：接口越小、扛住的功能越多，你和团队未来每一次改动的成本就越低——而 AI 越强大，这门记账手艺越值钱。

## 参考来源

1. [A Philosophy of Software Design — John Ousterhout（Google TechTalks）](https://www.youtube.com/results?search_query=A+Philosophy+of+Software+Design+John+Ousterhout) — 本文分析的核心视频（检索直达链接，打开后第一条即该视频；撰稿环境未能联网核验直链与实时播放数据）
2. [John Ousterhout 斯坦福个人主页·书页](https://web.stanford.edu/~ouster/cgi-bin/book.php) — 书本体信息与作者背景
3. [Raft 官网](https://raft.github.io) — Ousterhout 团队代表作，深模块的分布式系统样本
4. [豆瓣搜索：软件设计的哲学](https://www.douban.com/search?q=%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1%E7%9A%84%E5%93%B2%E5%AD%A6) — 中译本信息
5. [GitHub：johnousterhout](https://github.com/johnousterhout) — 与 Uncle Bob 的公开设计辩论等讨论所在（据社区报道）

---
> 本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵**爱卫生**（微信ID: gprshome201101）维护，聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。
> 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
