阅读材料: 第20部分。SDD反模式

模块「第20部分。SDD反模式」中第 1 / 5 节课
您正在未登录状态下查看课程。 请登录,以保存进度并参加测试。

第20部分:SDD反模式

反模式是一种看起来像正确流程的习惯,但会破坏结果。在SDD中,这类错误尤其危险:文件存在,检查存在,代理运行迅速,但人逐渐失去控制。

这部分作为诊断地图。如果流程变得沉重、嘈杂或无用,从这里开始。

代码后写规范

症状:代理先实现功能,然后编写requirements.mdplan.mdvalidation.md来匹配已完成的代码。

为什么不好:规范不再指导工作,变成了报告。在这种模式下,它无法防止代理做出多余决策。

如何修复:

  • 在实现前至少提交规范草稿;
  • 禁止代理在创建规范的会话中编写产品代码;
  • 在合并请求中明确展示规范提交在实现提交之前。

巨型requirements.md

症状:一个需求文件包含数十个要点、多个场景、未来阶段和有争议的决策。

为什么不好:代理开始选择什么是重要的。人也同样看不到边界。

如何修复:

  • 将功能拆分为阶段;
  • 将未来想法移到roadmap.md
  • requirements.md中只保留当前分支需要的内容;
  • 将有争议的决策标记为问题,而非需求。

从未运行过的validation.md

症状:检查中有漂亮的事实,但没有执行过的痕迹。

为什么不好:这种文件制造虚假的完备感。它看起来很严格,但不能让分支进入合并。

如何修复:

  • 在每个强制性事实旁边存储命令或手动场景;
  • 在代理报告中要求列出通过、失败和未验证的事实;
  • 如果无法重现,就不认为事实已确认。

出错后弱化事实

症状:测试失败后,代理修改validation.md中的预期结果,而不是修改代码。

为什么不好:流程开始保护代理的实现,而非产品的意图。

如何修复:

  • 要求代理先展示差异,不做修改;
  • 特别仔细地审查validation.md的修改;
  • 在规范或合并请求中保存修改事实的原因;
  • 禁止未经人工决策删除强制性事实。

仪式性的/clear

症状:在阶段之间调用/clear,但之后代理仍然从聊天中获得长篇解释。

为什么不好:该命令制造了可移植性检查的假象。实际上流程仍然依赖人的记忆。

如何修复:

  • /clear后只给代理文件链接;
  • 检查新会话是否能从仓库理解下一个任务;
  • 如果不能,补充规范,而不是扩展提示词。

技能作为魔法按钮

症状:团队调用Qwen Code技能,但没人阅读SKILL.md,也不理解它做了什么决策。

为什么不好:技能变成隐藏流程。出故障时人们不知道要修什么。

如何修复:

  • 将项目技能存储在仓库中;
  • 像审查流程代码一样审查SKILL.md
  • 在技能中不仅写命令,还要写限制;
  • 在手动流程重复2-3次之前不要创建技能。

QWEN.md作为垃圾堆

症状:在QWEN.md中堆放产品需求、技术栈、个人偏好、临时任务和错误笔记。

为什么不好:代理无法区分永久规则和临时上下文。

如何修复:

  • 将产品决策存储在specs/中;
  • 将代理行为规则存储在QWEN.md中;
  • 将临时结论移到记忆或回顾中;
  • 定期删除过时的规则。

静默修改项目的钩子

症状:钩子格式化、重写或删除文件,而计划中没有明确步骤。

为什么不好:部分变更出现在代理和人控制之外。之后很难理解是谁改变了行为。

如何修复:

  • 钩子默认应该检查或记录,而不是修改文件;
  • 只允许自动格式化作为明确的命令规则;
  • 所有文件修改都应进入普通的git diff
  • 钩子阻止时应解释原因。

记忆作为隐藏的真相来源

症状:代理基于记忆做决策,但这些决策不在specs/QWEN.mdAGENTS.md中。

为什么不好:新团队成员看不到决策依据。另一个代理也可能得不到它。

如何修复:

  • 将记忆视为提示,而非规则;
  • 将重复出现的结论移到可审查的文件中;
  • 删除过时的记忆;
  • 记忆与规范冲突时,选择规范。

无任务的MCP

症状:为项目连接多个MCP服务器"以备将来"。

为什么不好:代理获得多余权限和更多出错方式。团队不再理解哪些外部操作是可能的。

如何修复:

  • 只为特定场景连接MCP;
  • 限制工具列表;
  • 将配置存储在可审查的位置;
  • 测试后关闭实验性服务器。

过大的MVP

