<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>決策記錄 on Tarragon</title><link>https://tarrragon.github.io/blog/tags/%E6%B1%BA%E7%AD%96%E8%A8%98%E9%8C%84/</link><description>Recent content in 決策記錄 on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Thu, 11 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/%E6%B1%BA%E7%AD%96%E8%A8%98%E9%8C%84/index.xml" rel="self" type="application/rss+xml"/><item><title>SaaS 選型訪談方法論 - 從使用者操作推導到技術選型</title><link>https://tarrragon.github.io/blog/record/saas-selection-interview-methodology/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/record/saas-selection-interview-methodology/</guid><description>&lt;p>專案初始化的選型決策，常見的起手式是直接列工具名單：選哪個資料庫、要上 k8s 嗎、queue 用哪家。這個順序跳過了選型真正的依據——產品要提供使用者哪些操作、領域邊界怎麼切、哪種失敗的代價最高。SaaS 選型訪談方法論把順序反過來：從使用者操作推導功能、從功能推導領域結構、最後才到技術選型，並把整段推導包裝成一份可重複執行的結構化訪談協議。&lt;/p></description><content:encoded><![CDATA[<p>專案初始化的選型決策，常見的起手式是直接列工具名單：選哪個資料庫、要上 k8s 嗎、queue 用哪家。這個順序跳過了選型真正的依據——產品要提供使用者哪些操作、領域邊界怎麼切、哪種失敗的代價最高。SaaS 選型訪談方法論把順序反過來：從使用者操作推導功能、從功能推導領域結構、最後才到技術選型，並把整段推導包裝成一份可重複執行的結構化訪談協議。</p>
<h2 id="方法論要解的問題">方法論要解的問題</h2>
<p>這套方法論的核心命題是成本不對稱：設計問題拖到開發中途才浮現，修正的代價遠高於在訪談階段多問十題。沒想清楚的操作、沒切清楚的領域邊界、沒被告知的防護缺口，最後都會在開發中途以重工的形式收費。訪談協議的責任是逼這些設計問題在寫第一行程式之前、於已知需求的範圍內浮現——因此訪談問題的數量刻意不設上限，問漏才是成本；節奏上每輪三到五題讓受訪者好消化，輪數跟著覆蓋率走。</p>
<p>協議同時內建「產品名攔截」：受訪者開口指定產品（「我要用 MongoDB」「直接上 k8s」）時，先回到需求確認背後動機（schema 變動頻繁？團隊熟悉度？），需求成立後產品可以直接採納。產品名是選型的輸出，由需求與領域模型推導出來，而非訪談的輸入。</p>
<h2 id="推導鏈從定錨到決策記錄">推導鏈：從定錨到決策記錄</h2>
<p>整條推導鏈的設計邏輯是：每一站的產出都是下一站的輸入，技術問題永遠錨在前面站點的具體產物上，避免「對空氣選型」。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">定錨 → 交付形態 gate → 操作盤點（BDD）→ domain / event 切分（DDD）
</span></span><span class="line"><span class="ln">2</span><span class="cl">    → 核心問題與維度展開（每個維度就地過防護底線）→ 決策記錄 + scaffold</span></span></code></pre></div><p><strong>定錨</strong>。訪談從建立規模假設開始，定錨問題覆蓋七個面向：</p>
<ul>
<li>產品形態（B2B / B2C / 內部工具）——決定合規壓力與流量不確定性的預設方向</li>
<li>動機（營收、學習、解決自己的營運問題）——決策記錄理由欄的錨點，「自建換學習」「託管換速度」的權重都從這裡來</li>
<li>租戶模型——多租戶把租戶隔離升級成儲存與安全維度的第一級問題</li>
<li>預期規模（首年用戶與資料量級）——決定容量維度是否展開</li>
<li>團隊能力（人數、production on-call 經驗）——維運經驗低時預設 managed 服務，每個自管元件都要回答「誰半夜處理它」</li>
<li>每週可投入時數——一週十小時跟全職的選型分母不同</li>
<li>上線時程與迭代節奏——時程緊時選型偏保守，團隊熟悉度的權重高於技術新穎度</li>
</ul>
<p>定錨答案是後續每個推薦的合法依據——「因為團隊兩人且無維運經驗，推薦 managed 資料庫」這類理由都要能回指到定錨。</p>
<p><strong>交付形態 gate</strong>。定錨之後、進入任何技術討論之前，先誠實回答「這個產品現在值得自建嗎」。需求落在現成平台的標準域時，訪談走縮減流程：完整推導跳過，但仍產出託管縮減記錄——平台選擇與理由、可遷出保險狀態、升級自建的 tripwire、防護底線總表的適用項，託管結論同樣留下可追溯的決策記錄。這一站的判讀邏輯單獨成節，見「交付形態 gate」。</p>
<p><strong>操作盤點（BDD）</strong>。自建成立後，枚舉所有操作主體（含管理者、客服、訪客、機器角色）與其全部操作，每個操作寫行為情境——Given / When / Then 至少一條主情境加一條失敗情境。誤操作風險成對設計：前端引導（確認對話框、預設值、防呆）與後端防護（驗證、權限、idempotency）一一對應，從介面一路串到伺服器側。行為情境寫不出來，代表那個操作的需求還沒成形——在盤點階段攔下，比開發中途才發現便宜得多。</p>
<p><strong>Domain / event 切分（DDD）</strong>。操作清單沿固定方向轉成領域骨架：operation → command → 唯一歸屬 domain → event。推導從操作出發而非資料表出發——從資料表出發會切出 CRUD 式的偽領域（UserManager、OrderManager），從操作出發才會浮現真正的業務領域與領域間需要交換的事實。切分只用兩個原則：</p>
<ul>
<li><strong>SRP</strong>：一個 domain 一個變更理由、一個 event 一個事實。判讀問題包括「這兩個概念會因為同一個業務原因一起改嗎」「這個規則改變時誰說了算」——組織的決策邊界是領域邊界最誠實的線索。</li>
<li><strong>OCP</strong>：每個 domain 區分公開面（別的 domain 需要知道的：event schema、查詢介面）與內部面（表結構、狀態機、內部規則）。公開面是 contract、變更要盤點訂閱者；內部面可自由改。判讀問題是「Order domain 的表加一個欄位，要通知誰」——理想答案是「不用通知任何人」。</li>
</ul>
<p>LSP / ISP / DIP（里氏替換、介面隔離、依賴反轉）三個原則刻意留給實作階段：初始化階段還沒有 class 階層、沒有 interface 簇、沒有依賴注入結構，提前套用會把訪談拖進實作細節，模糊掉「邊界在哪」這個此階段的核心問題。</p>
<p><strong>核心問題與維度展開</strong>。領域骨架立好後，依序確認需求類型、流量形狀、資料生命週期、失敗代價、成本模型、定位與備援、安全邊界。每題附答案路由：訊號決定哪些技術維度要展開（快取、非同步佇列、容量），哪些維度任何 production 服務都逃不掉（儲存、部署、安全、觀測、可靠性）。</p>
<p>展開時問題錨在領域骨架上——「Order domain 的不可丟 event 用什麼機制送」，而非抽象的「要不要 queue」。每站也帶反向問，因為受訪者描述的是想要的功能，沒想到的東西藏在失敗面：「使用者做完馬上後悔怎麼辦」「凌晨三點服務掛了誰會知道」。</p>
<p><strong>防護底線</strong>。每個維度附一份防護底線清單——底線的定義是「缺了它、第一次事故的代價會遠超過 day one 建立它的成本」的項目，例如 secret 管理、備份加至少一次還原驗證、物件層級授權、部署可回滾。底線跟選型的差別在答案空間：選型問題容許多個合理答案並存，底線項目只有「已納入」「已告知後延後」「不適用」三種合法狀態，每一項的狀態都要寫進決策記錄。延後必須轉成記錄：告知代價、記下延後理由、附具體的重評條件（「上線前」「第一個付費客戶前」），「之後再說」這種無期限的口頭妥協會被協議擋下。目的是讓六個月後接手的人能回答「當初為什麼沒做」，把口頭妥協變成可追溯的決策。底線在訪談中經過兩次——維度展開時就地逐項過，決策記錄的總表再核對一次；雙重核對是刻意設計，防止任何一條在長流程中被沉默跳過。</p>
<p><strong>決策記錄</strong>。訪談收斂成一份決策記錄：操作風險表、domain map、event catalog、每項技術選型的理由 / 防護狀態 / <a href="/blog/backend/knowledge-cards/tripwire/" data-link-title="Tripwire" data-link-desc="說明風險決策在條件變化時如何自動回到評估流程">tripwire</a> 三欄齊備、防護底線總表、規模成長 tripwire 總表。被淘汰的次選項留名字——淘汰原因消失（例如團隊長出維運能力）就是重評入口。scaffold 建議是決策記錄的下游：先確認決策、再產生檔案，決策改了 scaffold 跟著重生。</p>
<h2 id="交付形態-gate先勸退不必要的自建">交付形態 gate：先勸退不必要的自建</h2>
<p>一套為自建選型而生的訪談協議，第一個正式任務是勸退不必要的自建。自建的前提是差異化在軟體本身；差異化在商品、內容或服務品質的業務，託管平台、<a href="/blog/backend/knowledge-cards/baas/" data-link-title="BaaS（Backend as a Service）" data-link-desc="說明把認證、資料庫、檔案儲存、推播打包成現成模組、由前端 SDK 直連的後端交付形態">BaaS</a>、垂直 SaaS 可能是成本上更誠實的起點。跳過這個判斷，等於用整套自建流程回答一個本來就該用現成平台解的需求。交付形態光譜的完整論述（各形態的能力邊界、遷出代價、可遷出保險）見 <a href="/blog/backend/00-service-selection/delivery-mode-selection/" data-link-title="0.21 交付形態選型：從全託管到自建的光譜與邊界" data-link-desc="在進入資料庫、快取與部署選型之前、先判斷服務該用託管平台（Wix / Shopify / Google Sites）、辦公生態自動化（Apps Script）、BaaS（Firebase）、半託管 CMS（WordPress）還是自建、並為日後遷往自建保留可遷出路徑">交付形態選型：託管平台、BaaS 與自建的邊界</a>，訪談協議把它操作化成 gate。</p>
<p>gate 的第一個澄清問是身分問題：這個軟體是要賣的產品，還是經營業務的工具？「給健身教練用的課表系統」有兩種身分——要賣給眾多教練的產品（市場上的垂直 SaaS 是競爭對手，走自建），或教練管理自己學員的工具（同一批垂直 SaaS 正是該優先評估的託管候選）。同一句需求描述，兩種身分的結論相反。</p>
<p>回答「先自用、之後想賣」的雙重身分，用時間判準裁決：<strong>付費外部用戶離現在多遠</strong>。協議把裁決寫成兩條規則：外部買家已有承諾或近期有交付時程的，按「要賣的產品」走完整訪談，自家使用記為首租戶（dogfooding）；外部用戶還停在想像、目前唯一用戶是自己的，託管先行，平台野心轉成升級自建的 tripwire——協議給的觸發例是第一個付費外部用戶出現，或客製需求超出託管平台 API 的承載範圍。</p>
<p>gate 的收尾原則是尊重知情決定：受訪者聽完託管對照後仍選自建時，訪談照常繼續，勸退只做一次；選自建的動機（練手、控制權、長期成本）原樣記進決策記錄，讓未來重評者能還原當時的權重。</p>
<h2 id="用合成-dry-run-驗證協議">用合成 dry-run 驗證協議</h2>
<p>方法論本身也需要驗證。這套協議以一組結構化文件存在——訪談流程、各站的判讀表、決策記錄模板都是 agent 可直接執行的文件，驗證因此可以採用合成 dry-run：讓 agent 同時扮演訪談者與 persona 受訪者，從定錨到決策記錄完整走一遍協議，過程中記錄機械性斷點。斷點分五類：</p>
<ul>
<li><strong>路由斷裂</strong>：協議指向的段落不存在，或前後站接不上</li>
<li><strong>gate 矛盾</strong>：兩條判讀規則同時命中且結論相反，協議沒給裁決方式</li>
<li><strong>重複提問</strong>：同一風險在不同階段被當成新問題重新開放問</li>
<li><strong>資訊斷流</strong>：前站的產出（操作清單、event catalog）沒被後站引用</li>
<li><strong>判準缺席</strong>：協議要求做判讀，但沒給可操作的判讀條件</li>
</ul>
<p>dry-run 收尾時實際試填決策記錄模板，量測每個欄位填得出來的比例——填不出來的欄位就是協議在某一站漏問了。</p>
<p>第一輪驗證跑了兩個 persona：一個雙重身分的健身房管理 SaaS（自用兼想賣），一個 solo 開發者的付費電子報（最該被勸退自建的案例）。合計記錄 13 個斷點，在兩個 persona 覆蓋的路徑上路由斷裂為零——協議的檔案結構與觸發路由都接得起來；決策記錄試填率約 85-90%，缺口集中在交付形態相關欄位：gate 判讀依據寫不出來、混合形態的記錄格式沒有規格、自建動機沒有欄位可放。影響最大的斷點是兩個 persona 從不同方向撞上同一個 gate 矛盾：判讀表兩列規則同時命中且方向相反——健身房的「都是」讓垂直 SaaS 列與自建列並立，付費電子報既符合「託管平台標準域」也符合「產品本身是軟體」——協議當時沒有 tie-breaker，在最該被勸退的案例上這個斷點被評為阻斷級；前文的時間判準正是這次修復補上的。矛盾發生在協議最核心的判斷上，且在真實使用者撞到之前被攔下。兩場 dry-run 最終收斂出 8 項修復回寫協議，包括雙重身分的時間判準、混合形態的決策記錄規格、訪談問句去重、跨 domain 寫入的一致性判讀條件。</p>
<p>合成 dry-run 的邊界也要誠實：它抓得到機械性斷點，抓不到真實受訪者的不耐與理解斷層。agent 扮演的 persona 永遠有耐心答完所有問題、永遠聽得懂術語；真實使用者在第四輪提問時的疲乏、對「event catalog」一詞的困惑，要等真人訪談才會浮現。另一層盲點是同源：persona 由產生協議的同一個模型扮演，回答分布偏向協議作者想像得到的案例，超出這個想像的需求形態，結構上不會出現在合成驗證裡。合成驗證的定位是上線前的結構檢查，取代不了真實使用回饋。</p>
<h2 id="適用邊界與下一步">適用邊界與下一步</h2>
<p>完整協議的固定成本是數輪訪談加一份決策記錄，值得跑的情境有明確輪廓：</p>
<ul>
<li>產品會進 production，有真實使用者與失敗代價——失敗代價是核心問題階段的主要輸入，沒有它整條推導鏈失去分水嶺</li>
<li>團隊規模或交接需求讓「當初為什麼這樣選」值得被記錄——決策記錄的三種讀者（確認結論的現在使用者、回溯理由的未來維護者、等訊號的重評者）至少存在兩種</li>
<li>領域邊界有切分價值——操作主體超過一種、跨領域協作存在，domain / event 切分的產出才有承載對象</li>
</ul>
<p>反過來，快速原型與純內部腳本跑完整協議是過度設計——原型的目的是丟棄式驗證假設，設計決策活不過原型本身；這類情境取協議的最小子集就夠：定錨（確認規模假設）加防護底線裡的 secret 管理一條。另一類邊界是需求不可知：產品會進 production、但要提供哪些操作得靠市場驗證才知道的探索型產品，協議能整理的只有已知部分——它解「已知需求沒想清楚」的成本，解不了「需求本身未知」；這類情境先走薄切片迭代，需求穩定後再回來補完整訪談。</p>
<p>判讀方式可以收成一個問題：這個專案的設計決策，六個月後有人需要回答「當初為什麼這樣選」嗎？需要，完整協議的固定成本就划算；無此需求，取子集。</p>
<p>下一步路由：</p>
<ul>
<li>交付形態光譜與各形態的遷出代價：<a href="/blog/backend/00-service-selection/delivery-mode-selection/" data-link-title="0.21 交付形態選型：從全託管到自建的光譜與邊界" data-link-desc="在進入資料庫、快取與部署選型之前、先判斷服務該用託管平台（Wix / Shopify / Google Sites）、辦公生態自動化（Apps Script）、BaaS（Firebase）、半託管 CMS（WordPress）還是自建、並為日後遷往自建保留可遷出路徑">交付形態選型</a></li>
<li>判定自建後的服務選型順序：<a href="/blog/backend/00-service-selection/backend-demand-taxonomy/" data-link-title="0.0 後端需求分類地圖" data-link-desc="先從需求形狀辨識狀態、讀取、非同步、即時、診斷、交付與可靠性問題">後端需求分類地圖</a></li>
<li>不可丟 event 的執行層機制：<a href="/blog/backend/knowledge-cards/idempotency/" data-link-title="Idempotency" data-link-desc="說明同一操作執行多次時如何保持結果一致">idempotency</a> 與 <a href="/blog/backend/knowledge-cards/outbox-pattern/" data-link-title="Outbox Pattern" data-link-desc="說明資料庫狀態變更與事件發布如何透過 outbox 維持一致">outbox pattern</a> 知識卡</li>
</ul>]]></content:encoded></item></channel></rss>