ヘキサゴナルアーキテクチャとは?ポートとアダプタで実現する疎結合設計を徹底解説
ソフトウェア開発では、ビジネスロジックを外部技術から守ることが非常に重要です。アプリケーションの価値を生み出す中心部分は、データベース、UI、Webフレームワーク、外部API、クラウドサービスそのものではなく、業務ルールやユースケースにあります。たとえば、注文を確定する条件、在庫を引き当てるルール、請求を発行する流れ、ユーザー権限を判定する処理などは、システムの本質的な価値に直結します。
しかし、実際の開発では、ビジネスロジックがデータベースやUI、フレームワークに強く依存してしまうことがあります。たとえば、サービスクラスの中にORM固有の処理が深く入り込んだり、コントローラーに業務判断が書かれたり、外部APIの仕様がユースケース全体に漏れたりする状態です。このような設計では、技術変更や仕様変更の影響範囲が広がり、保守性が低下します。
ヘキサゴナルアーキテクチャは、この問題を解決するためのアーキテクチャパターンです。英語ではHexagonal Architectureと呼ばれ、ポートとアダプタというモデルでも知られています。この設計では、アプリケーションの中心にドメインロジックやユースケースを置き、その外側にUI、データベース、外部APIなどのアダプタを配置します。中心のロジックは外部技術に直接依存せず、ポートという抽象的な接点を通じて外部とやり取りします。
本記事では、ヘキサゴナルアーキテクチャの基本概念、ポートとアダプタの役割、入力ポート・出力ポート、入力アダプタ・出力アダプタ、依存関係のルール、クリーンアーキテクチャやオニオンアーキテクチャとの違い、DDDとの関係、実装例のイメージ、メリットとデメリット、テスト戦略、実務でのベストプラクティスまで体系的に解説します。
1. ヘキサゴナルアーキテクチャとは?
ヘキサゴナルアーキテクチャとは、アプリケーションの中心にドメインロジックやユースケースを置き、外部のUI、データベース、外部API、メッセージキュー、CLIなどをアダプタとして分離するアーキテクチャ設計です。中心のアプリケーションは、外部技術の詳細を直接知らず、ポートと呼ばれる抽象的なインターフェースを通じて外部と接続します。
この設計の目的は、ビジネスロジックを外部依存から守ることです。外部技術は時間とともに変化します。UIフレームワークを変更する、データベースを差し替える、外部決済サービスを変更する、APIの入口をRESTからメッセージキューに変える、といった変更は実務で起こり得ます。ヘキサゴナルアーキテクチャでは、こうした変更が中心のドメインロジックに直接影響しないように設計します。
主な特徴
| 項目 | 内容 |
|---|---|
| 日本語名 | ヘキサゴナルアーキテクチャ |
| 別名 | ポートとアダプタ |
| 英語名 | Hexagonal Architecture / Ports and Adapters |
| 主な目的 | 外部依存からドメインロジックを保護する |
| 重要概念 | ポート、アダプタ、依存性逆転、疎結合 |
1.1 誕生の背景
ヘキサゴナルアーキテクチャが生まれた背景には、アプリケーションが外部技術に強く依存しすぎる問題があります。従来のレイヤードアーキテクチャでは、画面からサービス、サービスからリポジトリ、リポジトリからデータベースへと処理が流れる形が一般的でした。しかし、この構造では、ビジネスロジックがデータベースやフレームワークの都合に引きずられることがあります。
特に、テストや保守の場面でこの問題が顕在化します。ビジネスロジックをテストしたいだけなのにデータベース接続が必要になる、外部APIが落ちているとユースケースのテストができない、UI変更が内部ロジックに影響する、といった状態は開発効率を下げます。ヘキサゴナルアーキテクチャは、アプリケーションの中心と外部技術の境界を明確にすることで、こうした問題を解消しようとする設計思想です。
1.2 なぜ六角形なのか
ヘキサゴナルアーキテクチャが六角形と呼ばれる理由は、アプリケーションの中心に対して、複数の外部接続口が存在することを図として表現しやすいためです。六角形の各辺は、Web API、CLI、データベース、外部サービス、メッセージキュー、テストコードなど、さまざまな接続先を表すイメージとして使われます。
重要なのは、実際に6つの接続口が必要という意味ではありません。六角形という形は、外部との接続が複数存在し、それらを中心のアプリケーションから分離して扱うという考え方を表現するための比喩です。つまり、六角形そのものよりも、中心のロジックと外部の入出力を分離するという設計思想が本質です。
2. 基本コンセプト
ヘキサゴナルアーキテクチャの基本コンセプトは、コアドメインの保護、外部依存の分離、入出力の抽象化です。アプリケーションの中心には、業務ルールやユースケースがあります。これらは、UIやデータベース、外部APIなどに依存せず、独立して存在できるように設計します。
外部との接続は、ポートとアダプタを通じて行います。ポートは中心のアプリケーションが外部とやり取りするための抽象的な接点であり、アダプタはそのポートを具体的な技術に接続する実装です。この分離によって、外部技術の変更がコアロジックに影響しにくくなります。
2.1 コアドメインの保護
コアドメインとは、アプリケーションの中心となる業務ルールやドメインロジックのことです。たとえば、ECサイトであれば注文、決済、在庫、配送などが重要なドメインになります。これらのルールは、システムの価値そのものであり、外部技術の都合によって簡単に変化すべきではありません。
ヘキサゴナルアーキテクチャでは、このコアドメインを外部技術から保護します。データベースに何を使うか、UIがWebなのかモバイルなのか、外部APIがどのサービスなのかといった詳細は、中心のロジックから切り離します。これにより、業務ルールを安定して保ちやすくなります。
2.2 外部依存の分離
外部依存とは、データベース、外部API、メール送信サービス、決済サービス、UIフレームワーク、メッセージブローカーなど、アプリケーションの外側にある技術要素を指します。これらは実務上必要ですが、変更されやすく、障害や仕様変更の影響も受けやすい部分です。
ヘキサゴナルアーキテクチャでは、外部依存をアダプタとして分離します。たとえば、データベースアクセスはDBアダプタ、メール送信はメールアダプタ、REST APIの入口はWebアダプタとして扱います。こうすることで、外部依存の変更をアダプタ内に閉じ込めやすくなります。
2.3 入出力の抽象化
ヘキサゴナルアーキテクチャでは、アプリケーションへの入力とアプリケーションからの出力を抽象化します。入力にはREST API、画面操作、CLI、バッチ、メッセージ受信などがあります。出力にはデータベース保存、メール送信、外部API呼び出し、ファイル出力などがあります。
これらの入出力を直接コアロジックに書くのではなく、ポートを通じて抽象化します。入力側ではユースケースを呼び出すためのポートを定義し、出力側では外部へ依存する処理を抽象インターフェースとして定義します。これにより、中心のアプリケーションは外部技術の詳細を知らずに動作できます。
3. ポートとは?
ポートとは、アプリケーションの中心と外部世界をつなぐ抽象的な接点です。ポートは具体的な技術実装ではなく、アプリケーションが外部からどのように呼び出されるか、または外部へ何を要求するかを表すインターフェースです。ヘキサゴナルアーキテクチャでは、ポートによって境界を明確にします。
ポートには、大きく入力ポートと出力ポートがあります。入力ポートは、外部からアプリケーションのユースケースを実行するための入口です。出力ポートは、アプリケーションが外部リソースへ依存するための出口です。どちらも、具体的な技術ではなく抽象として設計されます。
3.1 入力ポート
入力ポートは、外部からアプリケーションを操作するための入口です。たとえば、「注文を作成する」「ユーザーを登録する」「請求書を発行する」「在庫を更新する」といったユースケースを呼び出すためのインターフェースが入力ポートになります。REST APIやCLI、Web画面は、この入力ポートを呼び出す入力アダプタとして機能します。
入力ポートを定義することで、アプリケーションのユースケースが外部の入力手段から独立します。たとえば、同じ注文作成ユースケースをREST APIから呼び出すことも、管理画面から呼び出すことも、バッチ処理から呼び出すことも可能になります。入口が変わっても、中心のユースケースは変わりません。
3.2 出力ポート
出力ポートは、アプリケーションが外部リソースへアクセスするための抽象的な出口です。たとえば、注文情報を保存する、メールを送信する、決済サービスを呼び出す、在庫システムへ問い合わせる、といった外部依存処理を表します。出力ポートはインターフェースとして定義され、具体的な実装はアダプタ側に置きます。
出力ポートを使うことで、アプリケーションの中心は具体的なデータベースや外部APIを知る必要がなくなります。中心のユースケースは「注文を保存する」という抽象に依存し、実際にPostgreSQLへ保存するのか、MySQLへ保存するのか、外部APIへ送るのかはアダプタ側で決まります。
3.3 インターフェースの役割
ポートは、アプリケーションと外部技術の間にある契約として機能します。入力ポートは「外部からこのようにアプリケーションを呼び出せる」という契約であり、出力ポートは「アプリケーションは外部にこのような機能を要求する」という契約です。この契約によって、中心と外側の依存関係を整理できます。
インターフェースを適切に設計すると、テストもしやすくなります。出力ポートをモックに差し替えれば、実際のデータベースや外部APIを使わずにユースケースをテストできます。これは、ヘキサゴナルアーキテクチャの大きな利点の一つです。
4. アダプタとは?
アダプタとは、ポートを具体的な外部技術に接続する実装です。入力アダプタは、外部からのリクエストを受け取り、入力ポートを呼び出します。出力アダプタは、出力ポートのインターフェースを実装し、データベースや外部APIなどへ具体的に接続します。
アダプタは、技術依存の詳細を担当する層です。REST APIのルーティング、HTTPリクエストの変換、SQLやORMによるデータ保存、外部サービスのSDK呼び出しなどは、アダプタに配置されます。中心のドメインロジックは、こうした技術詳細を知りません。
4.1 UIアダプタ
UIアダプタは、ユーザーインターフェースからの操作をアプリケーションへ接続する役割を持ちます。Web画面、モバイルアプリ、管理画面、CLIなどが入力アダプタとして機能します。ユーザーの入力を受け取り、必要な形式に変換して入力ポートを呼び出します。
UIアダプタには、画面表示、入力値の受け取り、リクエスト形式の変換、エラーメッセージの整形などの責務があります。ただし、業務判断そのものをUIアダプタに書くべきではありません。業務ルールは中心のユースケースやドメイン層に配置し、UIアダプタは薄く保つことが重要です。
4.2 DBアダプタ
DBアダプタは、データベースとの接続を担当します。出力ポートで定義されたリポジトリや永続化インターフェースを実装し、実際にSQLやORMを使ってデータを保存・取得します。PostgreSQL、MySQL、MongoDB、SQLiteなど、具体的なデータベース技術はDBアダプタの中に閉じ込めます。
DBアダプタを分離することで、中心のアプリケーションはデータベースの種類やORMの詳細を知る必要がなくなります。将来的にデータベースを変更したり、ORMを差し替えたりする場合でも、影響をDBアダプタに限定しやすくなります。
4.3 外部サービスアダプタ
外部サービスアダプタは、決済サービス、メール配信サービス、認証サービス、通知サービス、外部業務システムなどとの連携を担当します。外部APIの仕様やSDKの使い方は変更される可能性があるため、中心のユースケースに直接書くと保守性が低下します。
外部サービスアダプタを用意することで、外部サービスの変更を局所化できます。たとえば、メール配信サービスをSendGridから別のサービスに変える場合でも、メール送信ポートの契約を維持できれば、中心のユースケースを大きく変更せずに済みます。
5. アーキテクチャの構造
ヘキサゴナルアーキテクチャの構造は、中央にドメインロジックやユースケースを置き、その周囲にポートを配置し、さらに外側にアダプタを配置する形で理解できます。中央はアプリケーションの本質であり、外側はその本質を現実の技術と接続するための仕組みです。
この構造では、中心と外側の境界が明確になります。中心は外部技術を知らず、外側のアダプタが中心に合わせて接続します。これは、ビジネスロジックを技術詳細から守り、変更に強い設計を実現するための重要な考え方です。
5.1 中央:ドメインロジック
中央には、ドメインロジックやユースケースが配置されます。ドメインロジックとは、業務ルールやビジネス上の判断を表す処理です。ユースケースは、アプリケーションが利用者に提供する具体的な機能を表します。たとえば、注文を作成する、支払いを確定する、会員を登録する、といった処理です。
中央のロジックは、外部技術に依存しないように設計します。HTTPリクエスト、SQL、外部APIのレスポンス形式、フレームワーク固有のクラスなどを直接扱わないようにします。これにより、中央のロジックを独立してテストしやすくなります。
5.2 内側のポート
内側には、アプリケーションが外部とやり取りするためのポートが配置されます。入力ポートはユースケースを呼び出すための入口であり、出力ポートはデータ保存や外部サービス呼び出しなどの外部依存を抽象化する出口です。ポートは、中心のアプリケーションにとって必要な契約を表します。
ポートを定義することで、中心のロジックは具体的なアダプタに依存せずに済みます。たとえば、注文保存ポートを定義しておけば、実装がPostgreSQLでもMySQLでもインメモリでも、中心のユースケースは同じ契約を使って処理できます。
5.3 外側のアダプタ
外側には、具体的な技術実装であるアダプタが配置されます。REST APIアダプタ、CLIアダプタ、DBアダプタ、メールアダプタ、外部APIアダプタなどが該当します。アダプタは外部世界とアプリケーション中心部を接続する変換役です。
アダプタは、外部技術の詳細を引き受けます。HTTPリクエストをコマンドオブジェクトに変換する、データベースのレコードをドメインオブジェクトに変換する、外部APIレスポンスをアプリケーションで使いやすい形式に変換する、といった処理が含まれます。
6. 依存関係のルール
ヘキサゴナルアーキテクチャでは、依存関係の向きが非常に重要です。中心のドメインロジックやユースケースは、外側のUI、データベース、外部API、フレームワークに直接依存してはいけません。外側のアダプタが内側のポートやユースケースに依存する形にします。
この依存関係のルールによって、中心のロジックを安定させられます。外部技術が変更されても、ポートの契約が保たれていれば、中心のアプリケーションは大きく変わりません。これは、疎結合なシステムを作るうえで非常に重要です。
6.1 内側への依存
ヘキサゴナルアーキテクチャでは、依存関係は外側から内側へ向かいます。入力アダプタは入力ポートやユースケースを呼び出し、出力アダプタは出力ポートを実装します。中心のユースケースやドメインロジックは、外側の具体的なアダプタを知りません。
このルールにより、中心のロジックは外部技術から独立します。たとえば、REST APIから呼び出されても、CLIから呼び出されても、同じユースケースを使えます。入力手段が変わっても、ビジネスロジックを再利用できる点が大きなメリットです。
6.2 外側は差し替え可能
外側のアダプタは差し替え可能な部品として扱います。たとえば、データベースアダプタをPostgreSQL実装からMySQL実装へ変更したり、メール送信アダプタを別のサービスへ変更したりできます。中心のロジックがポートに依存していれば、アダプタの差し替えは比較的容易になります。
もちろん、実際のシステムでは完全に無影響とは限りません。外部サービスの仕様やデータ構造の違いにより調整は必要です。しかし、外部依存をアダプタに閉じ込めておけば、変更の影響範囲を小さくできます。
6.3 疎結合の実現
疎結合とは、モジュール同士の依存関係が弱く、変更の影響が広がりにくい状態を指します。ヘキサゴナルアーキテクチャでは、ポートとアダプタを使うことで、中心のロジックと外部技術を疎結合にします。
疎結合な設計は、保守性、テスト容易性、拡張性に大きく貢献します。外部APIが変更された場合でも外部APIアダプタを修正すればよく、ドメインロジック全体を修正する必要はありません。この構造が長期運用に強いシステムを支えます。
7. クリーンアーキテクチャとの関係
ヘキサゴナルアーキテクチャは、クリーンアーキテクチャと非常に近い考え方を持っています。どちらも、ビジネスルールやユースケースを中心に置き、フレームワークやデータベースなどの外部技術を外側の詳細として扱います。依存関係を内側へ向ける点も共通しています。
一方で、説明の仕方や強調点には違いがあります。クリーンアーキテクチャは、エンティティ、ユースケース、インターフェースアダプタ、フレームワークといった層構造で説明されることが多いです。ヘキサゴナルアーキテクチャは、ポートとアダプタによって外部との接続を分離する点を強調します。
7.1 類似点
クリーンアーキテクチャとヘキサゴナルアーキテクチャの類似点は、中心のビジネスロジックを外部技術から独立させることです。どちらも、データベースやUI、フレームワークがアプリケーションの中心になることを避けます。中心には、業務ルールやユースケースを配置します。
また、依存性逆転の原則を活用する点も共通しています。中心のロジックが具体的な外部実装に依存するのではなく、抽象に依存し、外側の実装がその抽象に従う形になります。この構造により、テストしやすく変更に強い設計になります。
7.2 違い
違いは、主に表現方法と設計上の注目点です。クリーンアーキテクチャは、同心円の層構造として説明され、ビジネスルールを中心に置く依存関係ルールを重視します。一方、ヘキサゴナルアーキテクチャは、アプリケーションの周囲に複数の接続口があり、それぞれをポートとアダプタで扱う考え方を重視します。
実務では、両者を厳密に区別するよりも、共通する目的を理解することが重要です。中心のロジックを守る、外部依存を分離する、依存方向を内側へ向ける、テストしやすくするという目的は共通しています。
7.3 依存ルールの共通性
クリーンアーキテクチャとヘキサゴナルアーキテクチャは、依存ルールの面で非常に近いです。どちらも、中心のビジネスルールが外部技術に依存しないように設計します。外側の技術実装が内側の抽象に従うことで、依存関係を逆転させます。
この共通性を理解しておくと、アーキテクチャの選択に迷ったときにも判断しやすくなります。重要なのは名前ではなく、中心のロジックを守る構造を実現できているかどうかです。
8. オニオンアーキテクチャとの関係
ヘキサゴナルアーキテクチャは、オニオンアーキテクチャとも近い関係にあります。オニオンアーキテクチャでは、ドメインモデルを中心に置き、その外側にアプリケーション層、インフラ層、プレゼンテーション層などを配置します。依存関係は常に内側へ向かいます。
ヘキサゴナルアーキテクチャも、中心にドメインやユースケースを置き、外部技術をアダプタとして分離します。違いは、オニオンアーキテクチャが同心円状の層構造を強調するのに対し、ヘキサゴナルアーキテクチャは外部との接続口、つまりポートとアダプタを強調する点です。
8.1 同心円構造との比較
オニオンアーキテクチャは、玉ねぎのような同心円構造で説明されます。中心にドメイン層があり、外側にアプリケーション層やインフラ層が配置されます。中心に近いほどビジネス上重要で安定したルールが置かれ、外側に行くほど技術的な詳細が配置されます。
ヘキサゴナルアーキテクチャは、中心のアプリケーションを複数の外部接続から分離する形で説明されます。図の形は異なりますが、中心を守り、外側の技術詳細を分離するという目的は共通しています。
8.2 設計思想の共通点
両者の共通点は、ドメインロジックを外部依存から守ることです。データベース、UI、外部API、フレームワークなどは外側に置かれ、中心のビジネスルールはそれらに直接依存しません。この考え方により、変更に強くテストしやすい設計を実現できます。
また、依存性逆転を活用する点も共通しています。内側に抽象を置き、外側に具体実装を置くことで、依存関係を制御します。これにより、外部技術の変更が中心に波及しにくくなります。
8.3 違いのポイント
違いのポイントは、設計をどの観点から整理するかです。オニオンアーキテクチャは、層の内外関係やドメイン中心設計を強調します。ヘキサゴナルアーキテクチャは、外部との接続をポートとアダプタとして整理する点を強調します。
実務では、両者を組み合わせて考えることができます。中心にドメインやユースケースを置き、外側にアダプタを配置し、依存関係を内側へ向ける設計は、両方の思想に沿った実装と言えます。
9. DDDとの関係
ヘキサゴナルアーキテクチャは、ドメイン駆動設計と非常に相性が良いです。DDDでは、業務領域の知識をドメインモデルとして表現し、ビジネスルールを中心に設計します。ヘキサゴナルアーキテクチャは、そのドメインモデルを外部技術から守る構造を提供します。
DDDを実践する場合、ドメインモデルがデータベースやUIの都合に引きずられると、業務上の意味を表現しにくくなります。ヘキサゴナルアーキテクチャでは、ドメインを中心に置き、外部技術をアダプタとして扱うため、DDDの考え方を実装しやすくなります。
9.1 ドメイン中心設計
ドメイン中心設計では、業務上の概念やルールを設計の中心に置きます。注文、顧客、契約、在庫、請求、承認など、システムが扱う重要な概念をコード上に明確に表現します。ヘキサゴナルアーキテクチャは、このドメイン中心設計を外部依存から保護するために役立ちます。
ドメイン中心に設計すると、技術都合ではなく業務上の意味に沿ったコードになります。これにより、業務担当者とのコミュニケーションもしやすくなり、仕様変更への対応も整理しやすくなります。
9.2 境界づけられたコンテキスト
境界づけられたコンテキストとは、特定のドメインモデルや用語が有効になる範囲を定義するDDDの概念です。大規模なシステムでは、同じ言葉でも文脈によって意味が異なることがあります。そのため、適切な境界を設計することが重要です。
ヘキサゴナルアーキテクチャは、各コンテキスト内のアプリケーション構造として利用できます。各コンテキストが独自のドメインロジックを持ち、それを外部アダプタから分離することで、独立性の高い設計を実現できます。
9.3 ドメイン保護
DDDでは、ドメインモデルを正しく保護することが重要です。ドメインモデルがORMやWebフレームワーク、外部APIの都合に引きずられると、業務の意味が薄れてしまいます。ヘキサゴナルアーキテクチャは、ドメインモデルを外部詳細から守るための構造として有効です。
ドメイン保護を実現するには、外部技術をアダプタに閉じ込め、中心のモデルやユースケースは抽象に依存させます。これにより、ドメインロジックをより純粋な形で保ちやすくなります。
10. ポートの設計方法
ポートを設計する際には、インターフェースの責務、ユースケースの単位、抽象化レベルを慎重に考える必要があります。ポートは中心のアプリケーションと外部世界をつなぐ契約であるため、設計が不適切だとアダプタ側も複雑になります。
良いポートは、アプリケーションの目的を表現し、外部技術の詳細を含みません。たとえば、メール送信ポートであれば、特定のメール配信サービスのSDKの型をそのまま露出するのではなく、アプリケーションに必要な「通知を送る」という抽象的な操作として定義するべきです。
10.1 インターフェース設計
ポートのインターフェース設計では、外部技術ではなくアプリケーション側の要求を基準にします。たとえば、データベースに保存するからといって、SQLやORMの詳細をポートに含めるべきではありません。中心のユースケースが必要とする操作を、抽象的なメソッドとして定義します。
インターフェースは小さく保つことが重要です。多くの用途を詰め込んだ巨大なポートは、実装やテストを難しくします。必要な操作を明確にし、利用者ごとに適切な粒度で分けることで、保守しやすい設計になります。
10.2 ユースケース定義
入力ポートは、ユースケースを表現することが多いです。たとえば、CreateOrderUseCase、RegisterUserUseCase、IssueInvoiceUseCaseのように、アプリケーションが提供する具体的な機能をインターフェースとして定義します。これにより、外部から見たアプリケーションの振る舞いが明確になります。
ユースケース定義では、入力データと出力結果を明確にします。HTTPリクエストやDBレコードの形式をそのまま使うのではなく、ユースケースに必要なコマンドや結果オブジェクトとして整理すると、外部技術への依存を減らせます。
10.3 抽象化レベル
ポートの抽象化レベルは、実務で非常に重要です。抽象化しすぎると何をしているのか分かりにくくなり、抽象化が不足すると外部技術に依存しやすくなります。適切な抽象化とは、アプリケーションの目的に沿っていて、外部技術の詳細を隠せるレベルです。
たとえば、PaymentGatewayというポートは、決済処理という業務上の意味を持ちます。一方で、StripeClientやPayPalSDKのような名前を中心側に置くと、特定サービスへの依存が強くなります。ポートは技術名ではなく、業務上の目的で設計することが望ましいです。
11. アダプタの設計方法
アダプタを設計する際には、技術依存の実装を外側に閉じ込めることが重要です。アダプタは、ポートの契約を満たすために具体的な技術と接続します。REST API、データベース、外部API、メッセージキュー、ファイルシステムなどの詳細は、アダプタ内で扱います。
良いアダプタは薄く、変換に集中します。入力アダプタであれば、外部リクエストをユースケースの入力形式に変換します。出力アダプタであれば、出力ポートの呼び出しを具体的なデータベース操作や外部API呼び出しに変換します。アダプタにビジネスロジックを書きすぎないことが重要です。
11.1 技術依存の実装
アダプタには、技術依存の実装を配置します。たとえば、Webフレームワークのコントローラー、ORMを使ったリポジトリ実装、外部APIクライアント、メール送信ライブラリの呼び出しなどが該当します。これらは中心のユースケースやドメインから分離します。
技術依存をアダプタに閉じ込めることで、外部技術を変更しやすくなります。たとえば、ORMを変更する場合でも、DBアダプタを中心に修正すれば済むように設計できます。中心のビジネスロジックは変更しないことが理想です。
11.2 フレームワーク接続
Webフレームワークとの接続も、入力アダプタの役割です。たとえば、Spring、NestJS、Express、FastAPIなどのコントローラーは、HTTPリクエストを受け取り、入力値を変換し、ユースケースを呼び出します。フレームワークの型やライフサイクルは、できるだけアダプタ内に閉じ込めます。
フレームワーク固有の機能を中心のユースケースに持ち込むと、フレームワーク変更が難しくなります。ヘキサゴナルアーキテクチャでは、フレームワークはアプリケーションを動かすための外部詳細として扱い、中心のロジックとは分離します。
11.3 外部API連携
外部API連携では、APIのリクエスト形式、レスポンス形式、認証方法、エラー処理などをアダプタ内で扱います。中心のユースケースは、「決済を実行する」「通知を送る」「外部システムに連携する」といった抽象的な操作だけを知るようにします。
外部APIは仕様変更や障害の影響を受けやすいため、アダプタによる分離が重要です。APIレスポンスの形式が変わっても、アダプタで変換すれば中心のロジックへの影響を抑えられます。
12. 入力アダプタの例
入力アダプタとは、外部からアプリケーションへ処理要求を渡すためのアダプタです。REST API、CLI、Web UI、モバイルUI、バッチ処理、メッセージリスナーなどが代表例です。これらは、外部の入力形式をアプリケーションが理解できる形に変換し、入力ポートやユースケースを呼び出します。
入力アダプタは、外部との接点であるため、リクエスト形式や認証、入力バリデーション、レスポンス整形などを扱うことがあります。ただし、業務判断やドメインルールは入力アダプタに書かず、中心のユースケースやドメイン層へ委譲することが重要です。
12.1 REST API
REST APIは、最も一般的な入力アダプタの一つです。HTTPリクエストを受け取り、パス、クエリパラメータ、リクエストボディ、ヘッダーなどを読み取り、ユースケースに必要な入力形式へ変換します。APIコントローラーは入力アダプタとして機能します。
REST APIアダプタに業務ロジックを書きすぎると、同じ処理をCLIやバッチから呼び出したい場合に再利用しにくくなります。コントローラーは薄く保ち、ユースケースを呼び出す役割に集中させることが望ましいです。
12.2 CLI
CLIも入力アダプタの一種です。コマンドラインから引数を受け取り、アプリケーションのユースケースを実行します。管理用ツール、データ移行、バッチ処理、開発補助コマンドなどで利用されます。
CLIアダプタを使う場合も、コマンドの中に業務ロジックを直接書くのではなく、入力値を整理してユースケースを呼び出す形にします。これにより、同じユースケースをAPIや管理画面からも再利用しやすくなります。
12.3 UI
Web UIやモバイルUIも、入力アダプタとして考えることができます。ユーザー操作を受け取り、アプリケーションのユースケースを実行します。フロントエンドとバックエンドが分離されている場合は、UIが直接ユースケースを呼ぶのではなく、APIを通じて呼び出す構成になることが多いです。
UIアダプタでは、画面表示や入力支援、フォームバリデーションなどを扱います。ただし、ビジネス上の重要な判断はUIだけに閉じ込めるべきではありません。中心のユースケースやドメインにも同じルールを持たせることで、整合性を保てます。
13. 出力アダプタの例
出力アダプタとは、アプリケーションから外部リソースへアクセスするためのアダプタです。代表例として、データベース、メール送信、外部API、ファイル保存、メッセージキューなどがあります。中心のユースケースは出力ポートに依存し、出力アダプタがそのポートを具体的に実装します。
出力アダプタを分離することで、外部リソースの変更に強くなります。たとえば、データベースを差し替える、メール配信サービスを変更する、外部APIの仕様変更に対応する、といった場合でも、影響範囲をアダプタに限定しやすくなります。
13.1 データベース
データベースアダプタは、出力アダプタの代表例です。リポジトリポートを実装し、実際にデータベースへ保存・取得を行います。ORM、SQL、クエリビルダーなどの具体的な技術は、データベースアダプタの中で扱います。
中心のユースケースは、データベースがPostgreSQLなのかMySQLなのか、ORMがPrismaなのかTypeORMなのかを知る必要はありません。注文を保存する、ユーザーを取得する、といった抽象的な操作だけを知っていれば十分です。
13.2 メール送信
メール送信アダプタは、通知や確認メールを送るための出力アダプタです。中心のユースケースは、メール送信ポートを通じて「メールを送る」という操作を要求します。具体的にどのメール配信サービスを使うかは、アダプタ側で実装します。
この分離により、メール配信サービスを変更しやすくなります。たとえば、最初はSMTPを使い、後から外部メール配信サービスへ移行する場合でも、中心のユースケースを大きく変更せずに済みます。
13.3 外部API
外部APIアダプタは、決済、認証、配送、在庫、翻訳、AIサービスなどの外部システムと連携するために使われます。外部APIは仕様変更や障害が発生しやすいため、アダプタとして分離する価値が高い領域です。
中心のユースケースに外部APIのレスポンス形式やSDKの型を直接持ち込むと、外部サービス変更時の影響が大きくなります。アダプタで変換し、中心には業務上必要な結果だけを返す設計が望ましいです。
14. ヘキサゴナルアーキテクチャのメリット
ヘキサゴナルアーキテクチャの主なメリットは、テスト容易性、技術変更への強さ、保守性向上です。中心のドメインロジックやユースケースが外部技術に依存しないため、独立してテストしやすくなります。また、外部アダプタを差し替えることで技術変更にも対応しやすくなります。
特に、長期運用されるシステムや複雑な業務ロジックを持つシステムでは、これらのメリットが大きくなります。短期的には設計コストがかかりますが、長期的には変更しやすく、理解しやすい構造を維持しやすくなります。
14.1 テスト容易性
ヘキサゴナルアーキテクチャでは、中心のユースケースやドメインロジックを外部技術から切り離せるため、テストがしやすくなります。データベースや外部APIを使わずに、出力ポートをモック化してユースケースをテストできます。
テスト容易性が高いと、リファクタリングや機能追加を安全に行いやすくなります。特に、ビジネスルールが複雑なシステムでは、ドメインロジックを高速にテストできることが品質向上に直結します。
14.2 技術変更への強さ
外部技術は変化します。データベース、フレームワーク、外部サービス、UI、通信方式などは、プロジェクトの成長に合わせて変更される可能性があります。ヘキサゴナルアーキテクチャでは、これらをアダプタとして分離するため、変更の影響を限定しやすくなります。
たとえば、REST APIに加えてメッセージキューから同じユースケースを呼び出したい場合、入力アダプタを追加すれば対応できます。中心のユースケースを再利用できる点が大きなメリットです。
14.3 保守性向上
ヘキサゴナルアーキテクチャでは、責務が明確になります。中心はビジネスロジック、ポートは境界の契約、アダプタは外部技術との接続を担当します。この分離により、どこに何を書くべきかが明確になり、保守しやすくなります。
保守性が高い構造では、変更時に確認すべき範囲が分かりやすくなります。外部APIの仕様変更なら外部APIアダプタ、業務ルール変更ならドメインやユースケース、といったように修正箇所を判断しやすくなります。
15. ヘキサゴナルアーキテクチャのデメリット
ヘキサゴナルアーキテクチャには、設計コスト増加、初期開発の複雑化、小規模開発には過剰になりやすいというデメリットもあります。ポートやアダプタを分けるため、単純な処理でもファイルやクラスが増える場合があります。
そのため、すべてのプロジェクトに必ず適用すべきではありません。業務ロジックが単純で、短期間だけ使う小規模アプリケーションでは、よりシンプルな構成の方が適している場合もあります。重要なのは、プロジェクトの規模や変更頻度に応じて判断することです。
15.1 設計コスト増加
ヘキサゴナルアーキテクチャを導入するには、ポート、アダプタ、ユースケース、ドメインの責務を整理する必要があります。単純にコントローラーからデータベースを呼び出す構成よりも、初期設計に時間がかかります。
ただし、この設計コストは長期的な保守性への投資とも言えます。システムが成長し、外部連携や業務ルールが増えるほど、初期に境界を整理しておく価値が高まります。
15.2 初期開発の複雑化
ヘキサゴナルアーキテクチャでは、ポートやアダプタを分離するため、初期開発時の構造がやや複雑になります。新しいメンバーが参加した場合、どの層に何を書くべきかを理解するまでに時間がかかることがあります。
この複雑化を抑えるには、チーム内で設計ルールを明文化し、サンプル実装を用意することが有効です。すべてを厳密に分けすぎず、プロジェクトに合った粒度で導入することも重要です。
15.3 小規模開発には過剰
小規模で単純なアプリケーションでは、ヘキサゴナルアーキテクチャが過剰になる場合があります。たとえば、数画面だけの管理ツールや短期間のプロトタイプでは、ポートとアダプタを細かく分けるよりも、シンプルな構成の方が開発しやすいことがあります。
ただし、小規模でも将来的に複雑化する見込みがある場合は、軽量な形で考え方を取り入れる価値があります。重要なのは、アーキテクチャを目的化せず、保守性と開発速度のバランスを取ることです。
16. テスト戦略との関係
ヘキサゴナルアーキテクチャは、テスト戦略と非常に相性が良い設計です。中心のユースケースやドメインロジックが外部技術に依存しないため、単体テストを高速かつ安定して実行できます。出力ポートをモック化すれば、データベースや外部APIなしでテストできます。
また、アダプタ単位のテストも設計しやすくなります。中心のロジックはドメインテストやユースケーステストで確認し、アダプタは統合テストで確認する、といったようにテストの責務を分けられます。これはテストピラミッドの考え方とも相性があります。
16.1 モック活用
出力ポートを使うことで、モックを活用しやすくなります。たとえば、注文作成ユースケースをテストする際、実際のデータベースアダプタではなく、インメモリのリポジトリやモックリポジトリを使えます。メール送信や外部API呼び出しも同様に差し替えられます。
モックを使うことで、テストの実行速度が上がり、外部環境に依存しない安定したテストを作れます。ただし、モックだけでは実際の接続問題を検出できないため、アダプタの統合テストも別途必要です。
16.2 ドメイン単体テスト
ヘキサゴナルアーキテクチャでは、ドメインロジックを独立してテストしやすくなります。ドメインモデルが外部技術に依存していなければ、データベースやWebフレームワークを起動しなくても、業務ルールを検証できます。
たとえば、注文のキャンセル条件、料金計算、在庫引当、権限判定などを単体テストとして実行できます。ドメイン単体テストは高速で安定しやすく、ビジネスルールの品質を守るうえで重要です。
16.3 インフラ差し替えテスト
アダプタを分離しているため、インフラ差し替えテストも行いやすくなります。たとえば、同じ出力ポートに対して、インメモリアダプタ、テスト用DBアダプタ、本番DBアダプタを用意できます。これにより、テストの目的に応じて実装を切り替えられます。
インフラ差し替えが容易になると、開発環境やCI環境でのテストも柔軟になります。外部サービスに依存せずにユースケースを検証し、必要な部分だけ実際のアダプタで統合テストを行う構成が作れます。
17. フレームワーク依存の排除
ヘキサゴナルアーキテクチャでは、フレームワーク依存を中心のロジックから排除することが重要です。Spring、NestJS、Express、Django、FastAPIなどのフレームワークは便利ですが、ビジネスロジックがフレームワーク固有の型や仕組みに依存しすぎると、テストや変更が難しくなります。
フレームワークは外側のアダプタとして扱います。コントローラーやルーティング、依存性注入の設定、リクエスト・レスポンス処理などはフレームワークに依存しても構いませんが、中心のユースケースやドメインには持ち込まないようにします。
17.1 Spring / NestJSとの関係
SpringやNestJSは、ヘキサゴナルアーキテクチャと組み合わせて使いやすいフレームワークです。依存性注入の仕組みを活用して、入力アダプタ、ユースケース、出力ポート、出力アダプタを接続できます。コントローラーは入力アダプタとして、リポジトリ実装は出力アダプタとして設計できます。
ただし、フレームワークの便利な機能を中心のドメインに持ち込みすぎないことが重要です。アノテーションやデコレーター、フレームワーク固有のライフサイクルをドメイン層に入れると、独立性が弱くなります。フレームワークは外側に置く意識が必要です。
17.2 コアロジックの独立
コアロジックは、フレームワークなしでも動作できる状態が理想です。ユースケースやドメインモデルがHTTPリクエスト、DBコネクション、フレームワークの例外クラスなどに依存していない場合、テストや再利用がしやすくなります。
コアロジックが独立していれば、REST APIだけでなく、CLIやバッチ、メッセージキューからも同じユースケースを呼び出せます。これは、アプリケーションの拡張性を高めるうえで大きなメリットです。
17.3 依存逆転の活用
フレームワーク依存を排除するには、依存性逆転を活用します。中心のユースケースは具体的な実装ではなく、ポートという抽象に依存します。外側のアダプタがそのポートを実装し、依存性注入によって接続します。
この構造により、中心のロジックはフレームワークや外部技術を知る必要がありません。外側の実装が中心の抽象に合わせる形になるため、依存関係を内側へ向けることができます。
18. リポジトリとの関係
リポジトリは、ヘキサゴナルアーキテクチャにおける出力ポートとしてよく利用されます。アプリケーションは、データを保存・取得する必要がありますが、具体的なデータベースやORMに直接依存するべきではありません。そのため、リポジトリポートを定義し、DBアダプタがそれを実装します。
リポジトリを適切に設計すると、データアクセスの詳細を外側に閉じ込められます。中心のユースケースは、保存や検索といった抽象的な操作だけを知り、SQLやORMの詳細を知りません。これは、保守性とテスト容易性の向上につながります。
18.1 永続化ポート
永続化ポートは、データ保存や取得のための出力ポートです。たとえば、OrderRepository、UserRepository、InvoiceRepositoryのような形で定義されます。ユースケースは、このポートを通じて必要なドメインオブジェクトを取得したり保存したりします。
永続化ポートは、ドメインやユースケースが必要とする操作を基準に設計します。データベースのテーブル構造に引きずられすぎると、中心のロジックが永続化の都合に依存してしまいます。業務上の意味を意識した設計が重要です。
18.2 実装アダプタ
実装アダプタは、永続化ポートを具体的に実装します。たとえば、PostgreSQLを使うアダプタ、Prismaを使うアダプタ、JPAを使うアダプタ、インメモリのテスト用アダプタなどが考えられます。中心のユースケースは、どの実装が使われているかを知りません。
この分離により、テストではインメモリアダプタを使い、本番ではDBアダプタを使うといった切り替えが可能になります。実装アダプタは外側にあるため、技術変更にも対応しやすくなります。
18.3 DB差し替え可能性
リポジトリをポートとして定義しておくと、DB差し替え可能性が高まります。たとえば、初期開発ではSQLiteを使い、本番ではPostgreSQLを使う、あるいは一部の保存先を外部APIへ変更するといった設計がしやすくなります。
ただし、実際にはデータベースごとの機能差やスキーマ設計の違いがあるため、完全な差し替えが常に簡単とは限りません。それでも、中心のロジックからDB詳細を分離しておくことで、変更の影響範囲を小さくできます。
19. 実装例のイメージ
ヘキサゴナルアーキテクチャの実装例では、Use Case層、Domain層、Adapter層を分ける構成がよく使われます。Use Case層はアプリケーションの処理フローを担当し、Domain層はビジネスルールを担当し、Adapter層は外部技術との接続を担当します。
実装上のフォルダ名や構成は、言語やフレームワークによって異なります。重要なのは、中心のロジックが外側の具体実装に依存しないことです。フォルダ分けだけを真似しても、依存関係が崩れていればヘキサゴナルアーキテクチャの効果は得られません。
19.1 Use Case層
Use Case層は、アプリケーションが提供する機能を実行する層です。注文作成、ユーザー登録、請求発行、在庫更新など、具体的なユースケースを実装します。Use Case層は入力ポートとして外部から呼び出され、必要に応じてドメインオブジェクトや出力ポートを利用します。
Use Case層には、処理の流れを記述します。ただし、業務ルールの本質はDomain層に置くことが望ましいです。Use Case層は、入力を受け取り、ドメイン処理を呼び出し、必要な保存や外部連携を行う調整役として設計します。
19.2 Domain層
Domain層は、ビジネスルールや業務上の概念を表現する層です。エンティティ、値オブジェクト、ドメインサービスなどが配置されます。Domain層は、データベースやWebフレームワークに依存しない形で設計します。
Domain層が独立していれば、業務ルールを単体でテストしやすくなります。また、外部技術に引きずられないため、業務上の意味をより自然にコードへ反映できます。これは、DDDと組み合わせる場合にも重要です。
19.3 Adapter層
Adapter層は、外部技術との接続を担当します。REST APIコントローラー、DBリポジトリ実装、外部APIクライアント、メール送信実装、メッセージキューリスナーなどが含まれます。Adapter層は、外部世界の形式とアプリケーション内部の形式を変換します。
Adapter層には技術依存のコードが入りますが、ビジネスロジックを入れすぎないように注意します。アダプタは薄く保ち、変換と接続に集中させることで、中心のロジックをきれいに保てます。
20. よくある設計ミス
ヘキサゴナルアーキテクチャを導入しても、設計ミスがあると本来の効果を得られません。代表的なミスには、アダプタにビジネスロジックを書くこと、ポートが肥大化すること、依存方向が破壊されることがあります。これらは、責務の境界が曖昧な場合に発生しやすいです。
アーキテクチャはフォルダ構成だけで決まるものではありません。どの層が何を知ってよいのか、どこに業務ルールを書くのか、外部技術との境界をどう守るのかをチームで共有する必要があります。
20.1 アダプタにビジネスロジックを書く
よくあるミスの一つは、アダプタにビジネスロジックを書いてしまうことです。たとえば、APIコントローラーに注文のキャンセル条件を書いたり、DBアダプタに業務上の判断を書いたりすると、中心のドメインロジックが外側に漏れてしまいます。
アダプタは外部技術との接続と変換を担当するべきです。業務判断はUse Case層やDomain層へ置くことで、複数の入力手段から同じロジックを再利用できるようになります。
20.2 ポートが肥大化する
ポートが肥大化することもよくある問題です。多くの機能を一つのポートに詰め込むと、実装アダプタが複雑になり、テストもしにくくなります。また、使わないメソッドへの依存が発生し、インターフェース分離の原則にも反しやすくなります。
ポートは必要最小限に設計することが大切です。利用者やユースケースごとに適切な粒度で分け、責務を明確にします。巨大な万能ポートではなく、目的のはっきりした小さなポートを設計する方が保守しやすくなります。
20.3 依存方向の破壊
ヘキサゴナルアーキテクチャで最も避けるべきミスは、依存方向の破壊です。中心のユースケースやドメインが、外側のアダプタやフレームワークに直接依存すると、設計の意味が失われます。たとえば、ドメイン層がORMのモデルやHTTPリクエスト型を参照する状態は危険です。
依存方向を守るには、コードレビューや静的解析、パッケージ分離が有効です。中心の層が外側の層を参照しないように、明確なルールを設けることが重要です。
21. レイヤードアーキテクチャとの違い
レイヤードアーキテクチャは、システムをプレゼンテーション層、アプリケーション層、ドメイン層、データアクセス層などに分ける設計です。多くの開発現場で使われており、責務を整理しやすい点がメリットです。一方で、依存方向が上から下へ流れ、ドメインがデータアクセス層に依存しやすい構造になることがあります。
ヘキサゴナルアーキテクチャは、層の上下よりも、中心と外側の境界を重視します。データベースもUIも外側のアダプタとして扱い、中心のビジネスロジックを独立させます。この点が、従来のレイヤードアーキテクチャとの大きな違いです。
21.1 依存方向の違い
レイヤードアーキテクチャでは、上位層が下位層に依存する形になりやすいです。たとえば、サービス層がリポジトリ層に依存し、リポジトリ層がデータベースに依存します。この構造では、ビジネスロジックがデータアクセスの都合に引きずられることがあります。
ヘキサゴナルアーキテクチャでは、中心のロジックは外側の実装に直接依存しません。出力ポートを通じて外部依存を抽象化し、外側のアダプタがそのポートを実装します。依存方向を内側へ向ける点が重要です。
21.2 柔軟性の違い
レイヤードアーキテクチャは、構造が分かりやすい一方で、外部インターフェースの追加や差し替えが難しくなる場合があります。たとえば、REST APIだけを前提にした設計では、同じユースケースをCLIやメッセージキューから呼び出す際に再利用しにくいことがあります。
ヘキサゴナルアーキテクチャでは、入力アダプタを追加することで、同じユースケースを複数の入口から利用できます。外部との接続をアダプタとして扱うため、柔軟性が高くなります。
21.3 抽象化レベルの違い
レイヤードアーキテクチャでは、技術的な層分けが中心になりがちです。コントローラー、サービス、リポジトリ、モデルといった分類は分かりやすいですが、外部依存との境界が曖昧になることがあります。
ヘキサゴナルアーキテクチャでは、外部との接続をポートとアダプタとして抽象化します。技術層の分類だけではなく、アプリケーションの中心と外部世界の境界を明確にする点が特徴です。
22. マイクロカーネルアーキテクチャとの違い
マイクロカーネルアーキテクチャは、コア機能と拡張機能を分離し、プラグインによって機能追加を行う設計です。IDE、OS、業務パッケージ、拡張可能なアプリケーションなどで使われます。一方、ヘキサゴナルアーキテクチャは、外部依存をポートとアダプタで分離し、ドメインロジックを保護することを目的とします。
両者は「中心を守る」という点では似ていますが、目的と適用領域が異なります。マイクロカーネルアーキテクチャはプラグイン拡張性を重視し、ヘキサゴナルアーキテクチャは外部技術との疎結合を重視します。
22.1 プラグイン中心との違い
マイクロカーネルアーキテクチャでは、プラグインによる機能拡張が中心です。コアは最小限の機能を持ち、追加機能はプラグインとして外部から接続されます。ユーザーや開発者が後から機能を追加しやすい構造を目指します。
ヘキサゴナルアーキテクチャでは、外部技術との接続をアダプタとして扱います。アダプタはプラグインのように見える場合もありますが、主な目的は機能追加よりも、外部依存の分離とドメイン保護です。
22.2 コア構造の違い
マイクロカーネルアーキテクチャのコアは、拡張機能を動かすための最小限の基盤を提供します。一方、ヘキサゴナルアーキテクチャのコアは、ドメインロジックやユースケースを含むアプリケーションの中心です。つまり、コアが表すものが異なります。
ヘキサゴナルアーキテクチャでは、中心のコアがビジネス価値を持ちます。外側のアダプタは、そのコアを外部技術と接続するためのものです。マイクロカーネルでは、コアは拡張可能な基盤としての意味が強くなります。
22.3 適用領域の違い
マイクロカーネルアーキテクチャは、プラグイン拡張が重要なアプリケーションに向いています。たとえば、IDE、CMS、業務パッケージ、拡張可能なツールなどです。機能追加を柔軟に行いたい場合に有効です。
ヘキサゴナルアーキテクチャは、業務ロジックを外部依存から守りたいアプリケーションに向いています。APIサーバー、SaaS、業務システム、マイクロサービスなど、長期運用されるシステムで特に有効です。
23. 実務での活用例
ヘキサゴナルアーキテクチャは、SaaSアプリケーション、APIプラットフォーム、マイクロサービスなどで活用されます。これらのシステムでは、業務ロジックが重要であり、外部サービスや技術スタックが変化しやすいため、ポートとアダプタによる分離が効果を発揮します。
特に、複数の外部システムと連携するアプリケーションでは、外部依存をアダプタとして分離しておく価値が高くなります。決済、通知、認証、外部データ連携などをそれぞれアダプタとして扱えば、仕様変更への対応がしやすくなります。
23.1 SaaSアプリケーション
SaaSアプリケーションでは、継続的な機能追加や外部サービス連携が多く発生します。課金、認証、通知、分析、外部API連携など、多くの外部依存が存在します。ヘキサゴナルアーキテクチャを使うことで、中心の業務ロジックを守りながら外部連携を追加できます。
また、SaaSは長期運用されることが多いため、保守性とテスト容易性が重要です。ポートとアダプタを明確に分けることで、仕様変更や技術変更に対応しやすい構造を作れます。
23.2 APIプラットフォーム
APIプラットフォームでは、複数のクライアントや外部システムから同じユースケースが呼び出されることがあります。REST API、GraphQL、Webhook、メッセージキューなど、入力手段が複数になる場合もあります。
ヘキサゴナルアーキテクチャでは、入力アダプタを追加することで、同じ中心ロジックを複数の入口から利用できます。これにより、API形式が増えてもビジネスロジックの重複を避けやすくなります。
23.3 マイクロサービス
マイクロサービスでは、各サービスが独立したドメインやユースケースを持ちます。サービス内部をヘキサゴナルアーキテクチャで設計すると、外部API、メッセージング、データベースなどとの境界を明確にできます。
また、マイクロサービスは外部連携が多いため、アダプタによる分離が有効です。他サービスのAPI変更や通信方式の変更が発生しても、アダプタで吸収できれば中心のユースケースへの影響を抑えられます。
24. 実務でのベストプラクティス
ヘキサゴナルアーキテクチャを実務で活用するには、ドメイン中心設計、ポートを最小限にすること、アダプタを薄く保つことが重要です。形式だけを真似しても、責務が曖昧だったり、依存方向が崩れていたりすると、本来の効果は得られません。
また、導入時にはチーム全体で設計ルールを共有する必要があります。どこまでをドメインに置くのか、ユースケースはどの粒度にするのか、ポートはどの層に置くのか、アダプタに何を書いてよいのかを明確にすると、実装のばらつきを防げます。
24.1 ドメイン中心設計
まず重要なのは、ドメイン中心に設計することです。フレームワークやデータベースから設計を始めるのではなく、業務上の概念、ユースケース、ルールを整理します。中心に何を置くべきかを明確にすることで、外部依存との境界も決めやすくなります。
ドメイン中心設計では、業務の言葉をコードに反映することも重要です。注文、請求、契約、在庫、承認といったドメイン概念が構造上見えると、アプリケーションの目的を理解しやすくなります。
24.2 ポートを最小限にする
ポートは便利ですが、作りすぎると複雑になります。すべてのクラスにインターフェースを作るのではなく、外部依存との境界や差し替えが必要な箇所に絞って設計することが重要です。必要以上の抽象化は、かえって可読性を下げることがあります。
良いポートは、目的が明確で小さく、ユースケースに必要な操作だけを持っています。巨大な万能ポートを避け、利用者や責務ごとに適切な粒度で分けることが、保守しやすい設計につながります。
24.3 アダプタを薄く保つ
アダプタは、外部技術との接続と変換に集中させるべきです。アダプタに業務ロジックが入り込むと、中心のロジックが分散し、再利用性やテスト容易性が低下します。コントローラーやDB実装に業務判断を書きすぎないように注意が必要です。
アダプタを薄く保つことで、外部技術変更への対応がしやすくなります。アダプタは外部形式と内部形式を変換し、ユースケースやドメインに処理を委譲する役割に徹することが理想です。
おわりに
ヘキサゴナルアーキテクチャは、ドメインロジックを外部依存から守るためのアーキテクチャパターンです。ポートとアダプタという考え方を使い、アプリケーションの中心と外部技術の境界を明確にします。中心にはユースケースやドメインロジックを置き、外側にはUI、データベース、外部API、メッセージキューなどのアダプタを配置します。
この設計の最大の特徴は、外部技術に対して疎結合な構造を作れることです。REST API、CLI、Web UIなどの入力手段を入力アダプタとして扱い、データベース、メール送信、外部APIなどを出力アダプタとして扱います。中心のロジックはポートという抽象に依存するため、外部技術の変更が直接影響しにくくなります。
ヘキサゴナルアーキテクチャは、クリーンアーキテクチャやオニオンアーキテクチャとも強い関連があります。いずれも、ビジネスルールを中心に置き、外部技術を詳細として扱う点で共通しています。ヘキサゴナルアーキテクチャは、その中でも特に外部との接続口をポートとアダプタとして整理する点に特徴があります。
一方で、ヘキサゴナルアーキテクチャには設計コストや初期開発の複雑化というデメリットもあります。小規模で単純なアプリケーションでは過剰になる場合があるため、プロジェクトの規模、業務ロジックの複雑さ、長期運用の必要性を考慮して採用することが重要です。
実務で活用する際は、ドメイン中心に設計し、ポートを最小限に保ち、アダプタを薄くすることが大切です。アーキテクチャの形だけを真似るのではなく、中心のビジネスロジックを守り、外部依存を分離するという目的を意識することで、テストしやすく、保守しやすく、変更に強いソフトウェアを実現できるでしょう。
EN
JP
KR