题记与说明
主题研究 | 精读日期:2026-11-05 | 精读员:#2 | 前缀:knowledge-d2f37j93-2
原书:Michael C. Feathers, *Working Effectively with Legacy Code*, Prentice Hall PTR, 2004(ISBN 0-13-117705-2)
交付物:七维提取 + 接缝/依赖打破/特征测试三主题逐条原文引述 + 结合本机真实历史项目(QMT 量化脚本、工作回顾工具、douyin 前端)的可执行反思清单
0. 来源清单与检索方式(网络可用,全部在线精读)
| # | 来源 | 性质 | 作用 |
|---|---|---|---|
| 1 | Pearson 官方样章 PDF(0131177052.pdf,56 页) | 一手:出版社官方样张,含前言 xvii(遗留代码定义)、全书 TOC、第 4 章 The Seam Model 全文(书页 29–44) | 著名定义、接缝定义/使能点侧栏、CAsyncSslRec 案例的逐字原文 |
| 2 | InformIT: Testing Effectively With Legacy Code — Seams(Feathers 本人,2005-01) | 一手:作者本人在出版社网站连载的第 4 章书摘 | 接缝三类型的取舍原话;#ifdef 的警告 |
| 3 | understandlegacycode.com — The key points of Working Effectively with Legacy Code(Nicolas Carlo) | 二手:逐章导读博客 | 全书工作流(sprout/wrap/insertion point)与特征测试的同名技术梳理 |
| 4 | understandlegacycode.com — Characterization Tests or Approval Tests? | 二手:术语辨析 + Emily Bache 四段式流程 | 特征测试的操作流程、golden master 同源性、快照滥用的批评 |
| 5 | ACCU Overload 20/108 — Refactoring Towards Seams in C++(Michael Rüegg, 2012) | 二手(含原创扩展):C++ 实践视角 | "缺使能点即非接缝"反例;compile seam 扩展;link/preprocessing seam 的工程局限 |
检索执行记录(本会话实际运行,均成功):
- WebSearch ×4:
"Working Effectively with Legacy Code" Feathers seams "characterization tests" dependency breaking;Feathers seam "enabling point" object/link/preprocessing;InformIT Feathers "characterization testing" site:informit.com;understandlegacycode characterization test golden master(前三次各命中 6–8 条,第 4 次命中专题文) curl -sL -o pearson-sample.pdf https://ptgmedia.pearsoncmg.com/images/9780131177055/samplepages/0131177052.pdf→ 672,221 字节,头 4 字节%PDF(PDF-1.6)python -I+ pypdf 提取 56 页全文 →sample_text.txt(101,135 字符)→grep -n "simply code without\|legacy code dilemma\|seam\|characterization\|enabling point"+sed -n分段逐字核对(本笔记所有 PDF 引语的落点均给出行号/书页)- WebFetch ×3(来源 2、3、4)成功;ACCU 用 WebFetch 报
ECONNRESET,改用 webReader 抓取成功 - 项目取证命令(第七节全部依赖,本会话实跑):
find "D:/国金QMT交易端模拟/python" -name "*.py" | wc -l→ 33;find ... -iname "*test*" -name "*.py"→ 0 条;Python 读二进制头分类明文/加密;python -c读douyin_dashboard_frontend/package.json的 scripts;读工作回顾/scripts/generate_work_review.py统计 930 行/41 函数/0 测试
一、核心问题
这本书回答的是四个环环相扣的问题:
- 遗留代码两难(Legacy Code Dilemma):要安全地改代码需要先有测试;要把测试装进现有代码又得先改代码。先有鸡还是先有蛋?(Carlo 的导读将其表述为 "you need tests before changing code, but need to change code to get tests in place"——来源 3)
- "一整张文本纸"困境:Feathers 观察到 "programming languages just don't seem to support testing very well",程序在开发者眼里是一张改一字动全身的大纸,缺少"哪里可以换行为而不动那里"的心智模型。(来源 1,书页 29)
- 行为未知时怎么写测试:面对"我不知道这段代码现在到底干什么、更不知道该写什么断言"的代码,如何建立安全网——这是第 13 章 Characterization Tests 的标题问题(TOC 证实:书页 185:"I Need to Make a Change, but I Don't Know What Tests to Write")。
- 没有时间怎么办:截止日期压顶、不可能做理想重构时,如何用最小侵入的方式让新代码可测——第 6 章 Sprout/Wrap(TOC 证实:书页 57–76)。
二、主要主张
- 遗留代码 = 没有测试的代码。这是定义性主张,作者明知有争议仍坚持:"To me, legacy code is simply code without tests. I've gotten some grief for this definition... It is a good working definition, and it points to a solution."(来源 1,前言 xvii)。配套侧栏断言:"Code without tests is bad code. It doesn't matter how well written it is; it doesn't matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don't know if our code is getting better or worse."(同页侧栏)
- 接缝(seam)模型:行为可替换点是一个可以独立于"读懂全部代码"来定位的对象。"A seam is a place where you can alter behavior in your program without editing in that place."(来源 1,书页 31 侧栏)
- 每个接缝必有使能点(enabling point):"Every seam has an enabling point, a place where you can make the decision to use one behavior or another."(来源 1,书页 36 侧栏)。反过来,没有使能点的调用就不是接缝——书中的
cell.Recalculate()反例(书页 41)与 Rüegg 的GameFourWins.play()反例(来源 5)互相印证。 - 三类接缝有明确的优先级:"In general, object seams are the best choice in object-oriented languages.";preprocessing/link 接缝"are not as explicit as object seams",作者"I like to reserve preprocessing seams and link seams for cases where dependencies are pervasive and there are no better alternatives."(来源 2)
- 特征测试记录"是什么"而非"应该是什么":"The purpose of characterization testing is to document your system's actual behavior; not to check for the behavior you wish your system had"(Feathers 原话,经来源 4 引述);"A characterization test is a test that characterizes the actual behavior of a piece of code."(来源 3)
- 依赖打破技术是一类特殊重构:前言明确其性质——"The refactorings in Dependency-Breaking Techniques are special in that they are meant to be done without tests, in the service of putting tests in place."(来源 1,书页 xxi)——即在无测试状态下为了上测试而做的、必须格外小心的一次性手术。
- 接缝视角改变"好设计"的定义:"The seam view of software helps us see the opportunities that are already in the code base."(来源 1,书页 33);把类从项目里抽出来测时,"often you have a lot of work to do, regardless of how 'good' the design is"(同页)。
三、方法(这本书如何论证)
- FAQ 式组织:前言自述 "I decided that the easiest way to make the book approachable and handy would be to organize the bulk of it (Part II, Changing Software) in FAQ format",每章以一个具体问题命名("I Can't Get This Class into a Test Harness" 等,TOC 全文已在来源 1 提取)。技术之间大量交叉引用页码,承认会让读者"flip wildly through the book"。
- 单一案例贯穿三类接缝:第 4 章用同一个
CAsyncSslRec::Init()里的PostReceiveError(SOCKETCALLBACK, SSL_FAILURE)调用点,先后用对象接缝(virtual + 子类覆写)、链接接缝(测试库替换全局函数)、预处理接缝(同名宏)三种方式切断同一处副作用——用"一点三解"论证接缝是语言机制层面的客观存在,不是设计品味。 - 术语体系化:seam / enabling point / interception point(第 12 章,书页 174)/ pinch point(第 12 章,书页 182)/ sprout / wrap / characterization test,每个术语配一段定义侧栏,让"测试性"从整体设计问题降维成局部决策问题。
- 边界声明:"this book is not about testing","it is not a book about pretty code"(来源 1,前言 xvii–xviii)——本书只关心"being able to confidently make changes in any code base"。
- 二手来源的补充方法:Carlo 的导读把书浓缩为"identify change points (Seams) → break dependencies → write the tests → make your changes → refactor"的工作流,并把 sprout/wrap 的具体步骤写成操作卡片;Rüegg 则把接缝理论落成 C++ 的可实现重构(Extract Interface / Extract Template Parameter / ld -wrap / LD_PRELOAD),并实现了 Eclipse CDT 插件 Mockator——证明这套术语可以工具化。
四、数据与证据(关键原文引述,全部本会话逐字核对)
4.1 遗留代码定义与代价(来源 1,前言 xvii)
"In the industry, legacy code is often used as a slang term for difficult-to-change code that we don't understand. But over years of working with teams, helping them get past serious code problems, I've arrived at a different definition. To me, legacy code is simply code without tests."
"Teams with that degree of clarity in all of their code are rare. They seem like a statistical anomaly. And, you know what? If they don't have supporting tests, their code changes still appear to be slower than those of teams that do."
(侧栏)"Code without tests is bad code. It doesn't matter how well written it is; it doesn't matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don't know if our code is getting better or worse."
4.2 接缝与使能点定义(来源 1,PDF 行 903 / 1128–1131;来源 2 同文)
(侧栏 Seam,书页 31)"A seam is a place where you can alter behavior in your program without editing in that place."
(侧栏 Enabling Point,书页 36)"Every seam has an enabling point, a place where you can make the decision to use one behavior or another."
(书页 36)"When you have a seam, you have a place where behavior can change. We can't really go to that place and change the code just to test it. The source code should be the same in both production and test."
4.3 三类接缝要点(来源 1 书页 33–42;来源 2)
- 预处理接缝:使能点是
TESTING预处理宏;作者对滥用的警告:"excessive #ifdefs force you 'to maintain several different programs in the same source code'"(来源 2)。 - 链接接缝:"The enabling point for a link seam is always outside the program text. Sometimes it is in a build or a deployment script. This makes the use of link seams somewhat hard to notice."(书页 40)。Java 里使能点是 classpath("The enabling point is the classpath.",书页 40 区域)。
- 对象接缝:OO 的根本性质——"when we look at a call in an object-oriented program, it does not define which method will actually be executed"(书页 40)。
- 非接缝反例(书页 41,关键):对象在同一个方法里内联创建时——"Is the call to Recalculate an object seam? No. There is no enabling point. We can't change which Recalculate method is called because the choice depends on the class of the cell."
- 参数列表即使能点(书页 42):
buildMartSheet(Cell cell)里调用cell.Recalculate()——"Is the call to cell.Recalculate in buildMartSheet a seam now? Yes. ... Where is the enabling point? In this example, the enabling point is the argument list of buildMartSheet." - 取舍(来源 2):"In general, object seams are the best choice in object-oriented languages." + "I like to reserve preprocessing seams and link seams for cases where dependencies are pervasive and there are no better alternatives."
4.4 CAsyncSslRec 案例(来源 1,书页 30–33)
同一处全局调用 PostReceiveError(SOCKETCALLBACK, SSL_FAILURE)(与另一子系统通信、测试中很痛),三种解法原文:
- 对象接缝:把全局函数包成同名 virtual 方法 + 空实现子类
TestingAsyncSslRec——"We were able to change the method that is called without changing the method that calls it"(书页 33)。 - 链接接缝:测试库里给同名全局函数空体;"The enabling point would be our makefile or some..."(书页 44 区域,PDF 行 1429)。
- 预处理接缝:测试头文件里
#define同名宏。
4.5 传感(sensing)模式(来源 1,书页 39–40)
用队列记录调用以"感知"副作用,最小可复制的模式:
std::queue<GraphicsAction> actions;
void drawLine(int firstX, int firstY, int secondX, int secondY) {
actions.push_back(GraphicsAction(LINE_DRAW, firstX, firstY, secondX, secondY));
}
// 测试:LONGS_EQUAL(5, actions.size()); 并逐个断言 action.type / 坐标作者提醒:"it is best to start with a very simple scheme and allow it to get only as complicated as it needs to be."(书页 40)
4.6 特征测试与依赖打破(来源 3、4,二手)
"A characterization test is a test that characterizes the actual behavior of a piece of code."(来源 3)
"The purpose of characterization testing is to document your system's actual behavior; not to check for the behavior you wish your system had"(Feathers 原话经来源 4 引述)
来源 4 的三阶段流程与验证技巧:
- "Get the code run into automated tests"(最难,靠切依赖)→ "Capture interesting output"(返回值或自定义 logger)→ "Vary inputs as much as possible to cover all possible scenarios"
- 验证测试网真的能抓虫:"I like to introduce deliberate bugs to verify I got at least one test fails."
- Emily Bache 四段式:"Arrange, Act, Print, Assert (compare with previous output)",其中 Printer 要滤掉日期等易变数据。
- 同义技术谱系:Approval Tests / Characterization Tests / Golden Master / Snapshot Tests / Locking Tests——"Yes, Approval and Characterization Tests are the same thing.";Golden Master 之名来自音频母带:"It's the one truth from which copies can be made."
Sprout / Wrap(来源 3):
- Sprout:新代码写到独立可测的地方,再回到遗留代码的"插入点"调用——最小改动、最小风险。
- Wrap 操作卡片:"Rename the old method you want to wrap",用原名建新方法调用旧方法,把新逻辑放在调用前/后;被改名的旧方法本身就是可在测试中替换的接缝。
4.7 C++ 工程视角的补强与反驳(来源 5)
- 反例重申:"the call to
playis not a seam because it is missing an enabling point"——成员变量是具体类且方法非 virtual 时,无法在不改函数体的情况下换行为。 - 新增第四类:compile seam(模板参数,静态多态),使能点是模板实例化处;相对对象接缝省掉 vtable 虚调用开销、接口只需提供实际用到的成员(compile-time duck typing)。
- 链接接缝三种实现:链接顺序 shadowing、GNU
ld -wrap(仅 Linux,"GCC for Mac OS X does not offer the linker flag -wrap")、LD_PRELOAD(macOS 对应DYLD_INSERT_LIBRARIES);共性:"their enabling point lies outside of the code, i.e., in our build scripts." - 局限清单:宏接缝"cannot trace member functions"、与成员函数同名会误替换;"-wrap"不适用于 inline 函数与共享库;LD_PRELOAD 对成员函数"unreliable... no reliable, portable and standards compliant way"。
证据质量评估:4.1–4.5 为一手书文(出版社官方 PDF + 作者本人书摘,页码可查);4.6 为高质量二手(逐章导读,含作者引语转引);4.7 为独立第三方实践(有代码与工具链约束,可复现)。三组证据在"缺使能点即非接缝""link seam 使能点在代码外"两点上独立收敛,交叉验证充分。
五、结论
- 接缝模型的本质:把"这段代码能不能安全改"从对整个代码库的设计评价,降维成对单个调用点的局部判断——看它有没有使能点。没有就先造一个(通常一次 Extract & Override 或参数化构造),造接缝的过程本身就是依赖打破。
- 三个主题是一条流水线:接缝(找到能换行为的地方)→ 依赖打破(最小侵入地把地方造出来,Sprout/Wrap/Extract…)→ 特征测试(在换上测试替身之前,先用真实行为填满断言)。顺序不可颠倒:特征测试是让接缝上的替换"可验证"的前提。
- 特征测试的正确姿势:它记录现状、包括 bug;发现 bug 的正确动作是先写一个证明 bug 存在的特征测试锁定它,再修,而不是边测边修(来源 4 的工作流隐含此纪律;快照滥用的反面教训是"people just update snapshots without really understanding what's going on")。
- 语言决定接缝菜单:OO 语言优先对象接缝;C++ 额外有模板(compile seam);C/脚本语言常只能用链接/预处理接缝或"参数列表即接缝"。使能点在代码外(构建脚本、classpath、环境变量)的接缝威力大但难被注意到——代码评审时容易漏。
- 对个人项目的直接推论:见第七节——一个工具不需要"有完整测试"才算健康,只需要要改的那条路径上有接缝和特征测试;反向地,把 subprocess/时钟/网络收敛到单一封装层,等于提前给未来的自己造好接缝。
六、局限
- 2004 年的技术底座:Java 例子依赖 classpath 手工替换,今天 Mock frameworks(Mockito/Byte Buddy)与 JDK 工具已把 link seam 的大部分场景收编成 API 调用;Python/JS 这类动态语言里 monkeypatch/模块 mock 让"对象接缝"几乎免费——书中"打破依赖很难"的部分论证力度随语言演化衰减。C++ 部分未覆盖 C++11 以后的 lambda/std::function 注入(Rüegg 提到 C++11 但未展开)。
- 定义的争议性:作者自己承认被 grief("I've gotten some grief for this definition")。"没测试 = 坏代码"对一次性脚本、探索性 notebook、被平台加密无法携带测试的代码(本机 QMT 即是,见 7.1)不成立——更准确说是"没有测试的正在演化的代码"。
- 书中没有给"特征测试遇到非确定性"的完整方案:时间、随机、网络抖动会让 golden master 不稳定;来源 4 只给了"Printer 滤掉易变数据"的方向性建议,没有可操作的通用解(现代方案:快照可调字段 / 假时钟,书里未涉及)。
- 架构级遗留系统覆盖不足:接缝是调用点级的显微镜,缺少跨服务、数据迁移、schema 兼容这类"行为特征化"的技法(第 12 章 pinch point 是最接近的,TOC 证实书页 182,但样章未含正文)。
- 依赖打破技术的"临时性"风险:Sprout/Wrap 刻意绕开测试动手术,作者在书页 xxi 说它们是 "in the service of putting tests in place"——但实践里极易变成永久性的旁路结构;书本身没有强力的反退化机制(依赖命名约定与评审纪律)。
- 本笔记的边界:样章只含前言+Ch1+Ch4,第 13 章特征测试正文(书页 185–196)与 Part III 目录(书页 ~427 起)未获一手文本,特征测试流程引自二手导读;未运行书中任何代码示例;QMT/工作回顾项目的"反思"是静态分析,未实际写测试验证可行性(7.5 清单留作执行项)。
七、对我的启发 —— 结合个人历史项目的可执行反思
7.0 项目取证(本会话实跑命令与事实)
| 项目 | 位置 | 本会话取证 | 事实 |
|---|---|---|---|
| 国金 QMT 量化策略 | D:/国金QMT交易端模拟/python/ | find ... -name "*.py" | wc -l → 33;find ... -iname "*test*" -name "*.py" → 0;二进制头分类脚本 | 33 个 .py、0 个测试;14 个明文(GBK,如 ARIMA预测.py 69 行,ContextInfo×13、handlebar×2、get_market_data×1);19 个被平台加密(头部 R3/RS 或整文件 base64 块,含用户改进量最大的 期货网格.py 71KB、增强网格策略V2.py 58KB、期权网格.py 30KB)——源码在本机不可读 |
| 个人工作回顾工具 | C:/Users/马鑫悦/Documents/工作回顾/ | 读 scripts/generate_work_review.py 统计 | 930 行 / 41 个函数 / 0 测试引用 / datetime.now 仅 1 处;函数名清单显示分层清晰:parse_args/parse_date/build_window(纯逻辑)→ load_config/parse_simple_yaml → run_git/discover_git_repos/collect_commits(副作用) |
| douyin 数据看板前端 | D:/projects/douyin_dashboard_frontend/ | 读 package.json + find -name "*.test.*" -not -path "*/node_modules/*" | wc -l | 24 个测试文件、vitest run、precommit:check = lint + tsc --noEmit + test——已经是"非遗留代码"的对照组 |
| 个人博客 | D:/my-blog/(Hexo) | ls;项目盘点 _索引.md 记载"2025-11 后未动" | 低频变更,不需要接缝投资 |
7.1 QMT 量化脚本:加密源码倒逼"记录级特征测试"
这是全书理念的一个尖锐反例:源码被平台加密,19 个策略文件(恰是用户投入最多、最想改的网格策略族)在本机连 import 都做不到——Feathers 意义上的所有源码级接缝(对象/链接/预处理)全部失效。但这不等于只能裸奔:
- 降级到记录级 golden master:QMT 平台本身能导出回测报告、成交记录、日志。每次改策略参数前,先把当前参数下的回测输出(净值序列、逐笔成交表)导出存档作为"母带",改完重跑对比。这正是特征测试的思想搬到输出层——"document your system's actual behavior"(对平台而言行为 = 它产生的记录)。可执行:
# 在 D:/国金QMT交易端模拟/export_data/ 建立母带目录(该目录已存在,本会话 ls 验证)
# 每次"改参数前的最后一次成功回测"导出后:
cp export_data/回测导出.csv "export_data/golden/$(Get-Date -Format yyyyMMdd-HHmm)_策略名_参数指纹.csv"
- 明文小脚本反而有书上模式的现实标本:
ARIMA预测.py的入口是handlebar(ContextInfo)——ContextInfo 是平台注入的参数,参数列表就是使能点(与书页 42buildMartSheet(Cell cell)完全同构)。要测它不必启动 QMT:构造一个假 ContextInfo(字典/简单对象,预置get_market_data的返回),直接在普通 Python 里调handlebar(fake)。可执行:
# 1. 把 D:/国金QMT交易端模拟/python/ARIMA预测.py 复制为 tests/fixtures/ 下的样本
# 2. 新建 D:/CodexData/qmt-strategy-tests/(git 管理),pip install pytest
# 3. 第一支特征测试:调 handlebar(fake_context),把输出的序列 print 出来锁定成 golden 文件
- 教训沉淀:平台加密(vendor lock-in)是"源码级测试"的终极反模式。今后任何策略代码,本机保留一份明文镜像 + 测试(哪怕手动同步),平台里那份当作部署产物。
7.2 工作回顾工具:教科书式的"先接缝后特征"练习场
generate_work_review.py 的函数分层恰好是 Feathers 想要的改造地形:
run_git是天然接缝(subprocess 封装,全部 git 交互的咽喉):按书页 42 的模式,把run_git做成可注入参数——collect_commits(repo, run=run_git),默认真实现,测试传 fake。参数列表即使能点,一行签名改动完成对象接缝。parse_simple_yaml/build_window/parse_date是零风险起步点:纯函数、无副作用,特征测试只需喂输入锁输出。930 行的工具,这三支测试就能覆盖配置解析最常见的回归。datetime.now全文件仅 1 处:时钟依赖已经收敛——这是本会话取证里最幸运的发现。把这一处改成可注入(或 monkeypatch),窗口逻辑就能确定性测试。- 纪律对照:这个工具"活跃使用中(logs 持续更新到 2026-10-24,见
D:/projects/_索引.md)",即每周末报告都依赖它。按书的定义它是遗留代码(无测试),且正在被每次"改报告格式"反复触碰——正是"改动频率 × 无测试"风险矩阵里该优先动手的那个。
7.3 douyin 前端:对照组的启发是"守住接线"
24 个测试文件 + precommit:check 三连(lint + tsc + test)说明这个项目已经在书定义的"非遗留"一侧。两个仍然值得做的反思:
- 使能点藏在脚本里:
dev/build脚本用API_PROXY_TARGET环境变量注入后端地址(本会话读package.json验证)——这正是"enabling point outside the program text"的现代形态。守住这条纪律:任何新依赖(后端地址、密钥、feature flag)一律走环境变量/注入,不在组件里 hardcode,测试替身就有地方可插。 - 快照滥用警报:来源 4 的批评("people just update snapshots without really understanding what's going on")对 24 个测试文件同样适用——定期抽查是否有"改断言迁就实现"的提交习惯(
git log -p -- '**/*.test.*'里高频率的 expected 值改动是危险信号)。
7.4 给新项目的三条"预埋接缝"规则
- 副作用收敛到单一封装层:subprocess、网络、时钟、文件系统各只允许一个出口函数——未来的接缝天然存在,不用再"打破依赖"。
- 构造函数参数即接缝:写新类时把协作者从构造函数传入(哪怕默认实现就一行),这是书页 42 模式的零成本预埋。
- 变更先问"在哪断言":动任何超过 20 行的函数前,先回答"改坏了什么测试会红"。答不出来 → 先花 10 分钟在该函数出口处加特征测试(print 锁定 → assert),再动刀。
7.5 可执行清单(下一步照做)
- [ ]
D:/CodexData/qmt-strategy-tests/:git init + pytest,对ARIMA预测.py的handlebar(fake_context)写第一支特征测试(来源:7.1 方案) - [ ] QMT 回测导出建
golden/母带目录,改参数前先存档(来源:7.1 方案) - [ ]
generate_work_review.py:为parse_simple_yaml、build_window各写一支锁定测试;run_git参数化(来源:7.2 方案) - [ ] 给
douyin_dashboard_frontend跑一次git log -p -- '**/*.test.*' | grep -c "^[+-].*expect",看断言改动频率是否异常(来源:7.3 方案,本会话未执行) - [ ] 重读原书第 12–13 章全文(Interception Points / Characterization Tests,样章未含正文)——来源 1 的 TOC 显示书页 173–196
八、术语速查表
| 术语 | 定义(原文) | 出处 |
|---|---|---|
| Seam | "a place where you can alter behavior in your program without editing in that place" | 书页 31 |
| Enabling point | "a place where you can make the decision to use one behavior or another" | 书页 36 |
| Preprocessing seam | 使能点 = 预处理宏(如 TESTING);保留给"dependencies are pervasive"的场合 | 书页 33–36;InformIT |
| Link seam | 使能点"always outside the program text"(构建脚本/classpath) | 书页 37–40 |
| Object seam | OO 中"call 不决定执行哪个方法";使能点常是参数列表/构造点 | 书页 40–44 |
| Compile seam(Rüegg 扩展) | 模板参数静态注入,使能点 = 实例化处 | ACCU |
| Sprout Method/Class | 新逻辑写到独立可测处,回插插入点 | 书页 59/63(TOC) |
| Wrap Method/Class | 改名旧方法→原名新方法包住它→新逻辑放调用前后 | 书页 67/71(TOC) |
| Interception point | 一片代码的多处公共汇合点,判断该在哪写测试 | 书页 174(TOC) |
| Pinch point | interception point 中"输入变化最能暴露输出错误"的窄口 | 书页 182(TOC) |
| Characterization test | "a test that characterizes the actual behavior of a piece of code" | 书页 186(TOC)+ 来源 3 |
| Golden Master / Approval | 同一技术的音频母带隐喻:"the one truth from which copies can be made" | 来源 4 |
附:来源链接汇总
- Pearson 官方样章 PDF(一手书文):https://ptgmedia.pearsoncmg.com/images/9780131177055/samplepages/0131177052.pdf
- InformIT · Feathers 连载书摘(一手):https://www.informit.com/articles/article.aspx?p=359417&seqNum=3 (seqNum=1 为同章首页 https://www.informit.com/articles/article.aspx?p=359417&seqNum=1 )
- understandlegacycode · 全书要点导读:https://understandlegacycode.com/blog/key-points-of-working-effectively-with-legacy-code
- understandlegacycode · 特征测试术语与流程:https://understandlegacycode.com/blog/characterization-tests-or-approval-tests
- ACCU Overload · Refactoring Towards Seams in C++:https://accu.org/journals/overload/20/108/ruegg_1927/
- 原书出版社页(版本信息):https://www.informit.com/store/working-effectively-with-legacy-code-9780131177055
*本笔记所有 PDF 引语由 pypdf 从官方样章逐字提取(sample_text.txt,56 页 101,135 字符),引语旁标注书页码;二手引语经 WebFetch/webReader 全文抓取。项目取证命令与输出见 7.0 表,全部为本会话实跑。*