跳至主要內容
PCA 雲端架構師之旅 — 第 3/13 篇

PCA 雲端架構師之旅 03 — 撰寫 User Stories

內文字級

PCA 雲端架構師之旅 03 — 撰寫 User Stories
更新:2026-10-12

上一篇把人畫出來了——你知道阿元是誰、小葵在意什麼。但 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
合格的驗收條件必須可量測、描述失敗結果,而且只固定需求、不預先綁死解法。
把使用者希望首頁很快的模糊故事,改寫成角色、行動、價值以及 Given When Then、P95、資料新鮮度與故障降級等可驗收條件

角色、行動與價值只是骨架;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
先判斷即時或批次,再分交易或分析;這兩刀先切乾淨,服務選型才不會把 OLAP 壓力放進 OLTP 路徑。

延伸閱讀


下一步:故事有了可以拿尺量的驗收條件,就能正式把它變成 SLO 與 SLI,讓期望成為可以監控、可以被告警叫醒的指標。

🎯 換你練習

理論讀完,換自己來。到 架構師設計工作坊 · 步驟 3 填入你的 case study,邊寫邊內化。

PCA 雲端架構師之旅 — 第 3 篇/共 13 篇 查看系列全覽 →

讀完後,留一個學習紀錄

試著用自己的話說出一個重點,以及你會如何運用。實作文章請先核對結果與清理資源,再標記為讀完。

文章進度以你確認讀完的標記為準,可隨時取消。舊版造訪紀錄保留,但不計入讀完;這份自評不代表已掌握內容。

留言討論

文章目錄與系列

徽章解鎖!