Notes
← All notes
·ai·12 min

從零開始打造 Claude Code 工程團隊(三):主線後段——Reviewer、QA、Designer

Engineer 說「寫好了」,誰來相信他?Reviewer 兩段式審查、QA 邊界值掃描、Designer 旁支介入時機——主線後段三角色完整解析。

#claude-code#agent#reviewer#qa#designer#beginner-friendly

系列第三篇。Part 2 我們把忘記密碼功能跑到了 Engineer 完成 Phase 1。這一篇我們接力:Reviewer 怎麼接、QA 怎麼測、Designer 在什麼情況下才要出場。

開場:Engineer 說「寫好了」,誰來相信他?

延續上一篇的範例。Engineer 完成了 Phase 1:

  • 前端 /forgot
  • 後端 POST /api/forgot endpoint
  • 寄出 jwt token email

他在 handoff 文件寫:「全部測試通過,可以 review。」

新手會直接信。但資深做法是:Engineer 自己跑的測試只是必要條件,不是充分條件。為什麼?

  1. Engineer 寫測試時有確認偏誤——他會測自己「直覺會壞」的地方,但 bug 通常住在他直覺不到的地方。
  2. Engineer 容易漏掉 plan 對齊——code 跑得起來不代表它做的是 ticket 要的。
  3. Engineer 不會主動掃結構性問題——重複代碼、共用元件不一致、跨檔案的 config 漂移。

這就是 Reviewer 與 QA 存在的意義。


角色四:Reviewer——兩段式審 code

Reviewer 不是隨便看一遍。它有兩個明確分階段

Stage 1:breadth scan(廣度掃描)

第一階段檢查的是通用品質問題,跟 ticket 內容無關:

  • 有沒有 lint error / type error?
  • 命名一致嗎?
  • 有沒有重複的 code(structural chrome)?
  • Git status 乾淨嗎,有沒有不該被 commit 的檔案?
  • CJK 字串有沒有出現在不該出現的位置(例如 code identifier、function name)?

新手看到這些檢查會覺得「不就是 lint 嗎」。但這些在 LLM 的世界裡格外重要,因為LLM 寫 code 時容易產生看似合理的微小漂移

  • fetchUser 改成 fetchUserData,但其他地方還叫舊名字。
  • 加註解時留下中文,但這個專案規定 code 全英文。
  • 改 component 時複製貼上,留下重複 80% 的 sibling component。

Stage 1 用機械化的工具檢查(grep、tsc、自動掃描),人不需要太花腦力。

Stage 2:depth alignment(深度對齊)

第二階段才是 review 真正的價值:對齊 plan

Engineer 寫的 code,每一段是不是對應到 Architect 的 design doc 裡的某條目?

Design doc 條目Engineer 對應 commit對齊?
§3.1 Token schema:30 分鐘 expiryauth/token.ts30 * 60
§3.2 SendGrid client 抽 interfaceinfra/email.ts 直接 import 真 SDK
§4.1 失敗一律回成功(防列舉)/forgot controller 區分回應

§3.2 的問題是測試 seam 沒做出來——上線後才發現 unit test 跑不過,要花一倍時間補。 §4.1 的問題是安全性偏離設計——上線後可能被黑客當帳號列舉攻擊用。

這兩個問題 Stage 1 抓不到。Reviewer 要把 design doc 跟 git diff 並排看,逐條對齊。

Reviewer 的 Refusal Clause

最重要的一條:Reviewer 自己發現問題時,不能自己改

新手 Reviewer 看到 /forgot 區分了回應,會手動把它改成「一律回成功」然後 commit。這是嚴重違規。為什麼?

  1. Engineer 不會學到——下次還是會犯同樣錯誤。
  2. 改動沒有經過 Engineer 重新測試。
  3. Reviewer 變成另一個 Engineer,失去獨立視角。

正確做法:寫 review comment,退回給 Engineer 改。然後 Engineer 改完再來一次 review。

Reviewer Never Do

  • 不自己改 code(要退回給 Engineer)
  • 不寫到 canonical(主分支)路徑——只能 review 別人的 PR,不能自己直接動 main
  • 不放行未對齊 plan 的 commit(即使 code 看起來合理)

角色五:QA——邊界值才是 bug 的家

Reviewer 通過後,QA 上場。新手最容易把 QA 等於「跑一遍 happy path 看會不會壞」,但真正的 QA 工作 90% 在邊界值

Boundary Condition Mandatory Sweep

