ZJY365 实战
从想法到上线

第 7 章 · 验收、排错与迭代

按 PRD 的 AC 逐条验收,识别假成功、数据未保存、权限错误三类典型问题;学描述故障、缩小范围、让 AI 修复、复测回归、恢复旧版本。含三个教学演练。

这一章解决什么问题

「AI 说做完了」和「真的做完了」之间,隔着一条验收的河。AI 不会故意骗你,但它生成代码有个系统性倾向:高兴路径很顺畅,不高兴路径爱撒谎——保存失败装成功(假成功)、报错被悄悄吞掉(被吞掉的报错)、权限检查漏掉。这一章教三件事:

  1. 验收:拿第 3 章的 AC 逐条过,把「感觉做完了」变成「逐条有证据」;
  2. 排错:出了问题,怎么描述、怎么缩小范围、怎么让 AI 修得准、修完怎么复测;
  3. 恢复:改坏了怎么退回上一个好版本。

本章三个故障都是教学演练:演练一来自随教程附带的演示文件,演练二、三是文字推演。它们示范的是真实产品里会发生的真实故障形态,但都不是你项目的真实事故——请在自己的项目里用同样方法抓真的。

开始前你要有什么

  • 第 5 章完成 T1–T5 的项目(或至少完成 T2)
  • 第 3 章的 PRD(AC1–AC8 是验收清单)
  • 会开浏览器的开发者工具(F12 或右键「检查」——本章用到 Network 面板)

分工:人判断什么,AI 做什么

人负责(判断)AI / Skills 负责(加工)
按 AC 验收,宣告「过/不过」提供验收操作建议
描述故障:预期 vs 实际 + 证据先解释原因、给出最小修改方案,经你确认再动手
决定「修」还是「回退」执行修复后给出复测清单
复测并宣告修复成立检查改动是否波及无关功能

排错有一条铁纪律:不让 AI 直接动手,先让它解释「为什么」和「打算改哪」。原因:直接动手时 AI 常常重写一大片,掩盖了真正的病因,还可能改坏别处。

怎么做

第 1 步:逐条验收(约 20 分钟)

拿一张表过 AC1–AC8,一列都不许省(这是你的验收记录,存进项目 docs/验收记录.md):

AC操作预期(PRD 原文)实际结论
AC2登录,录入 resume + 释义列表立即出现,状态「未掌握」
AC3刷新;换浏览器登录再看已录的词都在
(8 条全列)

验收时随时启用假成功三连检查——凡界面显示「成功」的操作,都补三刀:

  1. 刷新页面,成果还在吗?
  2. 换浏览器(或无痕窗口)登录再看,还在吗?
  3. 有条件的话直查数据库(Supabase 控制台的 Table Editor 打开 words 表),那行数据真在吗?

界面会撒谎,数据库不会。

第 2 步:演练一——假成功(教学演练,约 10 分钟)

教程随附一个演示文件 examples/vocab-notebook/fake-success-demo.html(在本项目仓库里,双击打开)。它是一个故意做坏的「生词本」:

  1. 输入一个词,点「保存」→ 绿色提示「已保存 ✓」;
  2. 刷新页面 → 词没了。

打开它的源码看病因(就 30 行):

// 故意的错误示范 —— 不要模仿
function saveWord() {
  try {
    words.push(inputValue);      // 只推进了内存里的数组
    showMsg('已保存 ✓');          // 没有任何真实保存,就报了成功
  } catch (e) {
    // 出错也一声不吭 —— 错误被吞了
  }
}

两个错误叠一起:没有真实保存动作(对照假成功反模式),错误被 catch 吞掉(对照被吞掉的报错)。真实项目里的假成功是它的加强版:请求发到了服务端、服务端返回 500,前端照样提示「已保存」——因为代码写成了「发了请求就算成功」,根本没看响应。

第 3 步:演练二——数据没存上,怎么缩小范围(教学演练·文字推演)

现象:点保存,页面提示保存失败;或更糟——提示成功但刷新就没了。用开发者工具的 Network 面板做一次分叉定位:

点保存后看 Network 面板里那次请求:

├── 根本没有新请求
│     → 病在前端:按钮没绑事件、表单被默认行为刷新、JS 报错中断
│     → 证据:Console 面板的红色报错,原样复制

├── 有请求,状态 4xx / 5xx
│     → 病在服务端:400=校验拒绝(看响应体的 error 文案)
│                500=服务端炸了(看服务器日志/让 AI 读响应)
│     → 证据:请求的 URL、状态码、响应体

└── 有请求,状态 200,但刷新后数据没了
      → 病在「假成功」:前端没等响应就报了成功,
        或后端「假装写入」了(返回 ok 但没落库)
      → 证据:响应体内容 + 数据库里没有那行

对照第 6 章七段旅程:没请求 = 坏在①②;4xx/5xx = 坏在③④⑤;200 但没数据 = 坏在⑤⑥「谎报军情」。先定位段落,再动手——这一步是人与 AI 分工的示范位:定位是你的判断,修复是它的执行。

第 4 步:把故障说清楚——给 AI 的报告模板

定位到段落之后,用这个模板报给 AI(可复制):

问题报告(AC7 验收失败)

现象:断网状态下点「保存」,界面显示「已保存 ✓」,
刷新后词条消失。

