撰写计划
在写任何代码之前,先把工作写清楚。
为什么计划优先于代码
实现计划是一份文档,它详细描述你打算构建什么以及如何构建——在写任何代码之前。
这与"先规划、后实施"这句话的通常含义不同。Superpowers 中的计划足够具体,以至于任何胜任的工程师(或 AI agent)都可以执行其中的任何任务,而无需猜测意图或做出未记录的架构决策。
如果你的计划需要执行者自行解读,那就不够好。
计划结构
每份计划都以一个头部区块开始,然后是编号的任务列表。
头部格式
# 实现计划:[功能名称]
## 上下文
[1–3 句话描述这解决了什么问题]
## 方案
[所选方案的简短描述,来自头脑风暴]
## 超出范围
[明确列出我们*不*在这次实现中做的事]
## 前置条件
[开始之前必须为真的事]
任务结构
每项任务必须包含:
1. 任务编号和标题
任务 3:为用户登录创建失败测试
2. 目标 一句话描述这项任务完成了什么。
3. 精确的文件路径
不是"在 auth 文件夹中",而是 src/auth/login.test.ts。
4. 完整代码 不是"添加一个登录函数",而是确切的代码,完整且可运行。
5. 验证步骤 这项任务完成后如何验证。通常是运行测试套件的命令。
6. 预期输出 运行验证命令后你期望看到什么。
每项任务 2–5 分钟规则
计划中的每项任务都应该小到足以在 2–5 分钟内完成。
这个规则有两个目的:
第一: 它迫使任务足够小,以至于一个 subagent(一个新的、没有其他上下文的 AI 实例)可以完成它而不需要理解整个代码库。
第二: 它创造了一个自然的检查点节奏。每项任务完成后,都有一个明确的时刻来评估:计划还有效吗?有什么意外吗?
如果你发现自己在写一项"实现完整认证系统"的任务,那是一个信号:这项任务需要分解。
TDD 在计划中的体现
每项实现任务前面都必须有一项测试任务。计划结构强制执行 TDD:
任务 N:为 [行为] 编写失败测试 ← RED
任务 N+1:实现 [行为] ← GREEN
[如果范围需要,重构在任务 N+1 内或作为任务 N+2]
没有测试任务前置的实现任务是计划缺陷。
当你审查计划时,检查这个配对是否对每项功能任务都成立。如果一项实现任务没有对应的测试任务,要么添加测试任务,要么拒绝计划。
YAGNI 和 DRY 在计划中
YAGNI(你不会需要它)
计划中的每项任务都应该有明确的当前需求理由。问:
"这项任务是当前功能所需的,还是我们在为可能的未来需求提前构建?"
如果答案是"为了以后"——删除这项任务。当以后到来时,再计划和实现它。未来的功能有未来的需求;今天你不知道那些需求是什么。
DRY(不要重复自己)
在撰写计划时,查找可以提取的重复模式。如果三项任务都"在类似位置添加类似内容",可能有一个单一的任务可以把它们全部做完,或者一个你应该先创建的共享工具函数。
DRY 是在计划层面处理的,而不是在执行中途发现的。
范围管理信号
以下信号表明计划需要修剪或重构:
| 信号 | 问题是什么 |
|---|---|
| 超过 12 项任务 | 计划可能太大,无法安全地作为单一分支交付 |
| 任何任务估计超过 10 分钟 | 分解这项任务 |
| 任务依赖同一功能的并行任务 | 重新排序或分离依赖项 |
| "重构现有系统"的任务 | 这应该是单独的计划 |
| 任务说"更新所有 X 以支持 Y" | 枚举具体的文件和更改 |
| 任务需要读者填补空白 | 添加精确的代码和路径 |
计划审查流程
在执行开始之前,计划要经过三阶段审查:
阶段 1:完整性检查
- 每项任务是否有精确的文件路径?
- 每项任务是否有完整的、可运行的代码?
- 每项实现任务是否有前置的测试任务?
- 是否枚举了验证步骤?
阶段 2:设计对齐检查
- 这份计划是否实现了头脑风暴中批准的设计?
- 是否有任何任务超出了头脑风暴文档中明确的范围?
- 超出范围的内容是否真的没有出现在任何任务中?
阶段 3:可执行性检查
- 如果一个对代码库一无所知的工程师拿到这份计划,他们能够执行每项任务吗?
- 任务之间是否存在未记录的依赖关系?
- 是否有任何任务的成功标准含糊不清?
只有在三个阶段都通过后,计划才能进入执行阶段。
一份精心撰写的计划示例
# 实现计划:用户登录
## 上下文
用户目前必须手动输入凭据才能访问应用程序。
我们正在添加带有标准电子邮件/密码验证的登录表单。
## 方案
简单的服务器端会话,没有 JWT(来自头脑风暴,方案 A)
## 超出范围
- OAuth / 社交登录
- 记住我(持久化会话)
- 密码重置流程
## 前置条件
- 数据库迁移 #42(用户表)必须已运行
- AUTH_SECRET 环境变量必须已设置
---
任务 1:为登录表单验证编写失败测试
文件:src/auth/login.test.ts
目标:确认有一个失败测试捕获验证逻辑
代码:
test('rejects empty email', () => {
expect(validateLogin({ email: '', password: 'abc' })).toEqual({
valid: false,
error: 'Email is required'
});
});
验证:npm test -- --testPathPattern=login
预期输出:1 个失败(validateLogin 不存在)
任务 2:实现登录验证函数
文件:src/auth/login.ts
目标:使任务 1 的测试通过
代码:
export function validateLogin({ email, password }) {
if (!email) return { valid: false, error: 'Email is required' };
if (!password) return { valid: false, error: 'Password is required' };
return { valid: true };
}
验证:npm test -- --testPathPattern=login
预期输出:1 通过,0 失败
[以此类推...]
计划是对你意图的正式声明。 如果你无法写清楚,你还没有准备好实现。如果你可以写清楚,实现就变成了执行一系列明确步骤的问题——而不是在代码中发现架构。