QA 看到一個 input field(例如「輸入 email」)時,要強制掃過所有邊界

邊界類別範例
空值沒輸入直接送出、輸入單個空格、\n 換行
長度極限1 char、255 char、256 char、10000 char
格式邊界@example.com(缺 local part)、a@a@b(缺 TLD)、IDN domain
編碼邊界unicode、emoji、零寬字元、RTL 字元
時序邊界連續送 100 次、剛好在 token 過期前 1 秒重試
狀態邊界同時兩個分頁送出、token 已用過再用一次

Engineer 寫測試時會測「正常 email + 不存在 email」兩個 case 就交差。QA 要強制把上面 6 類都跑一遍。

有沒有可能 6 類都正常? 大部分情況下,至少一兩類會出錯。例如:

  • 長度 256 char 的 email 在 DB schema 是 VARCHAR(255) → 直接 500
  • emoji email 沒做 normalization → token 簽名失敗
  • 同時兩個分頁送出 → race condition,產生兩個 token,舊 token 沒失效

這些邊界新手 PM 跟 Architect 想不到,Engineer 不會主動測,QA 要當守門員

Early Consultation——QA 在 Architect 之前就要出聲

進階做法:QA 在 Architect 還沒寫完設計時就先諮詢一次。為什麼?

因為有些設計選擇從根本上難測,等 Architect 寫完才發現要花一倍時間補測試 seam。例如:

  • Architect 選方案 C(簡訊 OTP),但 QA 環境沒簡訊 mock infrastructure → 早講 Architect 可以選 B 避免。
  • Architect 選 Redis 撤銷清單,但 CI 環境沒有 Redis → QA 要先講「測試環境怎麼處理」。

PM 在 release Architect 之前,會檢查 ticket 上是不是有「qa-early-consultation 已完成」的標記。沒有不放行。這個欄位是個強制 gate。

Interception Protocol——退件而不是補丁

QA 發現 Engineer 漏測一個邊界時,不是自己補 case,而是退件給 Engineer。理由跟 Reviewer 一樣:

  1. Engineer 才會學到。
  2. 補 case 應該由 Engineer 重新確認 code 行為符合 spec。
  3. QA 補 case = QA 變成 Engineer,失去獨立性。

QA Never Do

  • 不挑戰需求合理性(那是 PM 的工作)
  • 不自己補測試代替 Engineer
  • 不跳過 boundary sweep 直接放行

Cross-Page Shared-Component Consistency

主流程跑完之後,QA 還有一個容易被新手漏掉的工作:檢查跨頁面共用元件的一致性

範例:忘記密碼功能加完之後,登入頁底部的 footer 看起來怪怪的——你發現 Engineer 為了 /forgot 頁加了一個 footer 變體,把 <Footer> 改成可接受 variant prop。但他只有改 /forgot,其他用到 <Footer> 的頁面(首頁、關於頁、文章頁)都還是舊版。

// Engineer 改的 /forgot 頁
<Footer variant="minimal" />

// 其他頁面(沒被 Engineer 動到)
<Footer />  // 用 default variant

問題:default variant 可能因為 prop 介面改變而靜悄悄壞掉——例如預設 logo 沒了、間距跑掉了。

QA 的工作是全站快速跑一遍,把所有用到該共用元件的頁面截圖比對。新手很容易只測「自己這個 ticket 動到的頁面」,這就是漏網的源頭。


角色六:Designer——什麼時候才需要叫設計師

主線到這裡跑完了。但有一類 ticket 還需要 Designer:動到視覺的 ticket。

Visual-Delta 欄位決定要不要叫 Designer

每個 ticket 在 PM 階段都會標一個欄位:

visual-delta: yes  # 或 no

什麼情況算 visual-delta: yes?

情況visual-delta
改 NavBar 順序、加新 menu itemyes
加新 modal、新表單頁yes
改顏色 token、字型大小yes
後端 API 改回應格式no
修純邏輯 bug(前端不改 UI)no
文件 PR、retro PRno

yes 的 ticket 在 Architect 階段就會 release Designer 平行作業。no 的 ticket 完全不要拉 Designer 進來——這是新手常犯的錯,把 Designer 當「QA Plus」用,浪費他的時間又稀釋他的權威。

Pencil SSOT——所有人讀同一個視覺真相

Designer 用 Pencil(或 Figma 之類的視覺工具)做設計。但設計檔不能只在 Designer 腦袋裡——要能被其他角色讀到。

