主题:第11部分. 功能第二阶段
难度级别:中级
预计学习时间:6-8小时(理论:2小时,实践:4-6小时)
前置条件: 已完成项目中的功能第一阶段
Git基础知识(分支、合并、fast-forward)
关系型数据库(SQLite)使用经验
熟悉Hono框架或类似的Web框架
服务器端组件渲染的基本理解
使用Vitest或类似测试框架的经验
数据库迁移概念的理解
熟悉规范驱动开发(SDD)方法论
学习目标: 应用干净启动检查清单来准备功能第二阶段,包括检查仓库状态和确认无未完成更改
通过结构化访谈制定第二阶段规范,包含三类问题:边界、决策和上下文
将第二阶段实现拆分为可管理的任务组(每组5-7个任务),通过中间提交降低认知负荷
创建修复规范(bugfix.md),包含必需的「不应更改的内容」部分和回归场景
使用目标审查请求进行阶段边界验证,重点关注迁移安全性、测试覆盖率和与技术栈的符合性
概述:功能第二阶段是规范驱动开发方法论中的关键阶段,它检验开发过程是否变得可重复。如果说第一阶段往往靠热情推进,那么第二阶段则展示团队是否能够干净地开始工作、保持边界、更新变更日志,并且不因变更量过大而疲惫。在AgentClinic项目的背景下,第二阶段被命名为「代理与疾病」,并引入了大量功能:SQLite数据库、代理和疾病表、初始数据、新页面 /agents 和 /ailments、测试和导航。第二阶段的主要难点在于认知负荷:代理一次运行可能修改数十个文件,而人根本无法及时理解。因此,本阶段的核心位置属于复杂度管理技术:任务分组、中间提交、定期边界检查,以及拒绝不符合规范的变更。
关键概念: 干净启动:开始新功能分支前的必需程序:切换到main分支、通过fast-forward更新、检查无未提交更改、运行测试和类型检查。在与AI代理协作的语境中,包括清理上下文(/clear)和检查路线图。禁止在存在未完成更改时开始新阶段——否则代理生成的变更将难以解释和集成。
规范访谈:在写入文件前通过向代理提出三类问题来创建规范的方法:(1)边界——哪些领域实体和页面属于本阶段;(2)决策——数据库、初始数据、接口约定、测试;(3)上下文——语气、限制、风险以及应排除在边界之外的内容。这种方法防止实现泄漏到需求讨论阶段。
认知负荷:人无法同时理解数十个被修改文件的现象。视线滑过,错误漏掉。降低方法:逐个或成对实现任务组、中间提交、请求变更摘要、使用 /review、拒绝不符合规范的变更。
任务组:将阶段实现逻辑性地拆分为每组5-7个任务。「代理与疾病」的示例分组:启动数据库、领域模式、初始数据、路由和组件、测试和验证。每组以中间提交和检查结束。
修复规范(bugfix.md):用于错误修复分支的替代规范模板。包含:当前行为、预期行为、根本原因证据、不应更改的内容、回归场景。与功能规范的主要区别——包含保护现有功能的必需部分。
回归场景:保证修复没有破坏正常工作的检查。对于表单验证修复:POST非空message继续工作、POST空name但非空message被保存、现有记录不被更改。
validation.md中的事实复现:修复前失败、修复后通过的命令或场景。示例:npm test -- feedback,预期POST空message返回400。这是客观验证是否修复了实际损坏内容的依据。
合并前变更日志:必需更新CHANGELOG.md,包含当前日期标题、简要列举领域模式、路由、页面、测试和规范更新。写得简洁,但完整性优于简洁性。
规范中的视觉方向:要求将样式决策(颜色、排版)记录在规范中,而非仅留在聊天中。示例:AgentClinic品牌色——橙色和黑色,作为强调色使用,页面保持可读性。
重构代替修复:将工作从修复模式转移到功能模式的信号:多个相关bug、新模式、模块重写。正常流程,需要关闭修复分支并作为普通功能重新规划。
练习题目: 标题:干净启动准备检查
问题:你即将在AgentClinic项目中开始功能第二阶段「代理与疾病」。执行完整的干净启动检查清单并确定是否可以开始工作。初始数据:你位于 feature/first-phase 分支,git status 有3个未提交文件,测试因类型错误失败,specs/ 目录中有无日期的规范草稿。描述命令序列和准备就绪决策。
解答:1. git stash push -m 'WIP: first-phase' —— 保存未提交更改。2. git checkout main —— 切换到main分支。3. git pull --ff-only —— 无合并更新。4. git status --short —— 检查干净状态(应为空)。5. npm test —— 运行测试(预期:通过)。6. npm run typecheck —— 检查类型(预期:无错误)。7. 在Qwen Code中: /clear —— 清理上下文。8. 阅读 @specs/roadmap.md 并确定下一个未完成阶段。9. 确认无日期草稿不是活跃规范。决策:在main中的类型错误消除且规范草稿完成前,不能开始工作。如果main中存在类型错误——这是阻塞问题,需要单独的bugfix分支修复。
难度:中级
标题:规范访谈的制定
问题:你开始「代理与疾病」阶段。根据项目上下文制定规范访谈的三类问题:AgentClinic是面向AI代理的讽刺诊所,技术栈包括Hono、SQLite、服务器端渲染、Vitest,无客户端JavaScript。第一阶段实现了主页和反馈表单。路线图指出需要代理和疾病参考手册。
解答:第一组——边界:哪些领域实体属于本阶段?(代理、疾病、agent_ailments关联)。实现哪些页面?(列表 /agents、详情 /agents/:id、列表 /ailments)。明确排除什么?(预约挂号、创建/编辑表单、客户端JavaScript)。第二组——决策:使用什么数据库?(带better-sqlite3的SQLite)。如何组织迁移?(手动、可重复执行)。哪些初始数据?(虚构代理和疾病,带讽刺描述)。哪些测试?(Vitest路由测试、组件渲染)。哪些接口约定?(Hono路由、服务器端渲染组件、响应式设计)。第三组——上下文:内容语气?(讽刺性,但实现清晰)。哪些限制?(无客户端JS、响应式界面、页面可演示)。哪些风险?(变更量带来的认知负荷、边界泄漏到表单)。什么留在边界外?(认证、管理面板、搜索和过滤)。
难度:中级
标题:考虑认知负荷的任务分组
问题:你面前有「代理与疾病」阶段的15个任务。任务:安装better-sqlite3、数据库连接模块、迁移机制、agents表、ailments表、agent_ailments表、虚构代理、虚构疾病、代理与疾病关联、/agents页面、/agents/:id页面、/ailments页面、路由测试、组件测试、运行npm test和typecheck。为降低认知负荷进行最优分组并说明理由。
解答:第一组——数据库基础设施(任务1-3):安装better-sqlite3、连接模块、迁移机制。理由:模式工作的基础,无此前提无法工作。单独验证:连接正常、迁移幂等。第二组——领域模式(任务4-6):agents、ailments、agent_ailments三个表。理由:模式逻辑完整性一目了然,关联更易检查。第三组——初始数据(任务7-9):三个表的种子数据。理由:需要就绪的模式,为页面手动检查提供测试数据。第四组——路由和组件(任务10-12):三个页面。理由:可视化结果,可演示。认知负荷风险——此处可按单个页面拆分为子组。第五组——测试和验证(任务13-15):路由测试、组件测试、最终运行。理由:验证整个阶段,发现回归。每组单独提交,组间请求代理汇总变更。
难度:中级
标题:创建修复规范
问题:在「代理与疾病」阶段发现bug: /agents 页面按创建顺序(按ID)显示代理,但预期按名称字母排序。同时存在风险:「修复」可能影响已正确按疾病名称排序的 /ailments 页面。创建包含必需保护部分的bugfix.md。
解答:bugfix.md:当前行为—— /agents 页面按id升序(创建顺序)显示代理,导致演示时布局不可预测。预期行为——代理按name字段字母升序ASC排列,考虑西里尔字母(locale-aware排序)。根本原因证据—— src/routes/agents.ts 中查询 db.query('SELECT * FROM agents') 无ORDER BY,可在阶段提交中查看。不应更改的内容——GET /ailments路由及其按ailments name的排序、agents表中现有记录(无需迁移重新排序)、分页(尚未实现)、响应格式(HTML页面)。回归场景——GET /agents按字母顺序返回代理;GET /ailments保持其排序;agents的POST及其他方法不受影响;/agents测试验证顺序。
难度:中级
标题:阶段边界验证
问题:代理提议为「代理与疾病」阶段增加额外功能:按名称搜索代理的表单(客户端JavaScript)、编辑疾病的管理员页面、管理员页面的JWT认证。制定当前分支的审查请求并确定应拒绝哪些变更。
解答:审查请求: /clear. 根据 @specs/2026-05-02-agents-ailments/plan.md 和 @specs/2026-05-02-agents-ailments/validation.md 检查当前分支。重点关注:1. 超出阶段边界;2. 数据库迁移安全性;3. 测试覆盖缺口;4. 与 @specs/tech-stack.md 的矛盾(禁止客户端JavaScript)。不要修改文件。 应拒绝的变更:带客户端JavaScript的搜索表单——直接违反tech-stack.md(无客户端JS);管理员页面——超出阶段边界(只读,无表单);JWT认证——超出边界且不符合阶段(只读参考手册)。可接受的变更:如果搜索通过Hono服务端处理query参数 ?q= —— 可讨论,但更可能推迟到下一阶段,因为不在计划中。决策:拒绝所有三项提议,在规范中记录原因(超出边界/技术栈),可能创建 specs/backlog/search-agents.md 供未来阶段使用。
难度:高级
案例研究: 标题:AgentClinic:因跳过干净启动检查而导致第二阶段失败
场景:两人团队开发讽刺项目AgentClinic——面向AI代理的诊所。第一阶段(主页和反馈表单)在热情中成功完成。第二阶段「代理与疾病」应引入SQLite、三个表、三个页面、测试和导航。开发者A在周五晚上开始工作,跳过了 git status 检查。
挑战:开发者A从一个包含反馈表单未提交实验性更改(添加了 priority 字段,更改了验证)的提交开始分支。Qwen Code代理收到包含这些更改的上下文后,将其纳入第二阶段生成。会话结束时分支中有47个更改文件。尝试合并时发现:(1)反馈表单包含第一阶段规范未描述的priority字段;(2)数据库迁移与实验性模式冲突;(3)测试因更改交叉而失败;(4)开发者B无法进行审查——视线在47个文件上滑过,错误漏掉。
解决方案:团队应用紧急协议:1. 从干净main创建单独分支 emergency/clean-state。2. 通过三类问题访谈重新创建第二阶段规范。3. 实现拆分为5个任务组,严格限制:每组不超过7个任务,中间提交强制。4. 禁止20:00后与代理工作——认知负荷与疲劳不兼容。5. 每组后增加 /review 检查。6. 反馈表单的未完成更改作为单独功能记入待办事项。
结果:第二次尝试耗时3个工作日而非一个周五晚间会话,但结果是:(1)23个文件而非47个——可管理量;(2)所有测试通过;(3)合并无冲突;(4)审查耗时45分钟而非不可能;(5)在分组检查阶段而非合并后发现迁移中的2个错误。项目为第三阶段获得了稳定基础。
经验教训: 未完成更改是开始阶段的阻塞问题,不是形式问题。 git status --short 检查必须为零。
40+文件的认知负荷使审查物理上不可能。每组5-7个任务加中间提交——不是优化,而是必需。
时间段影响控制代理的能力。大型阶段工作需要清醒状态。
代理放大现有混乱,但不会自行创造秩序。干净启动是人的责任。
相关概念: 干净启动
认知负荷
任务组
规范访谈
标题:AgentClinic:成功应用修复规范进行表单验证
场景:合并第二阶段「代理与疾病」后,用户发现第一阶段的反馈表单允许空消息通过。服务器返回302并将空字符串保存到 feedback 表。团队决定不将修复与第三阶段混合,而是应用修复规范。
挑战:修复看似简单(添加验证),但存在风险:(1)代理可能「改进」表单相邻代码,破坏样式或逻辑;(2)响应从302改为400可能影响客户端处理(如有);(3)表中现有空记录需要决策;(4)400错误格式应与项目其他路由一致。
解决方案:创建分支 2026-05-12-feedback-empty-message-bug 并附修复规范:包含当前/预期行为、根本原因证据(提交3a7c1b9中延迟验证的TODO)、不应更改的内容(GET /feedback、现有记录、字段名、400格式)、回归场景的bugfix.md。plan.md包含两组:验证修复和回归测试。validation.md包含事实复现: npm test -- feedback 预期空message返回400。明确禁止代理更改页面样式、添加客户端验证、修改feedback表。
结果:修复耗时2小时而非潜在的数天调试副作用。回归测试捕获到代理试图更改 name 字段处理(设为必填)的尝试——作为超出边界拒绝。现有空记录保持不变(决策:数据清理作为单独任务,与bug无关)。400错误格式因明确规范而与 /agents 路由一致。
经验教训: 修复规范比快速修复成本高:30分钟编写节省数小时回归调试。
「不应更改的内容」部分是防止代理「改进」的主要保护工具。
validation.md中的事实复现提供不依赖人为评估的客观就绪标准。
修复发展为重构时应尽早承认并作为功能重新规划——这不是失败。
相关概念: 修复规范(bugfix.md)
回归场景
validation.md中的事实复现
重构代替修复
学习建议: 将干净启动作为仪式练习:每次与代理会话前执行完整命令集,即使「昨天一切正常」。通过shell别名自动化。
记录个人认知负荷日志:记录视线开始「滑过」的文件数量。个人阈值通常为15-25个文件——用作任务组上限。
在编辑器中创建规范模板:requirements.md、bugfix.md、plan.md、validation.md的代码片段。节省格式化时间以增加思考时间。
即使对于功能也练习制定「不应更改的内容」——这培养边界保护技能。
可视化使用Git: git log --graph --oneline --all 理解分支结构, git diff --stat 提交前评估变更量。
向代理请求前进行自我审查:大声朗读自己的规范——模糊之处将变得明显。
学习他人规范:分析课程示例,提取结构,与自身尝试比较。
练习拒绝:当代理提议「改进」时,按规范而非直觉说明拒绝理由——这强化纪律。
额外资源: Git分支文档:https://git-scm.com/book/ru/v2/Git-Branching-Основы-ветвления-и-слияния —— 理解干净启动和fast-forward的基础
better-sqlite3文档:https://github.com/WiseLibs/better-sqlite3/blob/master/docs/api.md —— Node.js中SQLite的API
hono文档:https://hono.dev/docs/getting-started/basic —— 项目中使用的Web框架
vitest文档:https://vitest.dev/guide/ —— 路由和组件的测试框架
数据库迁移指南:https://flywaydb.org/documentation/concepts/migrations.html —— 可重复迁移的概念
「规范驱动开发」课程:课程原始材料,第1-10部分——理解第一阶段背景和 methodology 演进
Git交互式训练器:https://learngitbranching.js.org/?locale=ru_RU —— 为干净启动准备的可视化分支学习
agentclinic项目规范模板:项目仓库中 specs/templates/ —— requirements.md、bugfix.md、plan.md、validation.md的现成模板
总结:功能第二阶段是开发过程可重复性的考试。它与第一阶段的关键区别在于管理认知负荷的严格要求:代理生成更多更改,而人必须保持控制。关键实践:作为不可跳过检查的干净启动、通过三类问题结构化访谈制定规范、带中间提交的任务分组、保护现有行为的修复规范、合并前边界验证。第二阶段的成功不以速度衡量,而以可预测性衡量:审查可行、测试通过、合并干净、变更日志最新。第二阶段失败通常是跳过干净启动或接受未验证更改的结果。SDD方法论在第二阶段从「做得漂亮」转变为「做得让第三阶段不因第二阶段后果而受苦」。