Alistair Cockburn 在 2005 年提出 Hexagonal Architecture,他用的詞是 Ports & Adapters——這個名字比「六邊形架構」更直接說明了它要解決的問題。

問題是這樣的:你的業務邏輯(domain core)被各種外部細節包圍著——HTTP 框架、資料庫、外部 API、訊息佇列。這些外部依賴讓 domain 很難獨立測試:測一個訂單折扣規則,你要先起一個 HTTP server、連一個資料庫、設定一個 mock 的外部付款 API。

Hexagonal Architecture 的答案是:把所有外部依賴推到系統的邊緣,讓 domain core 完全不知道它們的存在。


Ports 和 Adapters 是什麼

Port(埠口) 是 domain core 定義的介面——「我需要這種能力,但我不管你怎麼實作」:

  • OrderRepository(一個介面):「我需要能存取訂單的能力」
  • PaymentGateway(一個介面):「我需要能收付款的能力」
  • NotificationService(一個介面):「我需要能發通知的能力」

這些介面定義在 domain 層,domain 只依賴這些介面,不依賴任何具體實作。

Adapter(適配器) 是外部世界和 domain 之間的橋樑——具體實作了 port 的介面:

  • PostgresOrderRepository implements OrderRepository:用 PostgreSQL 實作訂單存取
  • StripePaymentGateway implements PaymentGateway:用 Stripe 實作收付款
  • SendGridNotificationService implements NotificationService:用 SendGrid 發通知

Adapter 知道外部細節(SQL、Stripe API、SMTP),domain 不知道。


兩類 Port:Driving 和 Driven

Port 分兩個方向:

Driving Port(主動埠):外部呼叫 domain 的介面。HTTP Controller 把請求翻譯成 domain 能理解的呼叫;CLI 指令、GraphQL resolver、message consumer 都是 Driving Adapter。Domain 不知道是誰在呼叫它,只知道收到了什麼輸入。

Driven Port(被動埠):Domain 呼叫外部的介面。OrderRepositoryPaymentGateway 是 Driven Port——domain 主動要求這個能力,由外層的 Adapter 提供。

HTTP Request
    ↓
[HTTP Adapter](Driving)
    ↓
[Domain Core]
    ↓
[OrderRepository Port](Driven)
    ↓
[PostgresAdapter](Driven Adapter)
    ↓
PostgreSQL

Domain core 在中間,完全不知道左邊的 HTTP 和右邊的 PostgreSQL。


跟 Clean Architecture 的關係

Clean Architecture(Uncle Bob)和 Hexagonal Architecture 解決的是同一個問題,共享同一個核心想法:依賴方向從外向內,domain 不依賴任何外部。

差別主要在描述方式和分層細節:

  • Hexagonal 強調的是「port / adapter」的語言和「兩類 port 方向」的概念
  • Clean Architecture 強調的是「同心圓」的視覺化和四層的命名(Entities / Use Cases / Interface Adapters / Frameworks & Drivers)

實務上兩者經常混用,說「Hexagonal」或「Clean Architecture」指的往往是同一種架構風格。Hexagonal 的 port/adapter 詞彙在強調可測試性時更有用,Clean Architecture 的同心圓在解釋依賴規則時更直觀。


Hexagonal 真正的收益:可替換性和可測試性

Hexagonal Architecture 帶來兩個實際好處:

可替換性:把 PostgreSQL 換成 MongoDB,只需要寫一個新的 MongoOrderRepository,domain core 完全不動。理論上聽起來像「換資料庫是常見需求」,實際上更有用的場景是整合測試——你可以用 in-memory adapter 取代真實資料庫,跑快得多的整合測試。

可測試性:Domain core 的業務邏輯可以在不起任何 infrastructure 的情況下測試。OrderService 的測試只需要 mock OrderRepositoryPaymentGateway 的介面,不需要資料庫連線,不需要 Stripe sandbox。這讓業務邏輯的測試快、隔離、穩定。

這兩個收益的代價是:更多的 interface 定義、更多的 adapter 實作、更陡的學習曲線。在業務邏輯簡單的系統裡,這個成本沒有對應的回報。


下一篇 → Onion Architecture

上一篇 → Layered Architecture