做法是「single source of truth (SSOT)」:

Designer 在 Pencil 裡改設計
   ↓
匯出 JSON snapshot(規格) + PNG screenshot(視覺)
   ↓
commit 到 design_handoff/<ticket-id>/ 資料夾
   ↓
Engineer / Reviewer / QA 從這個資料夾讀規格做事

新手做法是 Designer 截圖丟到 chat 群裡,Engineer 自己對著截圖寫 CSS。問題:截圖會過期,但沒人通知。Designer 改了一版顏色,但 Engineer 還在看舊截圖,最後上線跟設計不同步。

Pencil SSOT 的好處:Designer 改設計 = 改 source 檔 = 自動更新 snapshot 與 screenshot。Engineer 每次動工前去拉最新的 design_handoff,永遠是同步狀態。

Touched-Frames Rule——只匯出被改的 frame

Pencil 一個檔案可能有 50 個 frame(首頁、登入頁、設定頁、彈窗 A、彈窗 B...)。Designer 改了 NavBar 之後,不能把整個 50 個 frame 全部 re-export

為什麼?

  1. PR diff 會爆炸,看不出真的改了什麼。
  2. 沒改的 frame 也會 churn(因為 export 過程可能影響元素位置一兩個 pixel)。
  3. Reviewer 看 PR 時無法快速判斷影響範圍。

Touched-Frames Rule:只 export 被這個 ticket 改動到的 frame。NavBar 改了 → 只 export 含 NavBar 的 frames(首頁、設定頁、文章頁);彈窗 A 沒動 → 不 export。

AC ↔ Pencil Conflict Escalation

進到實作階段,Engineer 可能會發現:

「AC-2 寫『重設成功訊息要顯示 5 秒』,但 Pencil 設計檔上的訊息只有兩行字,5 秒太久了。」

這是規格與設計衝突。怎麼處理?

新手會自己選一個——「我覺得 3 秒就好」。。正確做法是:

  1. Engineer 停下來。
  2. 把衝突 escalate 給 PM。
  3. PM 仲裁:是 AC 要改成 3 秒,還是 Pencil 要改成顯示 5 秒?
  4. 一邊改完,PM 通知 Engineer 繼續。

這個流程看起來慢,但避免了 AC 跟視覺的長期 drift。一個 ticket 妥協一次沒事,三十個 ticket 各妥協一次,整個系統就是規格與視覺各自一套真相。

Designer Never Do

  • 不主動介入 visual-delta: no 的 ticket
  • 不 export 整個檔案(要遵守 touched-frames)
  • 不私下解決 AC ↔ Pencil 衝突(要 escalate)

完整 ticket 接力示範(接續 Part 2)

Engineer 完成 Phase 1
   ↓
Reviewer
   - Stage 1 breadth scan:lint OK,但發現一個重複 helper
   - Stage 2 plan 對齊:發現 §3.2 SendGrid 沒抽 interface
   - 退件給 Engineer
   ↓
Engineer 修兩個問題
   ↓
Reviewer 第二輪通過
   ↓
QA
   - Boundary Sweep:email field 跑 6 類邊界
   - 發現 256 char email 直接 500
   - 退件給 Engineer
   ↓
Engineer 修 DB schema
   ↓
QA 第二輪通過
   ↓
Cross-Page Consistency 檢查:登入頁 footer 沒漂移,OK
   ↓
PM Phase Gate:AC-1 ✅ AC-2 ✅,放行 Phase 2

如果這個 ticket 是 visual-delta: yes(例如改 NavBar),時間軸會多一條:

PM 標 visual-delta: yes
   ↓
Architect 跟 Designer 平行啟動
   ↓
Designer 在 Pencil 改 NavBar,export touched frames
   ↓
Engineer 動手前先讀 design_handoff/<ticket-id>/ 取得規格
   ↓
過程中 Engineer 發現 AC vs Pencil 衝突 → escalate PM
   ↓
PM 仲裁,通知雙方繼續

小結

角色核心職責最容易違規的事
Reviewer兩段式審查(breadth + depth)自己改 code 不退件
QABoundary sweep + cross-page consistency只跑 happy path、自己補 case
DesignerPencil SSOT + touched frames + 衝突 escalationexport 整個檔、私下處理 AC 衝突

下一篇我們離開 agent 層,進到 Skill 與 Hook:怎麼把重複流程封裝成可呼叫的 SOP,怎麼用 shell script 強制執行不可商量的規則