Skip to main content

修改代码的艺术

📅 2026-04-09 ✏️ 2026-04-09 BN
No related notes

1 · 读书笔记:修改代码的艺术

Working Effectively with Legacy Code

https://book.douban.com/subject/1428943/

一句话:教你如何在没有测试的遗留代码中安全地打破依赖、补上测试、自信地修改——而不是推倒重写。

  • 是什么(What)— 遗留代码 = 没有测试的代码;缝(Seam)= 不改源码就能替换行为的位置,本质是代码中的可替换点(而非分隔点);特征测试 = 锁定现有行为而非期望行为的测试
  • 为什么(Why)— 重写风险高、成本大,渐进式改造才是现实选择;没有测试就无法自信修改,而依赖是写不了测试的根本原因
  • 怎么做(How)— 找接缝 → 打破依赖(提取接口/子类化重写/参数化构造函数)→ 写特征测试锁定行为 → 小步修改;用草稿重构理解代码,用影响草图控制波及范围

1.1 · 核心观点:

遗留代码 = 没有测试的代码。修改遗留代码的核心循环是:找到变更点 → 找到测试点 → 打破依赖 → 写测试 → 修改。安全地修改代码的前提不是”理解全部”,而是”能用测试保护你要动的那一小块”。

遗留代码 = 没有测试的代码(没有测试就不敢改)。解法是逐步增加测试:找到缝(代码中已有的、不修改源码就能替换行为的位置)→ 制造缝(通过最小的结构性重构如提取接口来创造可替换点)→ 使用缝(注入测试替身,开始写测试)。测试什么?用特征测试记录当前行为——不需要完全理解代码,先把”它现在是怎样的”锁定下来,然后在这个安全网上增量覆盖修改后的新行为。

1.2 · 启发点(关键洞察):

  1. 遗留代码的定义与心态(What/Why)— 遗留代码不是”老代码”,而是”没有测试覆盖、无法自信修改的代码”。这个定义把问题从”代码年龄”转移到”可修改性”,改变了我们对待旧代码的态度:不是重写,而是逐步驯化。
  2. 接缝(Seam)是打破依赖的关键抽象(What/How)— 接缝是程序中”不用修改源码就能改变行为”的位置。三种接缝:预处理接缝、链接接缝、对象接缝。找到接缝就能注入测试替身,让不可测代码变得可测。这是全书最核心的技术概念。
  3. “先写测试再改代码”的悖论与破解(Why/How)— 要安全修改代码需要测试,但要写测试又需要先修改代码(打破依赖)。解法:允许做最小的、保守的结构性重构(如提取接口、参数化构造函数)来引入接缝,这些重构风险极低,可以不需要测试保护。
  4. Characterization Test(特征测试)(How)— 不是验证”代码应该怎样”,而是记录”代码现在怎样”。先观察当前行为,再把它锁定为测试。这让你在不理解全部逻辑的情况下也能安全修改。
  5. Scratch Refactoring(草稿重构)(How)— 当代码太复杂无法理解时,大胆地重构它来理解结构,然后丢弃所有修改。目的不是改代码,而是建立理解。这是一种低风险的学习手段。
  6. 修改代码的四个理由(What)— 添加功能、修复 Bug、改善设计、优化性能。每种理由下变与不变的部分不同,清楚区分能帮助你控制修改范围。
  7. “编辑并祈祷” vs “覆盖并修改”(Why)— 前者是没有测试时的常见做法:小心翼翼地改,然后祈祷没出错。后者是用测试覆盖住要改的区域,然后自信地修改。两种方式的心理负担和风险完全不同。
  8. 效果的传播与影响分析(How)— 修改一个变量/方法后,影响会沿着数据流和调用链传播。画出”影响草图(effect sketch)“能帮你确定最小测试范围,避免”改一处崩十处”。

1.3 · 行动:

  1. 面对遗留代码时,先问”接缝在哪里”,用提取接口、子类化并重写、参数化构造函数等手法打破依赖,再补特征测试
  2. 对看不懂的代码做草稿重构:放心大胆地改,理解后 git checkout 丢掉,再用正式流程修改
  3. 每次修改前画影响草图,明确”我这次改动会波及哪些路径”,用测试覆盖这些路径

1.4 · 金句:

  1. “Legacy code is simply code without tests.”
  2. “A seam is a place where you can alter behavior in your program without editing in that place.”
  3. “When we have tests, we can make changes with confidence. Without them, we just don’t know.”
  4. “Dependency is one of the most critical problems in software development. Much of the work in getting legacy code under test involves breaking dependencies.”
  5. “Programming is the art of doing one thing at a time.”