Skip to content

Product Builder 面試日練 — 2026-09-12:Technical PM

2026年9月12日1 分鐘
TL;DRTechnical PM 題最常見的失分點,是把技術判斷講成「工程說了算」或「我全部自己決定」,講不出怎麼把決策過程開放給團隊、又不失去方向。今天用 RFC 流程收斂多方意見、用 Architecture Decision Record 留下決策的來龍去脈,再練一道「合作夥伴系統逾時後自動重試,造成重複下單」的 API 設計題——怎麼設計讓重試變安全,又怎麼知道修好了。案例是 Stripe 的 Idempotency-Key header:同一個問題,他們在支付 API 上已經解了十年,至今仍是這類題目最常被拿出來對照的答案。
目錄
  1. 今日主題
  2. 核心框架速記
    1. RFC 流程(Request for Comments)
    2. Architecture Decision Record(ADR)
  3. 今日練習題
    1. 題目
    2. 拆解思路
    3. 範例回答(面試時可以這樣講)
    4. 自我核對清單
  4. 今日案例
  5. 延伸閱讀
  6. 參考資料

🌏 English version

今日主題

Technical PM 這輪考的不是「你懂不懂技術」,而是你能不能在一個具體的系統限制裡,主導出一個工程團隊會接受、且半年後還看得懂為什麼這樣決定的方案。多數人講這類題目容易停在兩個極端——「這個我不懂,交給工程判斷」或「我自己拍板,工程照做」——面試官接下來一定會問「那你怎麼讓一個不同意的資深工程師點頭」。

今天用 RFC 流程把技術決策開放給團隊評論、收斂分歧,再用 Architecture Decision Record(ADR)把決策的理由寫下來,讓 Technical PM 題不再只是喊「我很懂技術」,而是有具體的協作機制和可追溯的紀錄。

核心框架速記

RFC 流程(Request for Comments)

技術決策不是一個人在會議室裡拍板,而是用一份文件把方案攤開,讓所有會被影響的人在文件裡把分歧講清楚:

階段做什麼Technical PM 的角色
起草寫清楚問題、目標、限制,至少列兩個方案的取捨主筆或跟工程 lead 共筆,把商業限制翻譯成技術限制的語言
開放評論設一個固定期限(例如 3-5 天),讓所有 stakeholder 都能留言主動標記會被影響的下游團隊,不是等他們自己發現
收斂決策對每條有分歧的評論回覆立場,不是全部照單全收判斷哪些是個人偏好、哪些是真的風險,不能各打五十大板
定案與公告標記狀態為 accepted,回寫成一份 ADR確保決策有可追溯的紀錄,不是散落在聊天訊息裡

常見失誤:把 RFC 當成蓋橡皮章的形式流程——評論期沒人真的看,或主導者迴避處理有分歧的評論,決策最後靠會議室裡的權力關係定案,而不是文件裡的論證。

Architecture Decision Record(ADR)

ADR 的目的是留下「為什麼」,不是「做了什麼」——讓半年後的人(可能是你自己)看得懂當時的取捨。Michael Nygard 在 2011 年提出的四段式格式,今天仍是業界標準:

  1. Context:當時的限制是什麼,為什麼這個決定現在非做不可
  2. Decision:做了什麼決定,用一句話講清楚
  3. Status:proposed / accepted / superseded——決定不是永久的,可以被之後的 ADR 取代
  4. Consequences:這個決定帶來的好處跟代價,包含之後可能會後悔的地方

常見失誤:只寫 Decision 那一段,沒寫 Context 跟 Consequences——半年後沒人知道當時為什麼沒選另一個方案,同樣的辯論會重新發生一次。

今日練習題

題目

「你負責一個 B2B 平台的訂單 API。合作夥伴的系統在呼叫下單 API 時,如果在逾時前沒收到回應,會自動重試同一個請求。上線後你發現,部分合作夥伴因為這個重試機制造成重複下單,客訴開始增加。你會怎麼設計 API 讓重試變安全,又要怎麼知道這個修復真的有效?」

(題型:API 設計/技術權衡題;自擬 based on Technical PM 面試題庫中常見的重試/重複下單情境)

