ヘキサゴナルアーキテクチャ
ポートとアダプターでビジネスロジックを外部依存から分離する設計パターン
ヘキサゴナルアーキテクチャとは
ヘキサゴナルアーキテクチャは Alistair Cockburn が 2005 年の記事で示した設計パターンで、ポート (アプリケーション側が定める会話の境界) とアダプター (その境界と個々の外部技術をつなぐ変換役) によってビジネスロジックを外部依存から分離する。原典でのパターン名は「Ports and Adapters」で、ヘキサゴナルアーキテクチャは図の見た目に由来する別名として併記されている。原典が掲げる意図は「利用者・他プログラム・自動テスト・バッチスクリプトのどれからでも等しく駆動でき、最終的な実行時のデバイスやデータベースから切り離した状態で開発・テストできるようにすること」だ。外から来たイベントは、まずポートで受け止められ、技術固有のアダプターが呼び出しやメッセージへ変換してアプリケーションへ渡す。
図が六角形なのは 6 という数に意味があるからではない。原典は、一次元の層状の図に縛られずポートとアダプターを描き足す余白を確保するための形だと明言している。実際のポート数は 2〜4 個程度が多く、原典の著者も 4 個までしか見たことがないと書いている。「六角形だから 6 層」「6 種類の要素が必要」といった読み方は原典に無い。
構造
ヘキサゴナルアーキテクチャはコア (ビジネスロジック) を中心に、Input Port (外部からコアへの入口) と Output Port (コアから外部への出口) を配置する。外部の技術的詳細 (HTTP、DB、キュー) はポートを介してコアに接続するため、コアは外部に依存しない。テスト時はポートの実装をインメモリに差し替えるだけで済む。
[外部] [ポート] [コア] [ポート] [外部]
HTTP Request → Input Port → ビジネスロジック → Output Port → DynamoDB
CLI → Input Port → → Output Port → SQS
Test → Input Port → → Output Port → InMemory
| 層 | 説明 | 例 |
|---|---|---|
| コア (ドメイン) | ビジネスロジック | 注文処理、バリデーション |
| Input Port | コアへの入口 | OrderService インターフェース |
| Output Port | コアからの出口 | OrderRepository インターフェース |
| Input Adapter | 外部 → コア | Lambda ハンドラ、CLI |
| Output Adapter | コア → 外部 | DynamoDB 実装、InMemory 実装 |
Input / Output という呼び分けは実装側で広まった言い方で、原典では駆動する側を primary (driving) アダプター、駆動される側を secondary (driven) アダプターと呼び、図の左側・右側として説明している。原典を読むときはこの対応で読み替える。左側は自動テストのドライバ、右側はモックやインメモリ実装を差し込む場所にあたる。
TypeScript での実装
TypeScript での実装のコード例を示す。
// Output Port (インターフェース)
interface OrderRepository {
save(order: Order): Promise<void>;
findById(id: string): Promise<Order | null>;
}
// コア (ビジネスロジック、外部依存なし)
class OrderService {
constructor(private repo: OrderRepository) {}
async create(input: CreateOrderInput): Promise<Order> {
const order = Order.create(input);
await this.repo.save(order);
return order;
}
}
// Output Adapter: DynamoDB 実装、InMemory 実装など差し替え可能
// Input Adapter: Lambda ハンドラ、CLI など
ヘキサゴナル vs レイヤード vs クリーン
ヘキサゴナル・レイヤード・クリーンの違いを以下にまとめる。
| 観点 | ヘキサゴナル | レイヤード | クリーン |
|---|---|---|---|
| 依存の方向 | 外 → 内 | 上 → 下 | 外 → 内 |
| テスト容易性 | 高い | 中 | 高い |
| 複雑さ | 中 | 低い | 高い |
メリット
最大の利点はテスト容易性だ。Output Adapter を InMemory 実装に差し替えるだけで、DB やメッセージキューなしにビジネスロジックをテストできる。また、コアがフレームワーク (Express、Lambda など) に依存しないため、実行環境の変更がコアに波及しない。DB を DynamoDB から Aurora に移行する場合も、Output Adapter を差し替えるだけでコアは無変更で済む。
ヘキサゴナルアーキテクチャについては関連書籍でも詳しく扱われている。
この記事は役に立ちましたか?
関連用語
オニオンアーキテクチャ
ドメインロジックを中心に据え、外側の層が内側に依存する同心円状のアーキテクチャ
アダプターパターン
互換性のないインターフェースを変換し、既存のコードを変更せずに連携させるデザインパターン
依存関係
モジュールやサービスが他のモジュールやサービスに依存する関係で、結合度と変更の影響範囲を決定する
クリーンアーキテクチャ
ビジネスロジックを外部の技術的詳細から分離し、依存関係を内側に向けることで変更に強い設計を実現するアーキテクチャ原則
ポートとアダプター
アプリケーションのコアロジックを外部技術から分離し、ポート (インターフェース) とアダプター (実装) で接続するアーキテクチャ
YAGNI
You Aren't Gonna Need It - 今必要でない機能を先回りして実装しない原則