🎯 什麼情境該想到我

當你「有一個需要多個步驟的處理流程,想把每步拆成獨立、可重組、可重用的小元件」的時候。

⚙️ 怎麼用(步驟 / 公式)

意圖:把一個複雜的處理,拆成一連串各自獨立的處理步驟(過濾器),用通道(管道)串接起來。

做法 / 結構要點:

  • 每個 過濾器(Filter) 只負責一件事,從輸入通道收訊息、處理後寫入輸出通道。
  • 管道(Pipe) 就是連接兩個過濾器的訊息通道。
  • 過濾器彼此只透過管道相連、互不知情,因此可自由增減、重排、替換、平行化。

★★ 這個模式的核心紀律:每個過濾器只認識「通道」,不認識彼此

Order ──▶ [驗證] ──▶ [補資料] ──▶ [計稅] ──▶ [出貨]
           ↑ 每一段都是「同一種介面:吃訊息、吐訊息」

★ 所以你可以任意重排、插入、移除一段,而不必改其他段。
這正是 裝飾者模式/middleware 在行程內的同一個想法——
★ 差別只在「邊界是函式呼叫還是訊息通道」。

★ Go 的三種實作,成本差三個數量級

// ① ★ 行程內:函式組合(middleware)—— 零基礎設施成本
type Filter func(context.Context, Order) (Order, error)
 
func Chain(fs ...Filter) Filter {
    return func(ctx context.Context, o Order) (Order, error) {
        var err error
        for _, f := range fs {
            if o, err = f(ctx, o); err != nil { return o, err }   // ★ 任一段失敗就停
        }
        return o, nil
    }
}
pipeline := Chain(validate, enrich, calcTax)
 
// ② 行程內、非同步:goroutine + channel
//    ★ 每段一個 goroutine,用 channel 串起來 —— 可以各自並行
//    ⚠️ 但行程死了資料就沒了,而且沒有重試(見 [[工具-靠通訊共享記憶體]])
 
// ③ ★ 跨行程:每段一個服務,用真的 MQ 串
//    ★ 代價:N 個部署單元、N 個佇列要監控、除錯要跨服務追 trace

★★ 判準:這些階段需要「各自獨立擴展」或「各自獨立失敗」嗎?
不需要 → 選 ①。一個函式鏈就是管道與過濾器,而且好測十倍。
需要(某一段特別慢、特別容易掛、要用不同語言寫)→ 才升級到 ③。

⚠️ 最常見的過度設計:把五個純計算步驟拆成五個服務、四個佇列。
那不是「管道與過濾器」的勝利,是把一個函式鏈換成一個分散式系統。

★ 跨行程管道的三個真實代價

① ★ 延遲相加,而且每一跳都有排隊
   五段 × (網路 + 排隊 + 處理) → p99 會比單體高一個數量級

② ★★ 中間狀態沒有交易性
   第 3 段成功、第 4 段失敗 → 訊息重送會讓第 3 段重跑
   → ★ 每一段都必須冪等([[冪等接收者]])

③ ★ 除錯需要端到端追蹤
   「這筆為什麼停在第 3 段」→ 沒有 correlation id 就查不出來
   → ★ trace id 必須貫穿所有段([[訊息歷史]]、[[工具-遙測與監控]])

★ 兄弟辨析

差別
路由單★ 路徑寫在訊息裡(每則訊息可以走不同順序);管道的順序是固定的拓撲
流程管理器★ 有一個中央協調者持有狀態,可以分支、等待、補償;管道是線性無狀態的
組合訊息處理器拆開 → 各自處理 → 合回;管道不拆分
以管道取代迴圈同一想法在單一函式內的版本(⚠️ 在 Go 裡多半不該做)
拆分階段同一想法在單一函式內、且只切兩段並產生中間型別

★ 什麼時候不要用

  • ★ 步驟之間需要看到彼此的中間狀態(第 4 段要用第 1 段的原始輸入)→ 那不是管道,
    硬做會讓訊息帶著一路累積的 原始輸入 欄位。
  • ★ 需要分支/條件路徑/等待多方 → 流程管理器。
  • 只有兩段,而且不會變 → 直接一個函式。
  • 需要整體原子性 → 一個資料庫交易。

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 步驟切太細會增加通道與序列化開銷,並讓整體延遲與除錯變複雜。

  • 這是本書許多路由/轉換模式共用的底層架構觀點,而非具體某個元件。

  • ★★ 「管道與過濾器」不代表要拆成多個服務。行程內的函式鏈就是這個模式,而且好測十倍。

  • ★ 跨行程版的代價:延遲相加、中間狀態無交易性、除錯要跨服務追 trace。

  • ★ 每一段都必須冪等。第 4 段失敗導致重送時,前面幾段會重跑。

  • ★ 步驟之間需要看到彼此的中間狀態 → 切點錯了。訊息會長出一路累積的欄位。

  • 需要分支、等待、補償 → 用 流程管理器,不要硬塞進線性管道。

  • ★ 過濾器的順序是隱性契約。「補資料必須在計稅之前」如果只存在於部署設定裡,遲早會被人改錯——寫進文件與測試。

  • 中間通道要監控積壓。管道裡任一段變慢,前面的通道就會堆積。

🔗 相關工具