知道边界之后,能做的事只有三件:切小块、先复述、用验证代替质疑。 切小块不是「拆任务」,是「让每一块都能被单独验证」——这个区别决定了它有没有用。 三条方法都能量出成本,不是感觉。第一条的收益是 5 倍定位范围。
这一篇是第 2 章的收口。 前面四篇讲了:它靠预测下一个 token 干活、靠四样东西支撑、信息永远不完整、它还会犯三类错。 知道了这些,接下来不是「更小心」,是「换方法」。 这一篇给三条方法,每条都能落到具体动作上。 Demo 里量了第一条的收益:同一个任务,一次做完和分五块做,出错时的定位范围是 5 行对 1 行。 这个 5 倍不是估算,是数出来的。
一、把任务切成能被验证的小块
「切小块」这句话谁都会说,但大部分人切错了。 常见的切法是按「工作量」切:先把接口写完,再写实现,最后写测试。 这种切法有个问题:前三块都没法验证。 正确的切法是按「能不能单独验证」切。 每一块的结尾都要能回答一个问题:怎么知道这块对了? 答不上来的,说明这块还不够小,或者切错了方向。
| 切法 | 每块的验收 | 好不好 |
|---|---|---|
| 按层切(接口/实现/测试) | 前两块都没法验 | 不好 |
| 按功能切(登录/列表/导出) | 每块能跑给用户看 | 好 |
| 按文件切 | 改完了但跑不起来 | 不好 |
| 按「一次改动」切 | 每块一条测试能过 | 最好 |
「按一次改动切」是什么意思? 就是「这一块改完之后,应该只有一条测试从红变绿」。 如果一块改完有三条测试变绿,那它其实是三块——拆开之后,出错了你能立刻知道是哪一块的问题。 Demo 量过这个收益:五个函数一起加日志,diff 是 5 行;分五次做,每次 1 行。 第 3 处写错时,前者要在 5 行里找,后者只看 1 行。 差 5 倍。而且如果整份 revert,前者前 4 处白做。
二、先让它复述,再让它动手
这是三条里最便宜的一条,也最少人用。 因为它看起来「多一步」,而人讨厌多一步。 具体做法:动手之前,让它用自己的话说一遍「我理解的任务是……」。 你对照一眼,歪了当场纠正。 成本是一句话,收益是「在动手之前发现理解歪了」。 这一条为什么有效? 因为它的理解偏差在「复述」这一步会暴露出来—— 而如果直接动手,偏差会藏在代码里,直到你审 diff 才发现。 审 diff 的成本比读一句复述高一个数量级。 Demo 里那个复述漏了「别动返回值」。 而「返回值」恰恰是最容易被顺手改掉的地方—— 如果没复述,这个漏会在 diff 里出现,那时候已经改完了。 有个细节:复述不需要它写得多完整。 三句话就够——改哪儿、改成什么、不许动什么。 你把这三句当模板,每次都要,形成习惯。
三、不信任但有礼貌的默认姿态
「不信任」听着刺耳,但它是工程上的正确姿态。 不是怀疑它的人品,是承认「它可能看漏、可能记错、可能顺手改多」这三件事客观存在。 「有礼貌」是指:不要每次都说「你确定吗」。 反复质疑会让对话变成拉扯,而且它每次都会说「确定」——因为它的训练数据里,「被质疑后改口」是少数。
| 动作 | 做什么 | 花多久 |
|---|---|---|
| 看计划 | 动手前让它说打算改哪几个文件 | 十秒 |
| 看 diff | 先看文件数和行数,再看内容 | 一分钟 |
| 看退出码 | 命令返回 0 才算过,不看它怎么说 | 零 |
三个动作加起来不到两分钟。它们能拦住的是「看起来做完了」这一类, 而这一类占了失败案例的绝大多数。 「用验证代替质疑」是这一条的核心。 跑一遍比问十遍管用——因为「问」得到的答案是它生成的,而「跑」得到的结果是环境给的。 前者可以编,后者不能。
四、本章小结
第 2 章五节,可以压成一句话: 它是一个很擅长猜下一个 token 的程序,猜得准是因为代码的约束多; 但它看不见的部分等于不存在,而且它不会告诉你它没看见。 两条边界分别对应两种失误: 信息不完整 → 它会按惯例猜(补的办法:写下来、写成测试、让它复述); 三类工程错误 → 它会犯(补的办法:查文档、写死边界、跑全量)。 从这里往后,全书的重点就转到「怎么把这两条补上」: 第 3 章跑通第一次闭环,第 5~8 章讲 Harness 四件套,第 9~12 章在四个场景里用。 方法都从那两条边界推出来。 最后一句: 「知道边界」不是让你少用它,是让你知道在哪一步加人。 边界之外的活儿交给它,边界之内的活儿留给自己——这才是「会用」,不是「敢用」也不是「不用」。
五、动手 Demo:同一个任务,一次做完和分五块做
这个 Demo 把「切小块」的收益量出来。 任务:给五个函数各加一行日志。 做法 A:一次全改;做法 B:分五次改,每次一个函数。 两种做法都真跑 git,量 numstat。 然后算一个数:假设第 3 处写错了,审查的人要在多大范围里找那一处。 这个数就是这个方法的收益,不是感觉。 后面还演了「先复述」怎么用规则检查出漏项。 复述漏了「别动返回值」,而返回值恰恰是最容易被顺手改掉的地方。
# 做法 A:五个函数一起改
for i in range(1, 6):
one = one.replace(" return x * %d\n" % i,
' log.info("step%d x=%%s", x)\n return x * %d\n' % (i, i))
git diff --numstat # 加 5 删 0,合计 5 行
# 做法 B:一次一个,每块单独提交
for i in range(1, 6):
cur = get(base, "svc.py")
put(base, "svc.py", cur.replace(...))
git diff --numstat # 每块加 1 删 0
git commit -m "feat: step%d 加日志" % i
实跑输出:
--------------------------------------------------------------------
同一个任务,一次做完和分五块做
--------------------------------------------------------------------
① 任务:给五个函数各加一行日志
--------------------------------------------------------------------
svc.py 五个函数 step1~step5,每个就一行。
② 一次做完:一处改动,一份大 diff
--------------------------------------------------------------------
五个函数一起改:加 5 行、删 0 行,合计 5 行 diff
假设其中第 3 处写错了(这是常事),审查的人要在 5 行里找那一处。
③ 分五块做:每块一份小 diff
--------------------------------------------------------------------
| 块 | numstat | 出错时要看的范围 |
|---|---|---:|
| 第 1 块 | 加 1 / 删 0 | 1 行 |
| 第 2 块 | 加 1 / 删 0 | 1 行 |
| 第 3 块 | 加 1 / 删 0 | 1 行 |
| 第 4 块 | 加 1 / 删 0 | 1 行 |
| 第 5 块 | 加 1 / 删 0 | 1 行 |
分块之后,第 3 块写错:看 1 行、重做 1 行。
一次做完时第 3 处写错:要在 5 行里找;若整份 revert,前 4 处白做。
定位范围 5 行对 1 行,差 5 倍——这是数出来的,不是估的。
④ 先复述,再动手
--------------------------------------------------------------------
把它理解的任务复述一遍,你对照一眼就知道有没有理解歪。这一步几乎不花成本。
| 要素 | 原任务 | 复述 | 判定 |
|---|:---:|:---:|:---:|
| 范围 | 有 | 有 | — |
| 内容 | 有 | 有 | — |
| 禁区 | 有 | 无 | 漏了 |
这段复述漏了「别动返回值」——而返回值恰恰是最容易被顺手改掉的地方。
! 复述的成本是一句话,收益是「在动手之前发现理解歪了」。返工的成本是一整轮。
⑤ 不信任但有礼貌:三个动作
--------------------------------------------------------------------
| 动作 | 做什么 | 花多久 |
|---|---|:---:|
| 看计划 | 动手前让它说打算改哪几个文件 | 十秒 |
| 看 diff | 先看文件数和行数,再看内容 | 一分钟 |
| 看退出码 | 命令返回 0 才算过,不看它怎么说 | 零 |
三个动作加起来不到两分钟,能拦住八成的「看起来做完了」。
! 「有礼貌」是指:不要每次都说「你确定吗」。用验证代替质疑——跑一遍比问十遍管用。
结果:一次做完 5 行 diff,分块做每块 1 行。 第 3 处写错时,前者要在 5 行里找,后者只看 1 行——差 5 倍。 还有一个更隐蔽的差别:返工范围。 一次做完写错了,最省事的做法是整份 revert 重来——那前面 4 处白做。 分块做写错了,只 revert 那一块,前 4 块不受影响。 这个 Demo 的任务很小,所以差距只有 5 倍。 真实项目里一个改动动辄几百行,差距会到几十倍。 但倍数不重要,重要的是「这个数是能算出来的」——下一次你可以拿自己项目的数字算一遍。 复述那一段值得看第二遍: 表格里「禁区」那一栏,原任务有、复述没有,判定是「漏了」。 而这个漏,恰恰是最容易出事的一项—— 「别动返回值」这句话没说,它加日志的时候顺手把返回值改了。
30 秒实验
- 把你手上一个任务切成「每次一条测试从红变绿」的小块,数一数切成了几块。 超过七块,说明任务本身该拆成两个。
- 下次交任务之前,加一句「先说一遍你打算怎么做」。 就一句话,试试省下多少返工。
- 把「看计划、看 diff、看退出码」三个动作写进你的日常流程。 不到两分钟,但它们挡住了大部分「看起来做完了」。
常见误区
- 「切小块太麻烦,一次做完更快。」 快的是「做完」,慢的是「查错」。 一次做完省下的时间,会在审查和返工时还回去。 而且分块做的时候,每一块都能单独验证——验证得早,返工就少。
- 「复述是形式主义。」 复述的成本是一句话,收益是「在动手之前发现理解歪了」。 它是所有纠错手段里最便宜的一个——比审 diff 便宜,比返工便宜得多。
- 「不信任会让它表现变差。」 它不会因为你不信任就变差,也不会因为你信任就变好。 验证是为了让你自己知道结果,不是为了给它压力。
自测三问(点开对答案)
1. 「按能不能单独验证」切块,和「按工作量」切块,差别在哪? —— **按工作量切,前三块都没法验**(接口写完不能跑、实现写完没测试); **按可验证切,每一块结尾都能回答「怎么知道这块对了」。** 2. 复述为什么比审 diff 便宜? —— **复述是一句话,你读一眼就知道歪没歪;** **diff 是几十行,你要逐行判断。** **而且复述在动手之前,改的是「理解」;diff 在动手之后,改的是「代码」。** 3. 为什么说「用验证代替质疑」比反复问「你确定吗」有效? —— **因为「问」得到的答案是它生成的,可以编;「跑」得到的结果是环境给的,不能编。** **而且它每次被问都会答「确定」**——质疑换不来信息。第 2 章到这里收住。 下一篇进第 3 章 3.1,动手装、登、跑第一条命令——从这一节开始,正式进入「怎么用」的部分。
- ☐ (本篇完,下一篇 3.1 安装与登录:先把入口跑通)