面對複雜功能,本能反應是「先寫點試試」——但架構決策藏在第 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 把「寫」變成了純機械動作。