拆解思路

  1. 釐清問題:先問清楚重試發生在哪一層——是合作夥伴的 SDK 自動重試,還是他們自己寫的重試邏輯?逾時的時間窗口多長?目前 API 有沒有任何去重機制,還是完全沒有?
  2. 定義使用者:這裡的使用者是整合這個 API 的合作夥伴工程團隊,不是終端消費者。要理解他們的限制——多數合作夥伴沒辦法馬上改自己的重試邏輯,方案要在「不要求對方配合太多」的前提下解決問題。
  3. 結構化分析:核心問題是伺服器要能分辨「同一個邏輯請求的第二次嘗試」跟「使用者真的想再下一筆訂單」。這需要決定:去重的識別鍵放在哪裡、有效期多長、儲存在哪裡,以及「識別鍵一樣但內容不一樣」這種矛盾情況怎麼處理。
  4. 提出方案:要求呼叫端在請求標頭帶一個 Idempotency-Key,伺服器在一段時間內(例如 24 小時)快取這個 key 對應的處理結果——同一個 key 重試時直接回傳原本的結果,不重新執行下單邏輯;如果同一個 key 但請求內容不同,回傳明確的錯誤,而不是默默用新內容覆蓋。
  5. 定義成功:上線後追蹤「重複下單客訴數」和「因逾時重試產生的支援工單量」有沒有下降,同時要盯著 API 平均延遲有沒有因為多了一次查詢快取而上升——修好一個問題、拖慢所有請求,不算真的解決。

範例回答(面試時可以這樣講)

釐清問題:「我會先確認重試發生在哪一層——是合作夥伴用的官方 SDK 內建自動重試,還是他們自己寫的邏輯?逾時窗口設多長?現在的 API 完全沒有去重機制,還是有但沒處理好這個情境?這會決定我是要教育合作夥伴改重試邏輯,還是把去重責任整個收回到我們這邊。」

方案設計:「我傾向把責任收回到 API 這一層,因為要求所有合作夥伴同時改自己的重試邏輯不現實。具體做法是要求每個下單請求帶一個 Idempotency-Key,伺服器收到後先查這個 key 有沒有處理過——處理過就直接回傳原本的結果,不會再跑一次下單邏輯;如果同一個 key 帶著不一樣的訂單內容進來,我會回傳一個明確的錯誤,而不是猜測使用者的意圖,因為猜錯的代價比要求對方重新確認更高。」

成功定義與風險:「上線後我會盯兩個指標——重複下單客訴數,還有因為逾時重試產生的支援工單量,這兩個應該要往下降。但我也會盯 API 平均延遲,因為多了一次去重查詢,如果延遲明顯上升,代表我們用效能換正確性換得不划算,要重新設計儲存方式,而不是接受這個代價。這個決定我會寫一份 ADR,記錄為什麼選擇伺服器端去重而不是要求合作夥伴改重試邏輯,免得半年後有新人又想重新討論一次。」

自我核對清單

用這張表檢查你的回答有沒有漏掉關鍵點:

核對項目有提到?
區分「網路層重試」跟「使用者真的想再下一筆」這兩種情況
提到識別鍵(idempotency key)的生命週期與儲存設計
講清楚「識別鍵相同但內容不同」時怎麼處理,而不是默默覆蓋
定義了具體的成功指標(客訴數、工單量)
有考慮到方案對延遲/效能的影響,不只看正確性
加分項:提到用 RFC 或 ADR 跟工程團隊溝通這個決策,留下可追溯的紀錄

今日案例

Stripe:用 Idempotency-Key header 讓支付 API 的重試變安全

Stripe 在自家 API 文件裡明確要求:呼叫端在請求標頭放一個 Idempotency-Key(建議用 V4 UUID 或其他有足夠隨機性的字串),伺服器用這個 key 辨識「這是同一個邏輯請求的重試」還是「一筆新的請求」。Stripe 在 2017 年發表的技術部落格〈Designing robust and predictable APIs with idempotency〉說明,他們官方的 Ruby 函式庫甚至內建了自動重試機制,搭配 idempotency key 使用指數退避與 jitter 的重試時間——因為在支付這個場景,「重複扣款」的代價遠比「多等一秒鐘」高得多。這套設計至今仍是 Stripe API 的核心機制,寫在現行的官方文件裡。

面試連結:這個案例是「合作夥伴逾時重試造成重複下單」問題的真實答案版本,可以直接拿來回答「舉一個 API 設計如何處理重試安全的例子」,或用來檢驗自己剛才的方案是不是重新發明了 Stripe 已經驗證過的模式。重點不是背 Idempotency-Key 這個名詞,而是講清楚為什麼「代價不對稱」(重複扣款代價 vs. 多一次確認的代價)決定了要把去重責任收回伺服器端,而不是留給合作夥伴自己處理。

延伸閱讀

參考資料