面对复杂功能,本能反应是"先写点试试"——但架构决策藏在第 3 个模型、第 5 个 edge case 里。plan mode 的真正价值是把架构级对话前置到文字层面。用 Pickful 的社区陪审系统实战:一个 commit 3032 行 119 spec 全绿,之后十几个提交零架构回炉。
面对复杂功能,大多数人本能反应是"先写点试试"。
问题是复杂系统有一个特点:架构决策藏在第 3 个模型、第 5 个 edge case、第 8 个积分规则里。你一头扎进代码,撞到这些决策时回头改,比一开始在文字层面讨论清楚贵 10 倍。
我用 Claude Code 的 plan mode 做 Pickful 的 TopicReview 社区陪审系统时,验证了这个不等式的极端版本:一个 commit,3032 行,119 spec 全绿,一次上线。之后十几个提交没有一次是架构回炉,全是参数调整、UI polish、边界 case 修补。系统稳定运行到现在,是社区治理的核心。
这篇讲为什么复杂功能必须先 plan,plan 阶段到底在做什么,沟通到什么程度算可以开始写。
TopicReview 是社区投票决定是否移除低质量帖子的系统。一句话讲完——但规格一层层展开:
复杂性核心不在单条规则,是规则之间的交互。每加一条都可能触发另一条的回退。
直接写,最容易出问题的不是看得见的事实——是你想不到要问的问题。从 TopicReview 的代码里反推,至少四处不先 plan 就必然撞墙:
陪审员资格规则。看起来就是 User.jurors_and_judges.sample(12)。但实际规则是:排除原作者、排除举报人、排除已投过初审的(防止同人投申诉)——三条排除叠加。合到一处写 model 时容易漏一两条。
积分延迟发放。Remove 裁决正常会触发陪审员积分发放。但申诉能推翻 remove——一推翻陪审员站队就反了,积分要按新裁决重算。所以 remove 裁决必须等 24h 申诉窗口过了才发积分。这条规则不写在纸上,你会先发积分后发现要退——退积分比延迟发麻烦十倍。
定时任务接口设计。CloseTopicReviewJob 看着就是"结束一个 review"。实际它要处理三种场景:
# 初审投票窗口到期
CloseTopicReviewJob.set(wait_until: voting_ends_at).perform_later(review.id)
# Remove 裁决后延迟发陪审员积分
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, award_juror_points: true)
# 申诉窗口到期
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, appeal_id: appeal.id)
不先梳理,会先写成单一签名,实现到第二种场景时整个接口重设计。
最贵的那种墙:provisional removal 期间能否申诉。投票过半数 remove 时帖子立刻下架(provisional),但整个 review 还在 voting 状态、没 decide。用户能不能申诉?
这个选择会反向影响 open_appeal! 的参数校验和状态机逻辑。不先想清楚,写到一半改 = 半个系统重写。
Claude Code 的 plan mode 是一个不允许写代码的模式——Claude 可以读仓库、想方案、和你讨论,但任何文件修改都被 hard-block,直到你同意一个 plan 才解锁。
这个机械约束就是 plan mode 的核心价值——强迫架构级对话发生在文字层面。
plan 阶段实际在做的几件事:
1. 画状态机和角色。5 个状态、4 种角色(陪审员 / judge / 发帖人 / 举报人)、每种角色能做什么不能做什么——全部落在几行 markdown。几行 vs 几十个文件,修改成本差两个数量级。
2. 每种角色的用户流程 walkthrough:
每条走不通的地方立刻暴露:「陪审员能看到其他陪审员的 vote 吗?」「发帖人在 provisional removal 时能做啥?」
3. 边界 case 审问。plan 阶段不是设计"正常情况",是特意问那些平时不想想的问题:
juror_points_awarded 幂等字段)这些问题 95% 写代码时不会自然浮现——plan 阶段强迫你一个个过。
4. 积分台账。积分系统复杂到光讨论不够,要真的画表:每笔 point 流动写明触发条件 + 数额 + 回退路径。台账对齐后所有边界 case(暂扣退、申诉退、bonus)都能对上账。
一个硬标准:
达到这个标准,写代码就是把 plan 翻译成 Ruby。
这个系统的第一次 ship:
d162f1e Add community moderation system with jury/judge review and appeals
63 files changed, 3032 insertions(+)
119 specs, 0 failures
63 个文件,3032 行,119 个 spec 全绿。一次上线。
之后十几个 commit 验证了架构稳定:
Apply legacy penalty (1pt) for posts created before 2026-03-26
Fix topic review appeal bugs: window mismatch and verdict not updated
Add topic_removed status for posts removed by community review
Default to keep verdict when review expires with zero votes
Reduce provisional removal penalty to 1pt during trial period
Allow topic creator to withdraw active reviews
Add handled tab to jury dashboard, fix tabs styling
每条都是 tune / fix / polish / 加小功能。没有一次是"回去重新设计状态机"或"积分模型要改"。架构骨架全对。
这是 plan 真正的回报:让执行不可中断。没有"等一下这条路径怎么处理"——plan 里已经写了。没有"边界 case 我没想到"——plan 阶段问过了。没有"这个接口要重设计"——plan 里已经梳理过。
连续几个小时写代码,只做一件事:把清晰的设计落到键盘。
不是所有任务都值得 plan:
plan mode 的收益来自降低重写成本。如果任务根本没有重写风险,plan 只是开销。
"先想好再做"听起来像性格建议。plan mode 不是这个意思。
plan mode 是把架构级对话发生在可以改 10 个字的地方,而不是必须改 30 个文件的地方。
复杂功能下,"words are cheap, code is expensive" 这个软件行业老生常谈的不等式要反过来用——不是鼓励你先写代码再说(那只在成本差距小的时候成立),是让你利用这个差距,把贵的沟通前置。
3000 行一次上线的感觉非常爽。不是因为我写得快,是因为 plan 把"写"变成了纯机械动作。