预期:按 PRD AC7,应显示失败提示,不显示「已保存」。
实际:显示成功,数据未保存。

环境:本地 dev;Chrome;已登录测试账号。

证据:
- Network 面板:POST /api/words 请求状态 500(失败),
  响应体:{"error":"database connection error"}(截图已存 docs/)
- 数据库 words 表中没有该行(Table Editor 截图已存)
- Console 无红色报错

已尝试:换浏览器复现一致。

请你:
1. 先解释为什么会这样(不要改代码);
2. 给出最小修改方案:改哪个文件、改什么、不动什么;
3. 我确认后你再动手,完成后给我复测步骤。

好的报告三要素:可复现的步骤、预期与实际的差距、证据(截图/状态码/响应原文)。AI 拿到这种报告,修复命中率完全不同;你下次自己看,也能立刻想起当时发生了什么。

第 5 步:演练三——权限漏洞(教学演练·文字推演)

设一个第 5 章 T5 里 AI 真有可能写出的 bug:列表接口忘了按账号过滤。

// 有洞的写法(教学示范,别学)
export async function GET() {
  const rows = await db.select().from(words);  // ← 少了 where user_id
  return Response.json({ words: rows });
}

界面上的表现完全正常:user-A 登录,看到的「恰好」都是自己的词——因为数据库里暂时只有 user-A 的数据。但用 user-B 登录,或直接请求接口,A、B 两家的词全量返回。这就是第 6 章说的「隐藏入口不等于权限」:界面恰好没露馅 ≠ 权限存在。

修复原则与验收:

  • 修:查询补上 where words.user_id = 会话用户.id(第 6 章沙盒第⑤眼的那句 where);顺手检查改、删两类的接口是否同样带条件——读有洞写也常跟着有洞。
  • 验收:AC8 原样重测——user-B 登录界面看不到 A 的词,直接请求接口拿不到 A 的词。两条都过才算修复。

第 6 步:复测与回归——修好一个,别弄坏三个

AI 报告修好了,按这个顺序收尾:

  1. 复测原问题:原样重走故障步骤,确认消失;
  2. 回归检查:把 AC 全表里跟这次改动相关的相邻条目重跑。修 AC7 动了保存链路,AC2、AC6、AC7 三条至少重跑;动过查询过滤的,AC2/AC5/AC8 重跑;
  3. 更新验收记录表:结论列写「已修复 + 日期 + 复测人(你)」。

回归不过 = 没修好。退回去重来,不要带病前进。

第 7 步:恢复旧版本——最后的安全网

修三轮还修不好,或 AI 把别处改坏了,别恋战,回退:

git status                  # 看哪些文件改动了
git restore 文件名           # 丢弃单个文件的未提交改动
git restore .               # 丢弃全部未提交改动(谨慎)
git revert 提交号            # 已提交的坏版本,生成一个「反向提交」撤销它

两条老规矩:

  • 第 5 章的版本规矩在这里兑现:每个任务验收过就 commit——所以「上一个好版本」永远存在,git log 里找得到;
  • 代码版本 ≠ 数据git revert 恢复的是代码,用户录的词在数据库里,不跟 git 走(概念课:数据存在哪)。排错时别指望「回退代码」能把误删的数据变回来。

第 8 步:验收全绿之后——进入迭代

AC1–AC8 全过,第一版就做完了——注意是「做完了」,不是「成功了」。成功与否由第 8 章上线后的真实使用回答。在那之前,把第 1 章的假设清单拿出来看一眼:哪些假设现在就能低成本验证(比如找一个同样备考的朋友走一遍流程,观察 TA 在哪一步卡住——观察方法见教学指南第九课的试用记录法),哪些要等上线。

迭代排优先级的三分法:无法完成任务的 → 影响操作的 → 外观建议。第一类永远最优先,外观建议永远排最后。

产物与检查

产物:验收记录表(8 条 AC 全列,带证据引用)+ 问题报告存档docs/ 下)。检查表:

  • AC1–AC8 每条有「实际」列的记录,不是全打勾了事
  • 界面报「成功」的操作都补过三连检查(刷新/换浏览器/直查库)
  • 每个修复都有复测记录和回归记录
  • 知道当前最新好版本的 git 提交号

不满意或失败时怎么调整

  • AI 解释不了故障原因(给了原因但和证据对不上):把证据再喂细一点——完整的响应体、Console 报错原文、复现步骤的最小化版本(少到「点一个按钮」)。还说不通,就按七段旅程人工分段检查:每段单独验证,锁定断点。
  • 修了又坏、坏了又修:停下,这是在猜。回演练二的分叉定位,重新取证;再不行就 git revert 回到好版本,把故障最小复现发给 AI 重来。
  • 发现 AC 本身定错了(比如「断网提示」其实实现成本远超预期):AC 是约定不是圣旨,改 PRD、在验收记录里注明「AC7 调整为……(原因)」。诚实地改约定,好过假装它过了。

交给下一章什么

  • 全绿的 AC1–AC8——但只算「本地验收」。第 8 章把它们搬到线上重跑一遍:本地好不算好,线上好才算上线;
  • 验收记录和问题报告——上线后试用反馈来了,新一轮排错从这里续写。

案例进度:本地验收全过。下一章,把这套东西发上公网——并回答「上线」到底比「本地能跑」多了什么。

On this page