PCA 雲端架構師之旅 03 — 撰寫 User Stories
上一篇把人畫出來了——你知道阿元是誰、小葵在意什麼。但 persona 只回答了「誰」,沒回答「他到底想做什麼、做成了長什麼樣」。這一篇就是把人翻譯成系統要做的事。
User Story 不只是一張待辦卡片。寫清楚誰要完成什麼事、什麼結果算成功,後面才有辦法訂 SLO、安排服務邊界與設計 API。這一步如果只寫「系統要快」,後面的架構選擇就很難驗證。
這是 PCA 雲端架構師之旅 的第三步,接著上一篇的 User Personas 往下走。

圖解:User Story 不是一句模糊待辦。先說清楚「誰要完成什麼、為什麼重要」,再補上可計時、可檢查的驗收條件,架構師才有辦法把它翻成延遲、可用性、安全與資料新鮮度等技術要求。
從需求句子找出真正的限制
需求常被寫成一句話,例如「使用者在 2 秒內看到首頁」或「分析師每天早上要拿到前一天的銷售報表」。這些句子雖然短,卻已經包含時間與資料新鮮度的要求。官方案例的需求也是一句一條,但多半只給方向,像 EHR Healthcare 的「Reduce latency to all customers」;帶明確數字的很少,例如同一份案例的「Provide a minimum 99.9% availability for all customer-facing systems」。
讀到這類描述時,先拆成「誰要做什麼、何時需要、怎樣算完成」。前一天的報表不一定需要即時處理;如果忽略「每天早上」這個條件,很可能會把系統設計得比業務需求複雜。資料儲存與處理方式,應等查詢量、更新頻率和延遲要求都釐清後再決定。
只把需求記成「要快、要穩、要報表」還不夠,得繼續追問可量測的條件:「2 秒」是平均值還是 P95?「每天早上」具體是幾點前?這些差異會影響資料管線與服務選擇。
📝 考場提點
可以把需求整理成三欄:角色、動作、可量測標準。時間、頻率和可容忍的中斷各自影響不同決策;「每天更新」與「每筆即時更新」不能當成同一種工作負載。碰到 RPO、RTO 或查詢延遲,也要分別確認指的是資料損失、復原時間,還是使用者等待時間。
流程圖暫時無法顯示。可先查看下方的流程與節點文字,或重新整理頁面後再試。
查看流程與節點文字
箭頭表示流程方向;方括號與引號內是節點名稱,可搭配下方圖解閱讀。
flowchart TB C[案例中的需求句子] --> W[找角色 Who] W --> A[找行動 Action] A --> V[找價值 Value] V --> M[圈出數字<br/>時間、頻率、容忍度] M --> S[寫成 User Story] S --> T[補上可驗收條件]
一個能用的 User Story 長什麼樣
骨架其實就一句話:「身為 <角色>,我想要 <目的>,以便 <好處>。」 角色對應到上一篇的某個 persona,目的是他想做的事,好處說明為什麼值得做。
但這句話只是開頭。真正讓架構師能動工的,是後面那組驗收條件(acceptance criteria)——「成功長什麼樣」。寫驗收條件最常用的是 Given/When/Then 這種寫法,意思就是「給定某個前置狀態、當使用者做了某個動作、就該得到某個結果」。它原本是 BDD(Behavior Driven Development,行為驅動開發)在用的,但你不用管它的學派來歷,把它當成一個逼你把「成功」講清楚的格式就好。
舉個對比你就懂差別在哪:
- 「使用者可以快速看到商品」——這不是 user story,這是願望。快是多快?P95 還是平均?空庫存的商品要不要顯示?通通沒講。
- 「身為消費者,我想要在首頁 P95 1.5 秒內看到 Top 10 暢銷榜,以便快速決定要買什麼;庫存為零的商品仍要顯示但標註缺貨」——這才是能餵給下一步的東西。它有角色、有目的、有可以拿尺量的標準。
差別就在那個「可以拿尺量」。一個寫得好的 user story,到了下一篇定 SLO 的時候,你幾乎是把驗收條件裡的數字直接搬過去。寫得爛的,到那一步你還得回頭重猜一次需求。
流程圖暫時無法顯示。可先查看下方的流程與節點文字,或重新整理頁面後再試。
查看流程與節點文字
箭頭表示流程方向;方括號與引號內是節點名稱,可搭配下方圖解閱讀。
flowchart LR
A[一條驗收條件] --> Q1{能觀測或計時?}
Q1 -- 否 --> R1[把快、穩、即時<br/>改成數字或事件]
Q1 -- 是 --> Q2{包含失敗時行為?}
Q2 -- 否 --> R2[補逾時、重試、降級<br/>或衝突處理]
Q2 -- 是 --> Q3{沒有預先寫死產品?}
Q3 -- 否 --> R3[改寫成使用者成果]
Q3 -- 是 --> P[可交給 SLI/SLO 與架構設計]
R1 --> A
R2 --> A
R3 --> A 
角色、行動與價值只是骨架;P95、資料更新延遲與區域故障時的降級行為,才讓故事可以測試。驗收條件寫成數字與失敗結果後,快取、SLI、資料新鮮度和降級路徑就能被具體推導。
三種需要重寫的 user story
寫完 user story,可以先用下面三種情況檢查它是否真的描述了需求。
把解法寫成需求。 「用 Pub/Sub 接收訊息」「用 Memorystore 快取商品」已經指定產品,卻還沒說要解決什麼問題。先寫出使用者要完成的事、流量與時效要求,再比較工具;若產品是既有系統給定的限制,也要明確標成限制,而不是混進故事本身。
驗收條件太模糊。 「要快」「要穩」還不能拿來測試。可以補上量測位置、時間範圍與目標,例如「首頁的 P95 回應時間低於 1.5 秒」;這個數字仍要和使用者需求及現況比較後才算定案。
一個故事塞進太多成果。 「使用者可以購物」可能包含瀏覽、加購物車、結帳與查訂單。這些步驟的失敗代價和驗收方式不同,拆開後比較容易各自交付、量測與改善。切分依據是使用者能否得到一個完整成果,不是故事碰了幾個服務。
還有一種容易漏掉:非功能性的故事。寫 user story 時,通常會先寫「我想做什麼」,但使用者也在意「出問題時會怎樣」。例如「頁面不要等超過 5 秒」「付款失敗不能重複扣款」。把延遲、錯誤和重複請求寫進需求,架構設計才不會只顧到正常流程。
流程圖暫時無法顯示。可先查看下方的流程與節點文字,或重新整理頁面後再試。
查看流程與節點文字
箭頭表示流程方向;方括號與引號內是節點名稱,可搭配下方圖解閱讀。
flowchart TB
S[一條 User Story] --> M{包含多個獨立成果?}
M -- 是 --> D[按使用者價值垂直拆分]
M -- 否 --> F{不同步驟的失敗代價<br/>或 SLO 明顯不同?}
F -- 是 --> D
F -- 否 --> K[保留為單一故事]
D --> V[每個切片都有可驗收的成果<br/>與必要的失敗處理]
V --> K 
不要按前端、後端、資料庫橫切,而要沿著使用者價值切成小而完整的垂直片段。瀏覽、購物車、結帳與通知各自帶著 UI、API、資料及失敗行為,才能單獨交付並設定不同的驗收條件與 SLO。
走一遍範例 — 登雲書店
回到我們的主線。前面替每個 persona 畫好了輪廓,現在替他們寫出 5 個核心 user story。重點不在數量,在於每一條都帶著可以驗收的標準——因為這些標準,就是下一篇 SLO 的原料。
消費者阿元
故事 3.1 · 瀏覽暢銷榜
身為一般消費者阿元,我想要在首頁看到即時暢銷榜,以便快速決定要買什麼。
驗收條件:
- Given 我是未登入訪客,When 我打開首頁,Then P95 在 1.5 秒內看到 Top 10。
- 暢銷榜更新延遲不超過 15 分鐘。
- 區域故障時暢銷榜仍可顯示(可接受降級為前一次快照)。
注意第三條。這就是上面講的非功能性需求——它不講「我要看暢銷榜」,它講「就算機房出事,我還是要看得到」。一旦把這條寫進故事,你後面的架構就被逼著去想跨區降級、想快取舊資料頂著用,而不是讓整頁開天窗。
故事 3.2 · 下單結帳
身為一般消費者阿元,我想要用 Apple Pay 一鍵結帳,以便不用每次輸入信用卡。
驗收條件:
- 結帳流程從按鈕到完成不超過 6 秒(P95)。
- 結帳 API 可用性 99.99%。
- 付款失敗時金流不會重複扣款(idempotent,同一筆請求重送結果不變)。
- 所有交易紀錄符合 PCI DSS 4.0.1 稽核需求。
把 3.1 跟 3.2 擺一起看,差別就出來了:暢銷榜掛了你頂多少賺幾單,結帳掛了或重複扣款是直接出事、會上新聞。所以結帳的可用性訂到 99.99%,而且特別點名 idempotent 跟 PCI DSS。這就是為什麼前面堅持要把「購物」拆開——綁在一起,你根本沒辦法給結帳這種等級的嚴格度。
電子書訂閱者小葵
故事 3.3 · 同步閱讀進度
身為訂閱者小葵,我想要換裝置時自動跳到上次看到的頁面,以便通勤跟在家看可以順順接著讀。
驗收條件:
- 換裝置後 10 秒內看到最新進度。
- 同一本書在兩台裝置同時閱讀時,以最後一次 sync 為準。
- 離線時可繼續閱讀,重新上線後 30 秒內同步。
這裡有兩個需要說清楚的行為:兩台裝置同時更新進度時,以哪次同步為準;離線期間各自保留的進度,重新上線後如何合併。範例選擇 last-write-wins,但得定義「最後」依伺服器接收時間還是裝置時間判斷。離線可讀不代表後端只能採最終一致性;它要求的是用戶端能保留資料,並在恢復連線後處理同步與衝突。
書商合作夥伴天下出版
故事 3.4 · 每日批次上傳庫存
身為書商合作夥伴,我想要每天上傳一份庫存與價格的 CSV,並在 email 收到處理結果,以便知道價格是否成功更新。
驗收條件:
- 單筆 CSV 最大 200MB,處理時間 < 30 分鐘。
- 失敗時 email 包含失敗列號與原因。
- 庫存更新對消費者端可見的延遲 < 10 分鐘。
每日上傳 CSV、30 分鐘內完成處理、再寄出結果,適合先按批次工作規劃。不過驗收條件另寫了「庫存更新 10 分鐘內對消費者可見」,這比整批處理期限更緊;設計時要確認是每筆處理後立即更新,還是檔案完成後再一起發布,不能只看「每日」兩個字就忽略這段延遲要求。
內部營運分析師 Marcus
故事 3.5 · 查詢昨日銷售
身為分析師 Marcus,我想要用 SQL 直接查昨日所有訂單,以便製作每週行銷報表。
驗收條件:
- 資料新鮮度 D+1(每日 6am 前完成前一日資料的 ETL)。
- 查詢 4,000 萬筆訂單聚合不超過 30 秒。
- 僅能看到去識別化後的會員 ID。
Marcus 要的是「昨日」資料,用來做「每週」報表,屬於分析場景。若讓大量聚合查詢直接打在處理結帳的交易資料庫上,可能拖慢線上請求。題目給了「D+1」和「4,000 萬筆聚合」,就要評估獨立的分析資料儲存;「去識別化的會員 ID」則提醒你限制分析師能看到的個資。
把這 5 個故事擺在一起,你會發現它們不只是在描述功能,而是替後面每一個服務的 SLO 與行為先卡好位子:哪個要訂到 99.99%、哪個可以接受 15 分鐘延遲、哪個是批次、哪個碰個資要去識別化。下一篇定 SLO 的時候,你做的事情很大程度上就是把這裡的數字翻譯成可監控的指標。
📝 考場提點
比較方案前,先問兩個問題:資料要即時更新還是可批次處理?主要是線上交易還是分析查詢?這樣能避免讓大量報表查詢影響結帳資料庫,也不會為了隔天才需要的報表,平白增加即時處理的成本。
流程圖暫時無法顯示。可先查看下方的流程與節點文字,或重新整理頁面後再試。
查看流程與節點文字
箭頭表示流程方向;方括號與引號內是節點名稱,可搭配下方圖解閱讀。
flowchart LR
S[User Story] --> T{即時互動?}
T -- 是 --> W{線上交易?}
T -- 否 --> B{批次分析?}
W -- 是 --> O[低延遲 OLTP<br/>交易與冪等]
W -- 否 --> E[即時事件處理<br/>快取或串流]
B -- 是 --> A[批次 ETL+分析倉儲]
B -- 否 --> J[批次工作+佇列重試]
O --> C[再依驗收條件選服務]
E --> C
A --> C
J --> C 延伸閱讀
- Google Cloud Well-Architected Framework — Define reliability based on user-experience goals — 官方建議從使用者的實際體驗出發定義可靠度。
- SRE Book — Chapter 4 Service Level Objectives — SLI、SLO、SLA 的定義,以及怎麼從使用者在意的事挑選指標。
- Atlassian — User Story Examples — 結構與範例參考。
下一步:故事有了可以拿尺量的驗收條件,就能正式把它變成 SLO 與 SLI,讓期望成為可以監控、可以被告警叫醒的指標。
🎯 換你練習
理論讀完,換自己來。到 架構師設計工作坊 · 步驟 3 填入你的 case study,邊寫邊內化。
讀完後,留一個學習紀錄
試著用自己的話說出一個重點,以及你會如何運用。實作文章請先核對結果與清理資源,再標記為讀完。
文章進度以你確認讀完的標記為準,可隨時取消。舊版造訪紀錄保留,但不計入讀完;這份自評不代表已掌握內容。