PDPI Spec:规格驱动开发如何提升AI时代软件工程效率
1. 项目概述从“感觉对了”到“规格对了”在软件开发的江湖里我们这行干久了总会遇到一个经典的困境项目初期大家一拍脑袋觉得“这个功能很简单”然后一头扎进代码里。几周后需求改了架构推翻了代码成了一团乱麻最后要么是“屎山”拔地而起要么是项目延期、团队士气低落。这种“先开枪后瞄准”的开发模式我称之为“感觉对了”式开发它依赖的是开发者的个人经验和临场发挥充满了不确定性。今天要聊的PDPI Spec或者说规格驱动开发就是对这个困境的一次系统性反击。它的核心思想极其朴素甚至有点“反直觉”在写第一行代码之前先把所有事情想清楚、写下来、并获得共识。这听起来像是老生常谈的“设计先行”但PDPI把它变成了一套可执行、可验证、并且能与现代AI开发工具如Cursor、Claude Code、Qwen Coder等深度结合的严格协议。简单来说PDPI Spec定义了一个五阶段的开发流水线准备工作 - 需求定义 - 系统设计 - 实施计划 - 代码实现。每个阶段都有明确的输入、输出、交付物和“角色扮演”规则。最有趣的是它强制要求你或者你的AI助手在进入“实现”阶段前必须依次完成并“签核”前四个阶段的文档。这就像盖房子必须先有蓝图和施工图而不是直接让工人去搬砖。这套方法特别适合当前“AI结对编程”成为标配的时代。当你让Claude或Cursor帮你写一个复杂功能时如果只是口头描述AI很容易误解你的意图写出南辕北辙的代码。但如果你先和AI一起按照PDPI的模板产出结构化的需求、设计和计划文档那么AI在实现时就有了精确的“施工图纸”出错率会大大降低代码质量也更有保障。这本质上是一种“用规格来对齐人机认知”的工程实践。2. 核心理念与价值为什么“慢”反而更快PDPI的格言是“慢即是稳稳即是快”。这八个字道尽了软件工程管理的精髓。很多团队追求“敏捷”却误解为“快速响应变化”等于“跳过设计”。结果往往是局部快了整体慢了开头快了结尾慢了。2.1 对抗“Vibe Coding”与认知负债近年来随着Copilot等工具的普及出现了一种被称为“Vibe Coding”的模式开发者有一个模糊的想法就开始写代码依靠AI的实时补全和提示来探索和塑造最终方案。这在小规模、探索性任务中很高效但在严肃的项目开发中风险极高。它会导致架构漂移代码结构随着每次AI提示而微调最终变成一个没有统一设计的“缝合怪”。上下文丢失为什么这里要用这个库那个参数为什么是5几周后没人记得包括AI。返工成本高昂当发现底层设计有问题时大量已写好的代码都需要重写。PDPI通过强制性的文档阶段将“Vibe”固化为“Spec”。每一次决策的理由、权衡的考量、接口的定义都被白纸黑字地记录下来形成了项目的“认知资产负债表”。这极大地降低了项目后期的“认知负债”——即为了理解“为什么代码长这样”而付出的额外脑力成本。2.2 为AI协作提供确定性上下文当你对AI说“帮我实现一个用户登录功能”时这背后有无数种可能是JWT还是Session密码加密算法用bcrypt还是Argon2错误信息如何返回AI会基于它的训练数据“猜”一个最常见的实现但这不一定是你的项目需要的。PDPI的STATUS.json文件和分阶段文档为AI提供了确定性的、结构化的上下文。AI在扮演“实现专员”角色时不需要去猜只需要严格遵循plan.md里原子化的步骤。这就像给AI一本详细的菜谱它只需要按步骤炒菜而不需要发明一道新菜。这种约束反而解放了生产力让AI的输出变得高度可预测和可集成。2.3 建立质量内建的安全网每个PDPI阶段后都有一个对应的*-QA.md检查清单。这不是事后补救而是质量内建。在进入设计前用需求QA清单检查用户故事是否覆盖了所有场景和异常流。在进入计划前用设计QA清单检查架构图是否清晰、接口是否完备。这相当于在流水线的每个环节都设置了质量闸门防止缺陷流入下一个环节。在软件开发中越早发现的缺陷修复成本越低。PDPI通过流程强制把缺陷发现的时间点尽可能地提前了。3. PDPI流水线深度拆解从侦探到工匠PDPI的五个阶段不仅仅是五个步骤更是五种完全不同的思维模式和“角色”。要求开发者或AI在相应阶段进行“角色扮演”能有效地切换心智模型避免思维惯性带来的盲点。3.1 第0阶段准备工作 - 扮演“上下文侦探”这个阶段常被忽略但却至关重要。它的目标是理解你将要修改的“战场”——现有的代码库。核心产出物上下文工件这通常不是一个正式的文档而是一份探索笔记应包含项目DNA分析技术栈框架、语言版本、构建工具、代码风格约定、现有的设计模式是MVC、Clean Architecture还是别的。依赖追踪你要修改的模块其上游依赖谁调用它和下游依赖它调用谁是什么修改它会像推倒多米诺骨牌一样产生连锁反应吗“地雷”地图代码库中已知的复杂、脆弱或历史遗留的“坑”在哪里避免踩雷。实操心得在这个阶段我习惯用grep、find命令和IDE的全局搜索快速绘制一张模块关系图。对于AI可以指示它“请分析src/services/目录下所有与auth相关的文件总结当前的认证流程和外部依赖。” 这能帮助AI建立准确的初始认知。3.2 第1阶段需求定义 - 扮演“技术产品经理”这里要彻底搞清楚“为什么”要做和“做什么”。PDPI推荐使用Jobs to be Done和Gherkin风格用户故事。JTBD不要只关注功能“用户需要登录按钮”要关注用户背后的目标“作为一个访客我想安全地验证身份以便访问我的个人数据”。JTBD能帮你抓住本质需求避免过度设计。Gherkin用户故事这是一种Given-When-Then的格式强制你从用户视角定义可执行、可测试的验收标准。功能用户登录 场景使用正确密码登录成功 假设 用户“testexample.com”已注册且密码为“123456” 当 我在登录页面输入邮箱“testexample.com”和密码“123456” 并 点击“登录”按钮 那么 我应该被重定向到仪表盘页面 并且 页面顶部应显示“欢迎回来test” 场景使用错误密码登录失败 ...产出物requirements.md这份文档是所有后续工作的基石。它必须清晰、无歧义、且获得所有干系人包括你自己和未来的AI的认可。注意事项需求阶段最忌讳两件事一是过于技术化开始讨论数据库选型二是过于模糊“让用户体验更好”。坚持用业务语言和用户视角描述。一个检验标准是把这个文档给一个不懂技术的产品经理看他是否能完全理解3.3 第2阶段系统设计 - 扮演“首席软件架构师”这是将“做什么”转化为“怎么做”的蓝图绘制阶段。重点在于接口、数据流和权衡。核心产出物design.md这份文档应该包含架构图使用Mermaid等文本图表工具绘制组件关系图、数据流图。这比文字描述直观十倍。接口定义每个模块对外的API函数签名、REST端点、GraphQL Schema是什么输入输出是什么数据模型数据库表结构、关键实体关系、缓存数据结构。关键技术选型与权衡为什么选择A方案而不是B考虑了性能、可维护性、团队熟悉度等哪些因素例如设计一个文件上传服务时需要明确API端点POST /api/v1/upload支持multipart/form-data。流程客户端上传 - 网关校验 - 服务端接收 - 病毒扫描 - 转存至对象存储S3/MinIO- 记录元信息到DB - 返回文件URL。权衡为什么选择MinIO而不是直接存本地磁盘因为需要高可用和扩展性且与现有云环境兼容。实操心得设计文档不是一次性艺术品而是一个活的决策记录。我会专门用一个章节叫“决策日志”记录所有重要的技术决策及其理由。这在后期复盘或新人接手时价值连城。同时设计必须对照需求文档确保每一个需求都有对应的设计项去实现避免遗漏。3.4 第3阶段实施计划 - 扮演“高级工程经理”设计是蓝图计划就是施工图。这个阶段的目标是把宏观的设计拆解成微观的、原子化的、可验证的任务步骤。核心产出物plan.md一个好的计划应该像一份IKEA家具安装说明书步骤原子化每个步骤都应该足够小小到可以在一个工作会话比如2-4小时内完成并且产出明确如“创建User模型类并定义字段”。可验证每个步骤完成后如何验证它是对的是跑通一个测试还是启动服务不报错计划里要写明验收方式。顺序依赖明确步骤之间的前后关系。哪些可以并行哪些必须串行资源标注某些步骤可能需要特定的知识如“配置OAuth2需要了解RFC 6749”或外部资源如“申请第三方API密钥”。一个计划片段示例## 阶段1搭建数据层 1. 【步骤1.1】在src/models/目录下创建user.model.js文件。 * 动作使用Sequelize定义User模型包含id, email, passwordHash, createdAt字段。 * 验证编写并运行一个简单的测试脚本能成功连接数据库并同步此模型无报错。 2. 【步骤1.2】创建用户数据访问层DAOsrc/repositories/user.repository.js。 * 动作实现createUser, findUserByEmail, updateUser等基础CRUD方法。 * 验证为每个DAO方法编写单元测试使用Jest并全部通过。常见问题计划过于粗糙比如“实现后端API”。这等于没计划。必须拆解到“创建路由文件 - 实现控制器函数 - 连接服务层 - 编写集成测试”这样的粒度。另一个问题是忽略“非编码任务”如“更新API文档”、“修改部署配置”这些都应列入计划。3.5 第4阶段代码实现 - 扮演“初级开发/实现专员”这是执行阶段但绝非无脑敲代码。PDPI强调严格遵循计划和测试驱动开发。严格遵循计划打开plan.md找到当前步骤只做这一步要求的事情。不要即兴发挥增加“顺手”做的功能。如果发现计划有误或遗漏先暂停编码回去更新plan.md和design.md然后再继续。这保持了变更的追溯性。测试驱动开发对于每个原子步骤尤其是业务逻辑部分先写测试再写实现。这能确保代码严格满足需求定义中的场景并且设计是可测试的。AI在此阶段的角色此时AI是最佳的执行者。你可以将plan.md中的具体步骤直接交给AI如Cursor的Chat或Claude并附上相关的design.md和requirements.md片段作为上下文。指令会变得非常精确“请根据design.md中3.2节的接口定义实现plan.md中步骤2.3的UserService.validatePassword方法需包含针对空密码和密码长度不足的异常处理并遵循项目现有的Jest测试规范。”踩坑实录我曾有一次在实现时“灵光一现”觉得计划里的方案不够优雅擅自改用了一个更“巧妙”的设计。结果这个改动引发了意想不到的副作用导致后续三个关联步骤全部需要重做浪费了一天时间。教训是在实现阶段创造力应体现在如何更好地完成计划任务而不是修改任务本身。任何对设计的改进都应先反馈到设计阶段。4. 核心工具与工作流让规格驱动落地一套好的方法论离不开与之匹配的工具链。PDPI Spec本身是语言和框架无关的但它与现代化开发工具的结合能产生巨大威力。4.1 目录结构与状态管理PDPI推荐的目录结构非常清晰将协议规则与项目规格分离.spec-rules/ # 存放“宪法”所有项目通用 specs/ # 存放“法律条文”即每个具体模块的规格 └── user-authentication/ # 一个功能模块 ├── STATUS.json # 状态核心 ├── PREWORK.md ├── requirements.md ├── design.md └── plan.mdSTATUS.json项目状态的唯一真理源这是PDPI流程的“大脑”。它不是一个手动维护的文件而应由AI在流程驱动下自动更新。一个典型的结构如下{ module: user-authentication, currentPhase: PLAN, // 当前所处阶段 phaseHistory: [ { phase: PREWORK, completedAt: 2023-10-27T10:00:00Z, artifact: PREWORK.md }, { phase: REQUIREMENTS, completedAt: 2023-10-27T14:30:00Z, artifact: requirements.md, approvedBy: human }, { phase: DESIGN, completedAt: 2023-10-28T11:15:00Z, artifact: design.md, approvedBy: human } ], currentPlanStep: 2, // 当前正在执行的计划步骤索引 blockers: [], // 当前遇到的阻碍 repositoryContext: { // 自动记录的代码库上下文快照 relevantFiles: [src/models/user.js, src/routes/auth.js], gitBranch: feat/user-auth } }AI在每次会话开始时读取此文件就知道“我现在在哪我该做什么”。完成一个阶段或步骤后AI必须更新此文件。这解决了AI对话的“失忆”问题实现了跨会话的持久化上下文。4.2 与AI智能体的协作协议这才是PDPI最精妙的部分。它定义了你和AI如Claude、Cursor之间的“协作契约”。规则内化将.spec-rules/目录下的规则文件提供给AI作为系统提示词的一部分。例如你可以对Claude说“你现在的角色是SDD编排者。请首先读取specs/user-auth/STATUS.json了解当前状态然后遵循.spec-rules/中对应阶段的规则与我协作。”角色强制AI会“扮演”当前阶段要求的角色。在需求阶段它会像一个严谨的产品经理一样追问场景和边界条件拒绝讨论技术细节。在设计阶段它会像一个架构师一样思考扩展性和权衡。这避免了AI“角色错乱”比如在讨论需求时突然开始写代码片段。流程把关当STATUS.json显示currentPhase为DESIGN时如果你直接要求AI“开始写登录API的代码”一个遵循PDPI规则的AI应该拒绝你并提醒“根据SDD协议我们当前处于设计阶段。在开始实现之前需要先完成并批准design.md和后续的plan.md。让我们先聚焦于完成当前的架构设计吧。”4.3 模板与检查清单的使用.spec-rules/templates/目录下的模板不是摆设是生产力工具。它们提供了每个阶段文档的标准结构确保信息的完整性和一致性。更重要的是*-QA.md检查清单。它们是你每个阶段结束前的“质量门禁”。例如在完成design.md后不是直接进入计划阶段而是必须拿着design-qa.md清单逐项打钩[ ] 架构图是否清晰展示了所有组件及其交互[ ] 所有外部依赖第三方API、数据库是否都已明确[ ] 接口的输入输出是否考虑了所有错误情况[ ] 数据模型是否满足了所有查询需求[ ] 是否记录了关键的技术选型理由这个过程最好由另一个人或另一个AI会话来执行进行交叉审查。自己检查自己的设计很容易陷入思维盲区。5. 实战案例开发一个用户评论模块让我们通过一个简化但完整的例子看看PDPI如何在实际中运转。假设我们要为一个博客系统添加“用户评论”功能。5.1 准备工作阶段角色上下文侦探。行动我首先探索现有代码库。发现项目是Node.js Express Sequelize MySQL的技术栈。发现已有Post文章模型和User用户模型关系是User hasMany Post。发现认证系统使用JWT中间件auth.js负责验证。关键约束数据库是MySQL 5.7不支持JSON字段的某些高级查询设计数据模型时需注意。产出PREWORK.md文档记录了以上发现并特别标注了数据库版本约束。5.2 需求定义阶段角色技术产品经理。行动与“业务方”可能是自己或团队成员沟通撰写requirements.md。JTBD1) 作为读者我想对文章发表看法以便与作者和其他读者交流。 2) 作为文章作者我想管理我文章下的评论以维护讨论区的质量。用户故事功能发布评论 场景登录用户发布评论成功 假设 用户已登录且文章ID123存在 当 我在文章页面评论框输入“这篇文章很有帮助”并点击提交 那么 评论应立即显示在文章下方并显示我的头像和昵称 并且 我收到“评论发布成功”的提示 场景未登录用户尝试发布评论 ... 功能评论管理 场景作者删除自己的评论 ... 场景文章作者删除他人评论 ...非功能需求评论列表加载时间应小于200ms支持分页每页20条。5.3 系统设计阶段角色首席软件架构师。行动基于需求和准备工作产出design.md。数据模型设计-- 考虑到MySQL 5.7的限制不使用嵌套JSON存储 CREATE TABLE comments ( id INT PRIMARY KEY AUTO_INCREMENT, content TEXT NOT NULL, post_id INT NOT NULL, -- 外键关联文章 user_id INT NOT NULL, -- 外键关联用户 parent_id INT NULL, -- 用于实现回复功能自关联 status ENUM(published, deleted, hidden) DEFAULT published, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (parent_id) REFERENCES comments(id) );API设计GET /api/posts/:postId/comments- 获取评论列表支持分页和排序。POST /api/comments- 发布新评论需认证。DELETE /api/comments/:commentId- 删除评论认证用户只能删自己的作者可删文章下所有。架构图用文字描述前端 - API网关 -CommentController-CommentService-CommentRepository- MySQL。CommentService会调用UserService和PostService验证用户和文章状态。权衡决策选择使用关系型数据库表而非嵌套JSON字段存储评论虽然查询回复树稍复杂需应用层处理或递归查询但保证了在MySQL 5.7下的兼容性和查询灵活性。5.4 实施计划阶段角色高级工程经理。行动将设计拆解为原子步骤形成plan.md。## 阶段一数据层与模型 1. 【DB迁移】创建数据库迁移文件YYYYMMDD-create-comments-table.js实现上述comments表。 * 验证运行迁移在MySQL中确认表结构正确创建。 2. 【模型定义】在src/models/下创建comment.js定义Sequelize模型及与User、Post的关联。 * 验证编写关联测试确保comment.getUser()和comment.getPost()能正确工作。 3. 【仓库层】创建src/repositories/comment.repository.js实现基础的create, findByPost, findById, softDelete方法。 * 验证为每个仓库方法编写单元测试覆盖成功和异常情况。 ## 阶段二业务逻辑与服务层 4. 【服务层】创建src/services/comment.service.js。 * 实现createComment校验用户、文章状态调用仓库。 * 实现getCommentsForPost处理分页逻辑调用仓库。 * 实现deleteComment校验权限是评论者本人或文章作者调用仓库的软删除。 * 验证为每个服务方法编写单元测试模拟仓库层。 ## 阶段三API接口层 5. 【控制器】创建src/controllers/comment.controller.js。 * 实现listComments, createComment, deleteComment三个控制器函数处理HTTP请求/响应调用服务层。 * 验证编写控制器测试模拟HTTP请求和响应对象。 6. 【路由】在src/routes/下创建commentRoutes.js注册上述API端点并集成JWT认证中间件。 * 验证启动应用使用Postman或curl测试路由是否可访问认证是否生效。 ## 阶段四集成与收尾 7. 【集成测试】编写端到端测试模拟用户登录、发布评论、查看列表、删除评论的全流程。 8. 【前端集成】更新前端文章页面组件调用新评论API此步骤可另开PDPI任务。同时更新STATUS.json将currentPhase设为PLANcurrentPlanStep设为0。5.5 代码实现阶段角色初级开发/实现专员。行动与AI如Cursor协作严格按计划执行。打开Cursor将STATUS.json、plan.md、design.md、requirements.md作为上下文。发出指令“我们现在处于PLAN阶段步骤1。请根据design.md中的数据模型创建Sequelize迁移文件20231027-create-comments-table.js。”AI生成迁移文件代码。我运行迁移验证通过。更新STATUS.jsoncurrentPlanStep: 1。重复步骤2-4直到所有计划步骤完成。在每个编码步骤中坚持TDD先让AI根据需求写测试用例再写实现代码运行测试通过。在整个过程中如果发现计划不周比如忘了设计“评论审核状态”我不会直接改代码而是会暂停回到plan.md甚至design.md去补充更新文档后再继续执行。这保证了所有决策都被记录代码与文档始终保持同步。6. 常见问题、挑战与应对策略任何新流程的引入都会遇到阻力。PDPI看似增加了前期开销但它的回报在于中后期的稳定与高效。以下是一些常见质疑和我的应对经验。6.1 “这太慢了我直接写代码早就搞定了。”短期 vs 长期对于极其微小比如修一个拼写错误或高度重复比如增删改查模板的任务PDPI确实过重。但对于任何有逻辑、有状态、有外部依赖的新功能或模块前期多花30%的时间在规格上往往能避免后期200%的返工和调试时间。策略灵活运用。不是每个if-else都需要写规格。但对于核心业务模块、公共组件、复杂算法强制走PDPI流程。可以设定一个阈值比如预计开发时间超过2人天的任务必须走规格流程。6.2 “需求总是变设计文档写完就过时了。”文档是路标不是枷锁PDPI不反对变化它反对的是无序的变化。当需求变更时流程应该是识别变更影响范围。首先更新requirements.md明确变更内容。评估对现有design.md和plan.md的影响。更新受影响的设计和计划部分。最后才修改代码。 这个过程本身被STATUS.json和文档的版本历史如Git记录了下来变更原因和影响一目了然。这比直接在代码里东改西改最后留下一堆技术债要清晰得多。6.3 “和AI一起写文档沟通成本更高了。”初期适应与长期收益是的一开始用自然语言向AI描述一个复杂设计可能比直接写代码更费劲。但这是一种投资。一旦AI通过文档理解了你的完整意图它在实现阶段的准确率和效率会呈指数级提升。而且这些文档未来可以复用 onboarding新人、复盘项目、重构系统时它们是无价之宝。技巧善用AI的归纳和追问能力。你可以先写一个草稿然后让AI“基于这份初步设计以首席软件架构师的身份向我提出十个最可能遗漏或存在风险的问题。” AI的提问往往会帮你发现盲点。6.4 如何说服团队或自己开始尝试从小处着手不要一开始就在核心项目上推行。找一个边缘的、独立的、风险可控的小功能或工具脚本作为试点。展示对比用PDPI流程完成试点后与团队过去类似规模但未用PDPI的任务进行对比。对比指标可以包括代码缺陷率、返工次数、后续维护时理解代码的成本。强调AI协同红利向团队展示有了清晰的规格AI如何从一个“不靠谱的实习生”变成一个“严格按图施工的熟练工”。这能直接提升个人和团队的交付能力。工具化支持尝试制作一些简单的脚本或IDE插件帮助自动生成模板、检查清单或者将STATUS.json与任务看板如Jira, Trello集成降低流程的摩擦。我个人在多个项目中实践PDPI或类似规格先行的方法后最深的体会是它带来的最大价值不是文档本身而是在创作文档过程中被迫进行的深度思考。那些在编码中途才发现的架构矛盾、边界情况被提前到了设计阶段解决那些因为沟通不畅导致的误解被结构化的需求文档消除了。当整个团队包括人类和AI都对“要做什么”和“怎么做”有一份共同认可的、详细的参考时协作的顺畅度和最终产出的质量自然会水到渠成。它让软件开发从一门“手艺活”变得更像一门可重复、可预测的“工程”。