一次最小变更四个动作:写成两行需求、先出计划、改完当场验、留痕两段。 计划的价值不是让你看懂,是把「不动的地方」变成明文承诺。 Demo 里不出计划那版动了三个文件十二行,出计划那版只动一行。
前面两篇把前提准备好了:能跑、能验。这一篇走一遍完整流程。 为什么强调「最小变更」?因为流程的价值要在小事上看清。 大事上变量太多,你分不清哪一步起了作用。 Demo 用同一个需求做了两遍:一遍不出计划直接改,一遍先出计划。 两遍的代码改动量、文件数、提交内容都摆出来对比。
一、选一个真需求
真需求的意思是:它真的需要改代码,而且改完有办法判断对不对。
「重构一下这个模块」不是真需求——它没有终点。
把需求写成两行:目标一行,验收一行。
只有目标那一行的时候,「返回一句默认话」也算合法实现。
Demo 里那两行是:
目标「空消息不该回话」,验收「handle 拿到空串或纯空格时返回空串,且不调用 reply」。
第二行把「不该回话」这个含糊的说法变成了可执行的判断。
一个自查方法:把验收那行交给别人,他能不看代码就判断对错吗?
不能,就还不够具体。
二、让 Agent 先出计划
计划要包含四样:会改哪、不动哪、怎么验、大概几步。 最容易漏的是「不动哪」——而它恰恰是计划里最值钱的一项。 为什么?因为 Agent 的默认行为是「顺手」。 它看到等级表里 2、1、0 这三个数,会觉得「改成 3、2、1 更整齐」; 它看到 README 写得乱,会觉得「顺便整理一下」。 这些都不在你的需求里,但它觉得这是做好事。 Demo 里不出计划那版就是这么歪的:需求只值一行,实际动了三个文件、加两行删十二行。 多出来的两处,全是「顺手」。 写了「不动 emo.py」,它就不动。 这不是它更听话了,是你把边界说出来了——没说出来的边界,在它看来不存在。
三、改完当场验
「当场」的意思是:不等提交、不等别人 review、不等明天。
改完立刻跑那条一键验证。
为什么强调当场?因为失败的信息是有时效的。
改完马上去验,失败了你还能想起刚才动了什么;
隔一天再验,你只能重新读一遍 diff。
还有一层:验证要跑在「你信的那条命令」上。
不要临时拼一条 python -c "..." 来验——临时命令验过了,下次没人能重现。
把它写成文件(哪怕八行),才算验过。
四、留痕
留痕就是提交信息,两段:改了什么、为什么这么改加怎么验的。
| 段 | 写什么 | 给谁看 |
|---|---|---|
| 第一段 | 改了什么,一句话 | 扫 log 的人 |
| 第二段 | 为什么、怎么验的 | 半年后的接手人 |
为什么第二段值得写? 因为半年后你会看到一个「莫名其妙」的改动,然后花二十分钟搞清它为什么存在。 而当时写清楚只花一分钟。 顺手记一件事:验证的输出不用全贴进提交信息,写「通过 3 / 失败 0」就够。 贴一大段日志的结果是没人读。
五、动手 Demo:一次最小变更的四步:计划、改、验、留痕
同一个需求做两遍。 第一遍不出计划,直接改——它会不会顺手改别处?看 diff。 第二遍先出计划,再改——看改动量差多少。 两遍用的仓库、需求、验收完全一样,只有「有没有先出计划」这一个变量不同。
plan = [
(u"会改", u"main.py 的 handle:空串与纯空格直接返回空串"),
(u"不动", u"emo.py 的判定逻辑与 LEVEL 表"),
(u"不动", u"README、tasks.py、config.py"),
(u"怎么验", u"三条断言:空串、纯空格、正常消息"),
]
for a, b in plan:
P(u" %s %s" % (pad(a, 8), b))
实跑输出:
--------------------------------------------------------------------
一次最小变更的四步:计划、改、验、留痕
--------------------------------------------------------------------
① 需求先写成两行:目标与验收
--------------------------------------------------------------------
目标:空消息不该回话
验收:handle 拿到空串或纯空格时返回空串,且不调用 reply
两行都有,才叫一个需求。只有第一行的时候,它做出来「返回一句默认话」也算合法。
② 不出计划,直接改
--------------------------------------------------------------------
README.md | 10 ----------
emo.py | 2 +-
main.py | 4 ++--
3 files changed, 3 insertions(+), 13 deletions(-)
合计:加 3 行、删 13 行、涉及 3 个文件
需求只值一行,实际动了三个文件。多出来的两处是「顺手」:调了等级表、把 README 砍成一行。
! 顺手改是 Agent 最危险的习惯之一。
它不觉得自己在越界,它觉得「顺便把这里也理顺了」——而你没让它这么做。
③ 出计划,再改
--------------------------------------------------------------------
计划:
会改 main.py 的 handle:空串与纯空格直接返回空串
不动 emo.py 的判定逻辑与 LEVEL 表
不动 README、tasks.py、config.py
怎么验 三条断言:空串、纯空格、正常消息
这时仓库状态:干净,还没动手
验证:通过 3 / 失败 0
改动:1 1 main.py
只动了 main.py 一行。没出计划的那一版动了三个文件,其中两处是顺手。
! 计划的用处不是让你看懂,是让「不动的地方」变成明文承诺。你写了「不动 emo.py」,它就不动;
没写,它就会「顺便理顺」。
④ 留痕:提交信息写两段
--------------------------------------------------------------------
[ok ] (无输出)
0bd7276 feat: 空消息不回话
check_empty.py | 8 ++++++++
main.py | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
! 两段的意思:第一段说改了什么,第二段说为什么这么改、怎么验的。半年后接手的人读第二段就够了。
⑤ 四步各自拦住什么
--------------------------------------------------------------------
| 步骤 | 拦住的问题 | 不做会怎样 |
|---|---|---|
| 目标加验收 | 「做完了」没有标准 | 它交什么你都得收 |
| 先出计划 | 顺手改别处 | diff 里混进两处无关改动 |
| 当场验 | 改完其实不通 | 提交之后才发现 |
| 留痕两段 | 半年后看不懂 | 得翻代码猜意图 |
第一遍:三个文件、加两行删十二行。
需求只值一行,多出来的两处是「顺手」——调了等级表,把 README 砍成一行。
第二遍:一个文件、加一行删一行。
1 1 main.py 这一行 numstat 就是「没越界」的证据。
注意第二遍的验证是在改完之后立刻跑的,三个断言全过,退出码零。
这一轮不省——省掉它,你只有一句「改好了」。
最后那个提交有两行 stat:check_empty.py 和 main.py。
验证脚本也跟着进仓库了,这是好事:下次同类需求,这条断言可以直接复用。
30 秒实验
- 拿一个你真要做的小需求,先写两行。 写完发现验收那行写不出来,就说明这个需求还没想清。
- 下一次让它干活,先要一份计划,只要四行。 看它写的「不动」那行跟你想的一样不一样。
- 翻一下你上一个提交的第二段。 如果只有一句话,试着补一句「怎么验的」。
常见误区
- 「先出计划太慢,直接改快。」 Demo 里不出计划那版多了两个文件的改动。 revert 那两处花的时间,比写四行计划长。
- 「顺手改的那些其实改得挺好。」 可能。但它没在你的需求里,也没在你的验收里。 「改得好」和「该改」是两件事。
- 「验过了就行,不用写下来。」 下次没人能重现你怎么验的。 写成八行文件,成本很低,收益是「可重复」。
自测三问(点开对答案)
1. 计划里最值钱的是哪一项?为什么? —— **「不动哪」这一项。** **因为 Agent 的默认行为是顺手改**——**没说出来的边界,在它看来不存在。** 2. 为什么验证要「当场」跑? —— **因为失败的信息有时效。** **当场跑,你还记得刚才动了什么;隔一天跑,你得重读 diff。** 3. 提交信息第二段写什么?给谁看? —— **写「为什么这么改」和「怎么验的」,给半年后的接手人看**——**那个人通常就是你自己。**下一篇 5.4 收这一章:把这次闭环变成可复用的东西,顺便把成本拆开算一遍。
- ☐ (本篇完,下一篇 5.4 从个人闭环到团队资产:复用、成本与模型选择)