主题:第二部分。为什么基于规范的开发
难度级别:中级
预计学习时间:4-6小时(理论+实践)
先决条件: 基本理解AI助手的使用(Qwen、ChatGPT、Claude等)
版本控制系统(Git)的使用经验
Web开发基础知识(HTML、CSS、JavaScript/TypeScript)
软件架构基本概念的理解
命令行和npm脚本的使用经验
学习目标: 解释vibe-coding的五种典型故障及其通过SDD(Specification-Driven Development,规范驱动开发)消除的机制
为验证功能规范是否准备好实现,阐述七个检查问题的答案
为Qwen Code项目以requirements/plan/validation格式编写完整的功能微型规范
区分功能级别的SDD与经典的瀑布式设计模型
应用确定特定代码变更是否需要规范的实践规则
概述:本模块致力于在使用AI代理(特别是Qwen Code)工作时,从混乱的vibe-coding过渡到规范的规范驱动开发(SDD)。Vibe-coding是一种开发者向AI发出连续冲动指令的方法,失去架构上下文并积累技术债务。SDD通过创建可版本控制、可验证且代理可读的文档来解决这个问题,这些文档固定意图、边界、已做出的决策和验收标准。模块涵盖vibe-coding的典型病理、Qwen Code的稳定工作循环结构、规范质量的七个问题、SDD冗余标准和微型规范的编写实践。
关键概念: Vibe-coding(氛围编码):一种使用AI助手进行开发的方法,基于持续即兴创作:开发者在聊天中发出简短命令,代理立即执行,上下文仅存在于临时会话中。对原型设计和研究有用,但产生五种关键故障:意图偏移、上下文瓦解、不可验证的结果、隐藏决策、审查者疲劳。
SDD(规范驱动开发):一种开发方法论,其中AI代理不仅收到"做"的命令,还收到以可版本控制文件形式的结构化上下文:项目使命、技术栈、路线图、单个功能的规范。将知识从临时对话转移到仓库中,使错误变得早期、微小且可验证。
意图偏移:Vibe-coding的典型故障:代理将"简单表单"解释为添加复杂状态管理、新库、替代界面风格的理由——这些都是开发者没有要求但代理认为合理的内容。
上下文瓦解:代理工作会话之间架构决策的丢失。经过几次迭代后,代理忘记为什么项目不使用ORM,为什么API在服务器端渲染HTML,为什么选择了特定技术栈——并重新做出矛盾的决策。
Qwen Code的稳定工作循环:替代漫长即兴会话的方案:三个分离的阶段,强制清除上下文(/clear)。阶段1——阅读基础规范和创建功能计划,提出澄清问题。阶段2——按照具体计划严格实现有限子集的任务。阶段3——根据预先固定的标准验证结果,在修复前列出偏差。
功能微型规范:紧凑的文档(不是80页的瀑布文档),面向一个阶段、一个分支、一次合并。由三个文件组成:requirements.md(需求和边界)、plan.md(实现计划)、validation.md(验证标准)。特点:小型、可验证、与路线图关联、无需先前聊天即可被新代理理解、足够严格以排除猜测。
规范的七个问题:内容就绪性的检查清单:(1)功能背后的业务意图,(2)用户和场景,(3)工作边界,(4)已做出和未决的决策,(5)不可放宽的限制,(6)不应破坏的内容,(7)如何证明结果的正确性。缺少任何一个问题的答案意味着尚未准备好实现。
负面需求:固定功能不应触及的现有行为。对于防止代理倾向于广泛变更时的回归至关重要。在课程第7部分中更详细展开。
冗余实践规则:确定是否需要规范的启发式方法:如果变更在5分钟内可理解且可验证——普通请求足够;如果触及架构、数据、安全、公共行为或多个文件——需要规范;如果代理自主工作超过几分钟——规范几乎总是值得的。
边界与超出边界:功能规范中明确列出的包含项和明确排除项。防止工作范围蔓延(scope creep),不允许代理"补充"开发者未订购的功能。
练习: 标题:Vibe-coding故障诊断
问题:阅读以下场景并确定发生了五种典型vibe-coding故障中的哪一种:开发者要求代理"为商品添加评论"。代理创建了包含审核、通知、分析和外部服务集成的完整评级系统。开发者只想要商品卡片下方的文本评论显示。在下一个会话中,代理建议将现有的SQLite替换为PostgreSQL以实现"可扩展性"。开发者花费2小时回滚变更。
解答:步骤1:识别第一个故障——代理添加了不相关的功能(评级、审核、通知、分析、外部服务),而非请求的最小功能。这是经典的意图偏移:将"评论"解释为生态系统的理由。步骤2:识别第二个故障——在新会话中,代理不记得/不考虑关于SQLite的决策,建议PostgreSQL。这是上下文瓦解:存储栈的架构决策已丢失。步骤3:识别第三个故障——结果需要2小时回滚,说明变更在体量上不可验证,后果不可预测(不可验证的结果+审查者疲劳)。步骤4:提出SDD解决方案:创建specs/2026-05-08-reviews-display/requirements.md,明确边界("仅显示"、"无评级"、"本阶段无审核"),在tech-stack.md中固定SQLite决策,创建validation.md检查无新依赖项。
难度:中级
标题:编写管理员登录微型规范
问题:从课程示例中选取"添加登录"功能。将冲动请求转换为包含三个文件的完整微型规范:requirements.md、plan.md、validation.md。使用七个问题作为内容检查。然后提出三个你会在实现开始前向代理提出的澄清问题。
解答:步骤1:requirements.md——结构:# 需求——管理员登录;## 边界(一个登录页面、cookie会话、无自助注册、本阶段无密码重置);## 超出边界(OAuth、JWT、用户注册、密码重置、多因素认证);## 决策(SQLite中一个管理员、httpOnly cookie、仅保护/dashboard);## 验证(测试场景)。步骤2:plan.md——分解为任务组:(1)数据模式和用户模型,(2)/login和/dashboard路由及中间件,(3)表单和验证,(4)测试。步骤3:validation.md——具体检查:未认证GET /dashboard → 302到/login;错误密码 → 通用错误消息,不泄露用户存在;正确密码 → httpOnly cookie + 302到/dashboard;npm test和npm run typecheck通过;除bcrypt和cookie-parser外无新依赖。步骤4:按七个问题检查:(1)意图——限制访问管理面板,(2)用户——唯一管理员,(3)边界——明确列出,(4)决策——SQLite、cookie、bcrypt已固定,(5)限制——httpOnly、仅保护/dashboard,(6)负面需求——不破坏公共页面,(7)证明——4个测试场景+CI检查。步骤5:向代理提出的澄清问题:"确认你理解:本阶段无密码重置意味着无/forgot-password路由且无邮件服务集成";"如果你认为bcrypt对SQLite不够优化,请提出替代方案并说明理由";"你将如何检查cookie确实是httpOnly且无法从document.cookie访问?"
难度:中级
标题:为功能设计稳定循环
问题:你有一个Next.js博客项目,路线图如下:阶段1——基础文章,阶段2——评论,阶段3——标签和搜索。你想实现阶段2(评论)。设计三个使用/clear的Qwen Code会话,指出代理在每个会话中阅读哪些规范文件,以及收到哪些具体指令。论证分为三个会话的理由。
解答:步骤1:会话"研究和规划"——/clear;阅读@specs/mission.md(项目目标:专注于可读性的极简博客),@specs/tech-stack.md(Next.js 14 App Router、Prisma + PostgreSQL、Tailwind、默认React Server Components),@specs/roadmap.md(阶段1已完成,阶段2——评论,阶段3——标签)。指令:"为路线图阶段2创建功能规范。先向我提出关于不明确之处的问题。不要写代码。"论证:代理需要理解项目上下文,不与先前会话混合,并在实现前表述歧义。步骤2:会话"实现"——/clear;阅读@specs/mission.md、@specs/tech-stack.md、@specs/2026-05-15-comments/plan.md(会话1创建)。指令:"仅实现计划中的任务组1和2:Prisma评论模式和API路由POST /api/posts/[id]/comments。不要更改不相关文件。本会话不添加UI。"论证:限制工作量防止意图偏移,明确边界防止蔓延。步骤3:会话"验证"——/clear;阅读@specs/2026-05-15-comments/validation.md。指令:"将当前实现与validation.md比较。修复前先列出偏差。然后提出最小修改。"论证:单独的验证会话防止冲动修复,强制明确承认问题,通过结构化协议保护审查者免受疲劳。
难度:高级
标题:应用冗余实践规则
问题:根据实践规则评估以下每个变更是否需要完整规范(requirements/plan/validation):(A)修复主页标题中的拼写错误;(B)在用户资料中添加"个人简介"字段,验证长度500字符;(C)从SQLite迁移到PostgreSQL以支持并发写入;(D)创建一次性内部使用数据迁移脚本;(E)实现Stripe支付集成用于订阅。
解答:步骤1:(A)拼写错误修复——单个文件变更,30秒内可理解,视觉上可验证。实践规则:<5分钟,一次性,不触及架构。结论:普通请求,无需规范。步骤2:(B)个人简介字段——触及数据模式、验证、表单、API、可能需要测试。但变更本地化、模板化,代理工作<<5分钟。边界明显。结论:聊天中带有上下文的轻量请求可能足够,但requirements.md中的最小固定可提高可靠性。边缘案例——可以无需完整循环。步骤3:(C)SQLite→PostgreSQL迁移——架构决策,触及数据、配置、可能ORM查询、测试、CI/CD。代理将长时间工作,错误代价高昂。结论:完整规范,包含明确决策、负面需求(不破坏的内容)、迁移计划、验证。步骤4:(D)一次性迁移脚本——内部使用、一次性、按结果验证。但如果代理自主工作且触及生产数据,风险高。结论:如果脚本简单且数据不关键——轻量请求;如果逻辑复杂或生产环境——带数据副本检查的最小规范。步骤5:(E)Stripe支付集成——安全、公共行为、外部服务、用户资金、错误的法律后果。结论:强制完整规范,包含明确边界(哪些支付、哪些货币、哪些webhook)、固定决策(Stripe SDK vs API、错误处理)、不可放宽限制(PCI合规、幂等键)、负面需求(不存储CVV、不同步处理支付)、详细验证。
难度:中级
案例研究: 标题:初创公司从Vibe-coding迁移到SDD:通过规范拯救项目
场景:一家教育科技初创公司使用Claude和GitHub Copilot以vibe-coding模式开发在线课程平台。4个月内,2人开发团队创建了可用的MVP:认证、视频播放器、学习进度、支付。项目冲动式增长:每个功能都按"做X"的请求添加,架构决策由代理即时做出,无文档记录。
挑战:第5个月,团队遇到关键问题:(1)意图偏移——支付系统包含3种不同方法(Stripe Checkout、Stripe Elements、自写表单),因为不同会话中代理选择了不同方案;(2)上下文瓦解——新开发者无法理解为什么视频播放器使用自定义进度存储格式而非标准格式;(3)不可验证的结果——发布包含47个变更文件,审查耗时6小时,错误渗入生产环境;(4)隐藏决策——关于数据库分片的关键决策仅存在于离职开发者的聊天历史中;(5)审查者疲劳——CTO因无法保证质量而停止夜间发布。
解决方案:团队在3周内实施SDD:(1)回顾——从聊天历史中提取隐藏决策,固定到specs/mission.md、specs/tech-stack.md、specs/architecture-decisions/;(2)路线图——将剩余功能分解为带明确边界的阶段;(3)微型规范——每个功能获得requirements/plan/validation,按七个问题验证;(4)稳定循环——会话间实施/clear,分离规划/实现/验证;(5)验证自动化——npm脚本和GitHub Actions强制在合并前通过validation.md。
结果:2个月后:审查时间从6小时缩短到45分钟;发布bug数量下降70%;新开发者3天融入项目而非3周;多亏负面需求,能够在无回归的情况下移除3种支付系统中的2种。CTO恢复夜间发布并有信心。项目获得A轮融资。
经验教训: Vibe-coding有隐藏成本:节省的每一分钟规范时间,在3-6个月后会变成数小时的审查和回滚
规范的七个问题作为早期歧义检测器:如果代理在验证requirements.md时提出意外问题,说明规范尚未准备好
使用/clear的会话分离对防止上下文混合至关重要:即使"智能"代理,当规划、实现和bug修复混合在一个会话中时,也会混淆优先级
负面需求是最被低估的组件:明确指定"不做什么"比列举"做什么"更能防止范围蔓延
SDD的回报不是即时的,而是通过可版本控制上下文的积累:收益随团队规模和项目年龄呈指数增长
相关概念: Vibe-coding(氛围编码)
规范的七个问题
Qwen Code的稳定工作循环
负面需求
冗余实践规则
标题:OAuth集成失败:当"添加登录"比规范更昂贵时
场景:独立开发者正在为自由职业者创建SaaS——时间追踪与发票系统。在准备公开发布时,需要认证。开发者向Claude发出冲动请求:"添加Google登录"。
挑战:代理实现了完整的Google OAuth 2.0集成,包括:通过Google注册新用户、关联现有账户、令牌刷新、访问Google Calendar导入事件、带Google头像的个人资料。问题:(1)开发者只想要认证,不要Calendar数据授权;(2)账户关联产生漏洞:如果用户B之前用密码登录,用户A可以关联用户B的邮箱;(3)令牌刷新需要未在基础设施中记录的cron任务;(4)通过Google注册绕过了发票所需的关键必填字段"时区";(5)回滚耗时8小时,包括从备份恢复数据库。
解决方案:事件后,开发者应用SDD方法:创建specs/auth/requirements.md,包含边界(仅认证、不访问Google数据、本阶段无自助注册),固定首版中邮箱密码优先于OAuth的决策,描述负面需求(不破坏现有用户、OAuth登录不要求时区)。计划包含2个任务组而非8个,验证包含5项具体检查,包括检查Google Console中无新scopes。
结果:重新实现耗时2小时,而非8小时回滚+不确定的修复时间。规范在编码前防止了5个问题中的3个(Calendar访问、账户关联、时区要求)。剩余2个问题在验证阶段15分钟内捕获。开发者估计编写规范耗时25分钟——相对于回滚节省12倍。
经验教训: 冲动请求"添加X"仅在当下便宜:完整成本包括回滚、修复、数据恢复和声誉损失
代理倾向于"有用"的扩展,而开发者并未订购:OAuth自然带动个人资料、集成、同步
25分钟写规范——在第一次严重故障时ROI>1000%的投资
"不访问Google数据"形式的负面需求比"仅认证"更具体、更可验证
通过与预先固定列表比较实现进行验证,可防止审查者疲劳时的"看起来正常"
相关概念: 意图偏移
边界与超出边界
冗余实践规则
规范的七个问题
功能微型规范
学习建议: 按顺序学习材料:先通过自身经验或案例意识到vibe-coding的问题,然后将SDD作为系统解决方案而非官僚主义来学习
记录"vibe-coding日记"——一周内记录你对AI的冲动请求,然后分析:哪些导致回滚?哪些本可在10分钟内形式化?
在真实或虚构功能上练习七个问题:从你当前项目中选取任何功能,检查能否在5分钟内回答全部七个问题。如果不能——需要规范
使用"红队"技术:编写规范后,请代理或同事找出实现可能偏离的歧义。这训练批判性思维
在编辑器或片段中创建三个规范文件的模板:requirements.md、plan.md、validation.md。自动化创建降低SDD入门门槛
实际练习会话分离:关闭聊天,用/clear打开新聊天,即使"继续"看起来更有效。衡量结果质量差异
单独学习负面需求:这是最反直觉的部分,需要习惯于思考"我不想要什么"而非"我想要什么"
积极将SDD与瀑布比较:瀑布试图预测未来,SDD为下一步固定足够上下文。这是不同逻辑,而非不同规模
衡量指标:审查时间、发布中的bug数量、新开发者入职时间。SDD由指标证明,而非直觉
从一个功能开始:不要试图立即覆盖整个项目规范。选择下一个非平凡功能,完成完整循环,衡量结果,然后扩展
额外资源: SDD原始课程:提取本部分内容的课程材料——深入AI代理上下文相关开发的基础
Qwen Code文档:关于上下文工作、/clear命令、@-文件引用的官方材料——稳定循环的技术基础
Kamil Nicieja《Writing Great Specifications》:经典意义上的规范书籍,经规模调整后适用于AI代理
ADR(Architecture Decision Records,架构决策记录):固定架构决策的格式——补充SDD项目级别,防止功能间上下文瓦解
Atul Gawande《The Checklist Manifesto》:关于复杂系统中清单力量的书籍——规范的七个问题作为质量清单
开源项目规范示例:研究团队如何在RFC(Request for Comments)中固定功能边界——与SDD微型规范的平行对照
API设计课程(API Design Patterns):帮助在规范中制定不可放宽限制,尤其适用于带外部接口的功能
总结:规范驱动开发(SDD)是对vibe-coding根本限制的回应:上下文的短暂性。AI代理快速编写代码,但没有关于意图、边界和已做决策的持久记忆。SDD将此上下文转移到可版本控制的文件中,为代理创建项目的"地图"。关键实践:带/clear和分离规划/实现/验证会话的稳定循环;功能微型规范替代单体设计;七个问题作为就绪性检查;明确边界和负面需求防止蔓延;冗余实践规则节省精力。SDD不使代理无错误——它使错误变得早期、微小且可验证。实施需要纪律,但随项目和团队增长呈指数回报。