代码生成与改写:小步提交,避免大爆炸式重写

"帮我重写整个 order 模块"是 AI 辅助开发里最贵的一句话。它一次产出上千行 diff,你既没法逐行审查,也没法在出错时定位是哪一步引入的;一旦行为偏移,回退的代价等于重新写一遍。

本章要解决的问题

  • diff 太大,评审退化成"扫一眼 + 点通过";
  • 一次改动涉及多个文件,测试红了不知道是谁的锅;
  • 让 AI"优化一下",它顺手改了命名、日志和错误处理,噪音淹没真实改动;
  • 出问题后 git bisect 失去意义,因为一次提交里塞了十件事。

核心纪律一句话:一次只动一个函数或一个文件,每步编译加测试,逐块审查 diff。

小步改动纪律

纪律具体做法检查命令
一次一个函数提示词里写死"只修改 Redeem 函数体"git diff --stat 只应出现 1 个文件
一次一个文件跨文件改动拆成多个提交,先改接口再改调用点git diff --stat 变动行数 < 200
每步编译加测试每次生成后立刻跑,红了先修再继续go build ./... && go test ./...
逐块审查 diff按 hunk 读,不按文件读git diff -U5 -- internal/coupon/service.go
提交信息写明范围refactor(coupon): 抽出核销校验函数git log --oneline -1

"每次生成后立刻跑"是最容易被跳过、也最不能跳过的一条:测试通过的每一步都是安全回退点,没跑测试的一步则是债务。

提示词:把范围钉死

目标:让 internal/coupon/service.go 的 Redeem 支持"订单金额低于门槛时返回 ErrBelowThreshold"。

严格约束:
1. 只允许修改 Redeem 的函数体,不改签名、不改其他文件;
2. 不改动现有注释、日志格式与错误文案;
3. 不要顺手重构、不要重命名变量、不要调整 import 顺序;
4. 输出 unified diff(git diff 格式),不要输出整个文件;
5. 如果发现必须改其他文件,先停下来说明原因,不要擅自改。

第 4 条尤其重要:要 diff,不要要文件。让 AI 输出整文件,你就得在几百行里找它改了哪 12 行;要 diff,审查面积直接等于改动面积。

一次改动应该有多大

规模行数参考能否一次交给 AI
单函数改逻辑5~40 行可以,最理想
单文件多函数40~150 行可以,但要逐 hunk 审
跨 2~3 文件改接口150~300 行拆两步:先改接口,再改调用点
整个模块重写500 行以上不要,见下一节

为什么"重写整个模块"危险

  1. 不可审查:1000 行 diff 里夹带的 3 行行为改变,人眼几乎必然漏掉;
  2. 行为漂移:旧代码里为绕过某个线上问题写的奇怪判断(带注释的特殊 if、被调过的重试次数)会在重写中消失,而这些恰恰没有测试覆盖;
  3. 责任链断裂:git blame 与 issue 的关联全部失效,日后排查失去线索;
  4. 无法二分:一次提交包含十处改动,git bisect 指到的是"一大坨",不是根因;
  5. 回退即重做:出错时不能只撤销一个函数,只能整体回滚,前面的时间全部白费;
  6. AI 不知道你没说的约束:重写时它按通用最佳实践来写,你项目里的历史包袱它看不见。

正确的做法是把"重写"翻译成有序的小步:先补测试固化现有行为 → 再逐个函数替换实现 → 每步测试全绿才提交。

# 重写前的安全网:先给旧实现补一组行为测试并确认全绿
go test ./internal/order/... -run TestOrderFlow -count=1 -v

# 每替换一个函数后
gofmt -l . && go build ./... && go test ./internal/order/... -count=1

常见坑

  • "顺便优化一下":这类模糊指令必然带来大面积无关改动,提示词里要显式禁止重构;
  • 让 AI 直接改文件而不看 diff:工具越自动,越要先用 git diff 决定是否保留;
  • 只在最后跑一次测试:中途的编译错误会被 AI 用"删掉调用"的方式掩盖,所以每步都要跑;
  • 相信 AI 的自我总结:它说"只改了一处"不算数,git diff --stat 才算数;
  • 格式改动与逻辑改动混在一步:gofmt 或 import 排序会污染 diff,应先单独提交格式变更。

小结:小步提交的本质是让每一步都可编译、可测试、可回退、可审查。提示词里钉死"改哪个函数、不许改什么、输出 diff 而不是文件",再配合 git diff --stat 与 go build && go test 两道闸门,AI 的产出就被压在可控范围内。"重写整个模块"不是效率,是把风险一次性堆积到最后一刻。

笔记加载中…