症状:第一个工作版本包含认证、角色、分析、精美界面、迁移、数据导入和集成。

为什么不好:代理快速创建大量文件,但人来不及理解决策质量。

如何修复:

  • 第一阶段应证明一个风险;
  • 用时间限制工作;
  • 如果分支膨胀,回退到最后一个绿色状态;
  • 只有在已有可验证事实后才添加功能。

代理代码中的幻觉

症状:代理自信地引用不存在的函数、方法或包。导入指向不存在的模块;调用使用仅在下个主版本才出现的API;package.json中添加了注册表中不存在的依赖,或名称与知名包几乎相同(例如requests-py而非requests)。

为什么不好:幻觉导入如果代理自己补充了存根,可能在类型检查阶段不报错。不存在的包名尤其危险:攻击者可能提前在注册表中注册此类名称(slopsquatting攻击),npm install会静默拉取恶意代码。

如何修复:

  • tech-stack.md中维护允许的依赖列表;
  • 任何依赖添加都是独立的审查步骤,而非"实现功能"的一部分;
  • 首次出现类型或运行时错误时,将包版本与package.json核对;
  • npm install前肉眼检查包名;与常用名相差一个字母的名称是停止信号;
  • 如果代理引用代码中之前没有的函数,要求给出链接:"展示定义或说明它应该出现在哪里"。

测试的幻觉

症状:npm test是绿色的,但bug仍然存在。测试存在,但它们没有检查声称的内容。

典型变体:

  • 同义反复测试:测试将函数结果与函数中相同的表达式比较——重命名变量会破坏一切,但逻辑从未被检查;
  • 镜像测试:测试检查函数返回了它返回的内容,没有独立预期值;
  • 快照欺骗:首次运行创建快照,第二次与自身比较;错误被固定在快照中并被当作"正确";
  • 无论如何都不失败的测试:唯一断言是函数没有抛出异常。

为什么不好:绿色测试集不再代表完备性。规范形式上完成("覆盖率90%"),但没有任何真正保证。

如何修复:

  • validation.md中要求事实重现:修复前失败、修复后通过的命令(尤其针对bug修复,见第11部分);
  • 审查时阅读测试本身,而非仅看覆盖率数字;
  • 对关键位置应用变异测试(Vitest可用Stryker):服务在代码中做微小修改,检查测试是否发现。如果没发现任何变异,测试什么都没检查;
  • 禁止业务逻辑使用快照;快照仅允许用于结果为人类可读渲染的场景。

开发者不理解自己的PR

症状:作者打开合并请求,但无法解释为什么采用特定方案;面对审查者的问题,他再次询问代理并转发回答。

为什么不好:代码责任被稀释。半年后团队中没人能说明为什么这里是这种错误处理,这是否是有意识的选择。如果作者不理解自己的PR,审查者无法依赖其判断,未来读者将在假设中迷失。

如何修复:

  • 制定规则:PR作者必须在描述中用自己的话一段解释做了什么和为什么(见附录C模板);
  • 审查者至少问一个只有人才能回答的问题("为什么这里数据库读取在事务外?");如果作者不回答或回答引用聊天记录,PR退回修改;
  • 在团队中鼓励"结对SDD"模式:一人写规范,另一人在实现前审查(第22部分,结对评分);
  • 对自己——合并后重读git diff并大声表述:"我做了X,因为Y"。如果解释不了,下个功能要求代理不仅提供代码,还要在PR评论中提供解释。

诊断检查清单

如果SDD不再有帮助,回答:

  1. 是否有规范写在代码之后的功能?
  2. 能否不借助聊天历史执行validation.md中的事实?
  3. 是否清楚哪些规则在QWEN.md中,哪些在specs/中?
  4. 是否有无明确步骤就修改文件的钩子?
  5. 是否有无当前任务的MCP服务器?
  6. 是否有仅存在于代理记忆中的决策?
  7. 新代理/clear后能否根据文件继续工作?
  8. 能否在一分钟内解释项目的当前阶段?

如果三个问题回答为否,不要添加新工具。简化流程。

相关部分

  • 第16部分——从审查者角度看同样的错误:如何在他人拉取请求中捕捉反模式。
  • 第18部分——同时是安全威胁的反模式(规范中的秘密、无审查的MCP、弱化validation.md)。
  • 第9部分——"功能类型→事实级别"矩阵,直接治疗"弱化validation.md"反模式。
我的笔记
0 / 10000

笔记保存在当前浏览器中。在其他设备上将不会显示。

课程菜单

课程

基于 Qwen Code CLI 的规范驱动开发
进度 0 / 135