從零開始打造 Claude Code 工程團隊(二):主線前段——PM、Architect、Engineer
用一個「忘記密碼功能」的需求走完前三個角色:PM 怎麼拆 AC、Architect 為什麼一定要寫三個方案、Engineer 動工前要過哪些檢查。
系列第二篇。Part 1 講了為什麼需要多角色,這篇開始拆主線前段三個角色:PM、Architect、Engineer。我們用「幫我加一個忘記密碼功能」這個需求作為貫穿範例。
開場:模糊需求進來會發生什麼
使用者丟過來:
「幫我加一個忘記密碼功能。」
這句話有 N 種可能的解讀:
- 用 email 發重設連結?還是發驗證碼?還是簡訊?
- 連結幾分鐘失效?10 分鐘還是 24 小時?
- 重設後現有 session 要不要全部登出?
- 失敗多少次要鎖帳號?
- 有沒有 rate limit?同一個 IP 一小時最多能試幾次?
直接跳到 Engineer 寫 code 的人,會自己用直覺幫使用者做完所有決定。等發現產品方向錯了,code 已經寫了一半。
PM 的存在就是為了卡在這個位置:還沒人寫程式之前,把模糊變成具體。
角色一:PM——把需求變成可驗收的 ticket
PM 的核心產出:AC(Acceptance Criteria)
PM 收到模糊需求後,要產出一份 ticket,裡面最重要的欄位是 AC。AC 是一條條可驗收的條件,每一條都是 yes/no 判斷,不是模糊形容。
爛 AC 範例:
- 使用者可以重設密碼
- 流程要安全
- UI 要好看
好 AC 範例:
AC-1: 使用者在登入頁點「忘記密碼」會跳到 /forgot 頁面,
該頁面有 email 輸入欄與「寄出重設連結」按鈕。
AC-2: 送出 email 後,系統用 SendGrid 寄一封信,
內含 https://<host>/reset?token=<jwt> 連結,token 有效期 30 分鐘。
AC-3: token 無效或過期,/reset 顯示「連結已失效,請重新申請」並提供回到 /forgot 的連結。
AC-4: 重設成功後,該帳號的所有現有 session 全部登出。
AC-5: 同一個 email 一小時內最多送 3 次重設信,超過回 429。
每一條都可以拿瀏覽器或 curl 去驗證。這個能驗證的特性就是 AC 的全部意義。
PM 的另一個職責:Phase Gate
把這個功能切成幾個 phase 開發:
- Phase 1:前端
/forgot頁 + 後端送信 endpoint(AC-1, AC-2) - Phase 2:
/reset頁 + 重設 endpoint + session 撤銷(AC-3, AC-4) - Phase 3:rate limit(AC-5)
Phase Gate = 紅綠燈。每個 phase 結束時 PM 要判斷:這個 phase 的所有 AC 都通過了嗎?沒通過的話可不可以放行下一階段?
新手最容易犯的錯:邊寫邊改 AC。寫到 Phase 2 才發現 AC-2 的 30 分鐘其實設不到,就把 AC 改成「token 有效到使用者重設為止」。這樣 AC 就失去了意義——它變成了「事後解釋實作」,而不是「事前定義驗收」。
PM Never Do
- 不寫 code
- 不直接做產品決策(要回問使用者)
- 不替自己改 AC——改 AC 必須走變更流程
PM 的 Refusal Clause
當 Engineer 在實作中跑來問「AC-3 那條沒寫到 token 在 cookie 還是 query string,我要寫哪邊?」PM 不能用直覺回答,要:
- 檢查 AC 是否真的沒寫(避免漏看)。
- 確認沒寫,就回去問使用者——這是產品決策。
- 補進 AC 後,才放行 Engineer。
「回去問」聽起來很煩,但這是 PM 的核心價值。PM 自己決定產品方向,就不再是 PM,而是另一個 Engineer。
角色二:Architect——為什麼一定要寫三個方案
PM 把 AC 給 Engineer 之前,中間還有 Architect。為什麼?
因為 AC 描述的是「結果應該長怎樣」,Architect 處理的是「有幾種方法能達到這個結果,我們選哪一種、為什麼」。
三個方案的硬性規則
Architect 收到 ticket 後,必須產出至少 3 個設計方案,而且 3 個方案要分布在不同維度——不能是「同一個方案的三種微調」。
回到忘記密碼的例子,AC-2 說「用 SendGrid 寄重設連結」。Architect 要思考:
| 方案 | 機制 | 優點 | 缺點 |
|---|---|---|---|
| A | Email 重設連結(jwt token) | 不需新基礎設施 | 使用者可能找不到信、token 可被外洩 |
| B | Email 6 位數驗證碼(user 輸入) | token 短、不會被 email 曝光 | 多一次輸入步驟 |
| C | 簡訊 OTP | 安全性高 | 需要手機號碼、有費用 |
只寫 A、B 兩個版本(都是 email)就違反「分布在不同維度」——B 雖然不同形式,但跟 A 共享同一條 email 通道風險。C 換通道才算真正的另一個維度。
為什麼要寫三個? 因為人在只有一個方案時,會自動把它合理化;有兩個方案時,會選比較熟悉的;只有三個以上、且被迫思考差異維度,才會看到真正的取捨。
All-Phase Coverage Gate
Architect 還要確保設計覆蓋每一個 phase。用考試比喻:題目要涵蓋每個章節,不能只考第一章。
AC-1 ── 前端 /forgot 頁 ── 設計:UI flow + form validation
AC-2 ── 後端送信 ── 設計:選擇 A/B/C + token schema
AC-3 ── /reset 失效處理 ── 設計:error state UI + 後端 token 驗證
AC-4 ── session 撤銷 ── 設計:Redis 撤銷清單 vs JWT blacklist
AC-5 ── rate limit ── 設計:IP-level vs email-level
每一行 AC 都要有對應的設計段落。漏一行就是 Coverage Gate 沒過,Architect 自己要打回重寫。
Boundary Pre-emption Table——先列雷區
設計階段最大價值是預判邊界,不是寫 happy path。Architect 要產出一張「會踩到什麼邊界」的表:
| 邊界 | 怎麼觸發 | 預期行為 |
|---|---|---|
| Email 不存在於系統 | 隨便填不存在的 email | 一律回成功(避免列舉攻擊) |
| 同一個 email 連點 5 次「寄出」 | rate limit 邊界 | 第 4 次起回 429 |
| token 過期後再點連結 | AC-3 路徑 | 顯示失效訊息,不揭露原因 |
| 使用者重設時舊密碼跟新密碼一樣 | 邊界 case | 回 422,提示不能與舊密碼相同 |
| 重設成功瞬間,使用者的另一個分頁還登入著 | AC-4 case | 那個分頁下次 API 呼叫會被 401,前端踢回登入頁 |
Boundary Pre-emption Table 沒寫的邊界,就是上線後會被使用者找到的 bug。架構師不寫這張表,就只是換個名字的 Engineer。
Architect Never Do
- 不直接寫實作
- 不只寫一個方案就 release
- 不跳過 Boundary Table
角色三:Engineer——動工前的五維挑戰表
設計通過後,輪到 Engineer 寫 code。但動手前還有一道關。
Pre-Implementation Design Challenge Sheet
新手會直接打開檔案開始寫。資深的做法是先過五個維度的自我挑戰:
| 維度 | 自問 | 範例 |
|---|---|---|
| Interface contract | 我要改哪些公開 API?誰會用到? | /api/forgot 新 endpoint,前端 /forgot 頁會呼叫,外部沒人用 |
| Refactorability | 半年後需求變了,這段 code 改起來容易嗎? | token 邏輯抽 service,避免散在 controller |
| Test seam | 測試要從哪裡注入? | SendGrid client 要可替換(用 interface) |
| Blast radius | 我這個改動會影響到誰? | 共用了 auth/session.ts,登入 / 登出流程都會被影響 |
| Drift | 我寫的跟設計一樣嗎?跟現有 code style 一致嗎? | check Architect 選 A/B/C 哪個,跟現有錯誤訊息格式對齊 |
走完這五題才動手。漏掉 blast radius 是新手最常踩的雷——以為只是加個新功能,結果改到一個共用的 helper,把不相關的另一個流程弄壞。
Step 0 系列前置 gate
Engineer 動手前還有幾個自動檢查,每一條沒過就直接 halt:
Step 0 — branch verification
目前在哪個 branch?是 main 嗎?是的話 → 停,建 worktree。
Step 0a — ticket ID 驗證
我有沒有對應的 ticket?沒有的話我在做的事可能不該做。
Step 0b — 檔案存在性
我打算改的檔案存在嗎?(用 Read / ls 驗證,不要靠記憶)
Step 0c — 上次離開的狀態
這個分支是不是有未 commit 的東西?是的話那是別的工作的中間狀態,要先處理。
這幾道 gate 看起來瑣碎,但每一條都對應到至少一次踩過的雷。例如 Step 0 對應「不小心 commit 到 main 結果汙染主分支」;Step 0a 對應「以為使用者要的功能但其實搞錯了 ticket」。
一次一個 edit,立刻驗證
新手最危險的習慣:連續改三四個檔案才跑測試。出錯時你不知道是哪一個改動造成的。
正確節奏:
- 改第一個檔案。
- 跑相關測試(單元 / E2E 都跑)。
- 通過了,才改第二個。
- 失敗就只回退第一個改動,不要連續累積問題。
聽起來很慢,但累積三個未驗證的 edit 才出錯,debug 時間是逐個驗證的 5 倍以上。
Engineer Never Do
- 不直接 commit 到 main
- 不堆疊多個未驗證的 edit
- 不自己驗收自己(驗收是 Reviewer + QA 的工作)
- 不跳過 Step 0 系列檢查
三角色完整接力示範
把整個前段串起來看:
[使用者] 「幫我加一個忘記密碼功能。」
↓
PM
- 釐清需求(回去問了 5 個 BQ)
- 寫好 AC-1..AC-5
- 切 3 個 phase
- release Architect
↓
Architect
- 提出方案 A/B/C
- 跟使用者確認選 A
- 寫 Boundary Pre-emption Table(5 個邊界)
- All-Phase Coverage check 通過
- release Engineer
↓
Engineer (Phase 1)
- Step 0 系列檢查(全部通過)
- Pre-Implementation 五維挑戰
- 改第一個檔案 → 測試 → 通過
- 改第二個檔案 → 測試 → 通過
- Phase 1 完成
- release Reviewer(Part 3 主題)
每個角色完成自己的工作後,用一份 handoff 文件交給下一個。Handoff 文件包含:
- 這個 phase 的 AC
- Architect 的設計選擇 + 理由
- Engineer 改了哪些檔案、跑了哪些測試
- 已知未解事項(known issues)
下一個角色開始工作前,必須先讀 handoff 文件。沒讀就動工 = 重蹈單一視角的覆轍。
小結
| 角色 | 核心產出 | 最容易漏掉的事 |
|---|---|---|
| PM | 可驗收的 AC + Phase 切分 | 自己改 AC 而不走變更流程 |
| Architect | ≥3 方案 + Boundary Pre-emption Table | 三個方案其實只是同維度微調 |
| Engineer | 通過五維挑戰才動工 + 一次一個 edit | 累積多個未驗證 edit、跳過 Step 0 |
下一篇我們進入主線後段:Reviewer 怎麼兩段式審 code、QA 為什麼邊界值才是 bug 的家、Designer 在什麼時候才要被叫進來。