Appearance
用Claude Code做需求拆解:比你自己想得更细
我让它帮我做用户订阅功能,它给我列了十七条清单。涉及Stripe Checkout、Webhook状态处理、订阅降级逻辑、grace period、试用期邮件通知……我以为这是一个功能,实际上是十七个。如果我直接让它写代码,剩下的会在上线后一个个炸给我看。
独立开发者最容易在哪里翻车
不是技术能力不够,是需求拆解不到位。
| 问题 | 原因 |
|---|---|
| 取消订阅了但还在扣款 | 没想到的功能场景 |
| 试用期过了账号直接被封无提示 | 只做了happy path |
| 用户反馈各种边界问题 | 没有足够的带宽做完整拆解 |
说人话:你以为做完了,其实你只做了happy path。边界情况、异常场景、用户视角下的关键细节,没有人帮你想。
需求拆解四步框架
第一步:用一句话描述需求,让它问你问题
不要一开始就让它帮你拆,先让它向你提问。
我要给我的SaaS工具加订阅功能,支持月付和年付,用Stripe。
在你开始帮我拆分任务之前,先问我你需要知道的问题,确保你完全理解这个需求。它会问你7-10个问题:
| 问题 | 你可能没想到的点 |
|---|---|
| 是否有试用期?试用期结束后未付款账号如何处理? | 试用期逻辑 |
| 用户能否在月付和年付之间切换?切换时费用如何计算? | 切换逻辑 |
| 订阅到期后是否有grace period?还是立刻锁定账号? | 降级策略 |
| 取消订阅后用户的数据保留多久? | 数据保留策略 |
| 是否需要支持退款?退款触发条件是什么? | 退款流程 |
| 订阅状态变更是否需要发邮件通知?哪些状态变更需要? | 通知机制 |
这些问题的价值:看到问题的一瞬间,你才意识到"这个我还没决定"。这个阶段花半小时回答,比上线后修复"没想到的场景"要便宜得多。
第二步:让它基于你的回答生成完整任务清单
好的,基于我的回答,帮我生成完整的任务清单。
每个任务要具体到"实现XX功能/处理XX场景"这个粒度,
不要笼统地说"处理支付逻辑"。
按照功能模块分组,标注每个任务的依赖关系。它会给你分组清单:
【模块一:Stripe基础接入】(无依赖,优先实现)
- 创建Stripe Checkout Session(月付/年付两种price_id)
- 实现success_url和cancel_url的跳转逻辑
- 初始化Stripe Webhook端点并验证signature
【模块二:Webhook事件处理】(依赖模块一) 4. checkout.session.completed → 更新subscription状态为active 5. customer.subscription.updated → 同步plan变更 6. customer.subscription.deleted → 触发降级逻辑 7. invoice.payment_failed → 标记past_due,发邮件提醒 8. invoice.payment_succeeded → 更新current_period_end
【模块三:用户操作】(依赖模块二) 9. 实现"升级到付费计划"入口 10. 实现"取消订阅"功能 11. 实现"月付/年付切换" 12. 展示当前订阅状态和下次扣费日期
【模块四:边界场景处理】 13. 试用期结束未付款 → 发邮件提醒,7天后锁定账号 14. 账号锁定后登录 → 展示"订阅已过期"页面,引导续费 15. Stripe customer不存在时的容错处理 16. 重复Webhook事件的幂等性处理 17. 退款申请 → 手动处理流程
关键点:模块四的"边界场景处理",是大多数人第一次拆需求时完全忽略的部分。
第三步:让它评估每个任务的工作量和风险
对这个任务清单里的每个任务,评估:
1)实现难度(简单/中等/复杂)
2)出错代价(低/中/高,出错了对用户影响多大)
3)实现顺序建议
如果某些任务有"看起来简单但容易踩坑"的地方,单独提出来。它会告诉你哪些任务表面简单实则危险:
| 任务 | 看起来 | 实际上 |
|---|---|---|
| 月付/年付切换 | 改一下subscription | 涉及按比例退款计算、旧item删除新item添加,API调用顺序错会双重收费 |
| Webhook幂等性 | 简单检查 | Stripe会重发事件,不检查会导致同一订单写入两次 |
第四步:逐个任务实现——每次只做一件事
原则:每次Claude Code会话只做清单里的一个任务。不是两个,不是"把这几个相关的一起做",是一个。
启动会话模板:
当前任务:实现Webhook处理函数中对invoice.payment_failed事件的处理。
处理逻辑:收到事件后,将Prisma数据库里对应用户的subscription.status更新为past_due,
同时触发发送邮件(用Resend),邮件模板是"payment-failed",发送到user.email。
相关文件:app/api/webhooks/stripe/route.ts(已有Webhook框架)、lib/email.ts
约束:不要修改Webhook函数的基础结构,只在switch语句里添加新的case。
幂等性检查:先查subscriptionEvents表里有没有这个event.id,有的话直接返回。踩坑环节
坑一:让它一次性实现整个订阅模块
| 后果 | 原因 |
|---|---|
| 代码有但没测试过边界 | 看起来完整,实际有漏洞 |
| 上线两天后报500错误 | 没处理"grace period里重新订阅"的场景 |
| 修了三小时+手动处理数据 | "全部一起实现"只是把风险推后积累 |
解决方案:任务必须一个一个做,做完一个、测一个、commit一个。
坑二:跳过了"让它问你问题"的步骤
| 后果 | 原因 |
|---|---|
| 清单漏掉邮件通知 | 需求描述里没提到 |
| 用户投诉被扣款但没收到确认 | 简单逻辑但没在拆需求阶段想到 |
| 用户信任损失 | 急着省半小时,上线后三倍代价还回来 |
解决方案:"让它问你问题"这一步不能跳过,那十个问题里藏着你的盲区。
总结
需求拆解的本质:把所有"你以为知道但其实没想清楚"的地方,提前暴露出来。
做不到这一点:写出来的代码就是在赌运气。一个人开发,没有团队帮你兜底,你必须比任何人都想得更细。
Claude Code的价值:不在于帮你写了多少代码,在于它逼你想清楚了多少你本来会跳过的细节。
