Contracts#

在軟體架構中,有一個跨越所有面向的常數因素:contracts(契約)。Contract 廣義定義為架構中不同部分之間的連接方式。

Hard parts contract 的定義:架構中各部分用來傳遞資訊或依賴關係的格式。

這個定義涵蓋了所有用來「連接」系統各部分的技術,包括框架和函式庫的 transitive dependency、內部和外部整合點、cache,以及各部分之間的任何通訊。

Figure 13.1: Three-dimensional intersecting space for messaging forces in distributed architectures

Strict Versus Loose Contracts#

契約不是二元選擇,而是一個從嚴格到鬆散的光譜

Figure 13.2: The spectrum of contract types, from strict to loose

  • Strict 端:XML Schema、JSON Schema、Object、RPC(含 gRPC)
  • 中間:GraphQL、REST
  • Loose 端:Value-driven contracts、Simple JSON、KVP arrays(maps)

Strict contract 要求嚴格遵守名稱、型別、順序等所有細節。最嚴格的例子是 Java 的 RMI——遠端呼叫模仿內部方法呼叫,匹配名稱、參數、型別等。gRPC 也是預設為 strict contract 的流行框架。

  • Strict contract 模仿內部方法呼叫的語意
  • 但 strict contract 會在整合架構中產生脆弱性——頻繁變動的契約會連帶影響其他服務

Loose contract(如 name-value pairs)只包含最基本的資訊,沒有額外的 metadata 或型別資訊。

  • 鬆散契約允許極度解耦的系統
  • 但缺乏契約確定性、驗證能力,需要更多應用程式邏輯

GraphQL 的用途:提供唯讀的聚合資料,不同消費者可取得同一資源的不同 view。例如 Customer Wishlist 只需要 name,而 Customer Profile 需要完整地址資訊。

契約應保持在「need to know」的層級——在語意耦合和必要資訊之間取得平衡,避免無謂的脆弱性。

Trade-Offs Between Strict and Loose Contracts#

Strict contracts 的優缺點

優勢劣勢
Guaranteed contract fidelity:schema 驗證確保精確遵守Tight coupling:契約變更時雙方都必須改動
Versioned:支援版本策略管理演進Versioned(也是劣勢):版本過多可能成為整合噩夢
Easier to verify at build time:可在建置時進行型別檢查
Better documentation:明確的參數和型別消除歧義

Loose contracts 的優缺點

優勢劣勢
Highly decoupled:最低程度的耦合,最高靈活性Contract management:可能出現拼寫錯誤、遺漏等問題
Easier to evolve:實作可更自由地演進Requires fitness functions:需要 consumer-driven contract 等機制來確保契約正確性

Contracts in Microservices#

架構師必須不斷決定服務如何互動:傳遞什麼資訊(語意)、如何傳遞(實作)、以及耦合的緊密程度。

Coupling Levels#

兩種方式讓需要共享資訊的微服務(如 Customer Address)互動:

Figure 13.3: Two services that must share domain information about the customer

  • Strict approach:使用同一技術堆疊的 RPC 協議(如 RMI、gRPC),契約可信度高但耦合緊密
  • Loose approach:每個服務有自己的 Customer 內部表示,使用 name-value pairs 傳遞資訊

Loose coupling 的好處:

  • 各服務在 bounded context 後高度解耦,可獨立演進內部表示
  • 即使團隊換技術平台也不影響另一方
  • Name-value pairs 是所有平台都能處理的 lingua franca

Figure 13.4: Microservices with their own internal semantic representation can pass minimal info

Consumer-Driven Contracts#

解決 loose coupling 和 contract fidelity 看似矛盾的需求。

  • 傳統模式是 push model:provider 決定發出什麼資訊
  • Consumer-driven contract 是 pull model:consumer 定義自己需要什麼,將契約交給 provider
  • Provider 將契約測試納入 CI/CD pipeline,確保契約始終滿足
  • 多個 consumer 各自定義不同契約,provider 必須全部滿足

Figure 13.5: Consumer-driven contracts allow the provider and consumers to stay in sync

Consumer-driven contracts 的取捨

優勢劣勢
服務間最低耦合的契約需要工程成熟度和紀律
允許嚴格度的可變性需要兩種互鎖機制而非一種
可演進(Evolvable)

Stamp Coupling#

Stamp coupling 是在服務間傳遞大型資料結構,但每個服務只使用其中一小部分的模式。常見於產業標準文件格式(如旅遊業的 XML itinerary)。

  • 可能是有意的模式,也可能是無意的反模式

Figure 13.6: Stamp coupling between four services

Over-Coupling via Stamp Coupling#

以 Wishlist Service 和 Profile Service 為例:

  • Wishlist 只需要 name(透過 unique ID 存取),但契約卻包含 Profile 的所有欄位
  • 若 Profile 變更了 Wishlist 不關心的欄位(如 state),仍然會破壞契約
  • 這是過度耦合的反模式——為了「以防萬一」而過度指定契約中的細節

Figure 13.7: The Wishlist Service is stamp coupled to the Profile Service

Bandwidth#

另一個常見問題與分散式計算的經典謬誤有關:bandwidth is infinite

  • 在單體系統中方法呼叫的大小無關緊要,但在分散式架構中會產生實際問題
  • 範例:若每個 payload 500 KB,2,000 requests/sec 就產生 1,000,000 KB/sec 的頻寬需求
  • 若只傳遞必要資訊(如 name 200 bytes),開銷降至合理的 400 KB/sec

Stamp Coupling for Workflow Management#

Stamp coupling 也有正面用途——用於工作流程管理

  • 架構師在契約中加入工作流程資訊(如狀態、交易狀態等)
  • 每個服務更新契約中屬於自己的部分,再傳給下一個服務
  • 消費者可查看契約來判斷工作流程狀態,無需查詢每個服務
  • 若系統需要交易一致性,服務可將契約重新廣播給先前造訪的服務以恢復一致性

Figure 13.8: Using stamp coupling for workflow management

Stamp coupling 用於工作流程管理的取捨

優勢劣勢
允許 choreography 中的複雜工作流程在協作者間產生(可能是人為的)高耦合
高規模時可能產生頻寬問題

Sysops Squad Saga: Managing Ticketing Contracts#

團隊討論 ticket 管理工作流程中的契約類型:

Figure 13.9: Types of contracts between collaborators in the ticket management workflow

  • Orchestrator ↔ Ticket Management / Ticket Assignment:使用 tight contract,因為資訊高度語意耦合,變更頻率一致
  • Orchestrator ↔ Notification Service / Survey Service:使用 loose contract,因為這些服務的資訊變更較慢,不需要緊密耦合
  • Orchestrator ↔ Mobile Application(Sysops Expert):使用 loose contract(name-value pairs),因為行動應用需透過 app store 部署,更新審核時間長,鬆散契約提供靈活性

ADR: Loose Contract for Sysops Squad Expert Mobile Application

Context:Sysops Squad 專家使用的行動應用必須透過公共 app store 部署,契約更新受限。

Decision:使用 loose 的 name-value pair 契約在 orchestrator 和行動應用之間傳遞資訊,並建立擴展機制以允許短期彈性。

Consequences:若 app store 政策允許更快(或持續)部署,應重新審視此決策。Orchestrator 和行動應用需包含更多契約驗證邏輯。