Javaにおけるヘキサゴナルアーキテクチャパターン:柔軟性を高めるためのコアロジックの分離
別名
- ポートとアダプター
ヘキサゴナルアーキテクチャのデザインパターンの意図
ヘキサゴナルアーキテクチャ(ポートとアダプターとも呼ばれる)は、データベースやユーザーインターフェースなどの外部インターフェースからコアビジネスロジックを分離することを促進するJavaのデザインパターンです。このアーキテクチャアプローチは、ソフトウェアシステムの保守性とテスト可能性を高めます。
実際の例を用いたヘキサゴナルアーキテクチャパターンの詳細な説明
現実世界の例
オンラインバンキングシステムでは、ヘキサゴナルアーキテクチャにより、ユーザーインターフェースやサードパーティサービスの変化に影響されないコアバンキングロジックを維持できます。この分離により、システムの保守性と柔軟性が確保されます。このようなシステムでは、コアバンキングロジック(トランザクションの処理、アカウントの管理、利息の計算など)がアプリケーションのコアを表します。次に、このコアは、ビジネスロジックに影響を与えることなく、異なる外部インターフェースと対話するためのさまざまなアダプターによって囲まれています。たとえば、顧客はWebインターフェース、モバイルアプリ、またはATMサービスを通じてアカウントにアクセスする場合があります。一方、バンキングシステムは、信用調査、不正検出、銀行間トランザクションのために外部サービスともインターフェースする必要があります。これらの各インターフェースは、外部呼び出しをアプリケーションの内部APIとの間で変換するように設計された特定のアダプターを介して、コアバンキングロジックと対話します。この設定により、銀行はコアビジネスロジックを変更することなく外部インターフェースを変更または拡張できるため、柔軟性と保守性が向上します。
平易な言葉で言うと
ヘキサゴナルアーキテクチャは、アプリケーションを、ユーザーインターフェースやデータベースなどの外部システムとの対話を管理するポートとアダプターで囲まれたビジネスロジックの中央コアに編成し、コアを外部の懸念から独立した状態に保ちます。
ウィキペディアによると
ヘキサゴナルアーキテクチャ、またはポートとアダプターアーキテクチャは、ソフトウェア設計で使用されるアーキテクチャパターンです。ポートとアダプターを使用して、ソフトウェア環境に簡単に接続できる疎結合のアプリケーションコンポーネントを作成することを目的としています。これにより、コンポーネントをあらゆるレベルで交換可能になり、テスト自動化が容易になります。
Javaにおけるヘキサゴナルアーキテクチャパターンのプログラム例
ヘキサゴナルアーキテクチャ(ポートとアダプターとも呼ばれる)は、コアビジネスロジックがデータベース、ユーザーインターフェース、サードパーティサービスなどの外部インターフェースから分離された、疎結合アプリケーションを作成することを目的としたデザインパターンです。これにより、コアアプリケーションを独立して簡単にテストできるようになります。
以下のJavaコード例は、依存性注入を使用してコアビジネスロジックを分離し、アプリケーションを非常にテスト可能で外部コンポーネントから独立させる方法を示しています。
提供されたコードでは、`App` クラスでのヘキサゴナルアーキテクチャパターンの例と、依存性注入のためのGoogleのGuiceの使用を確認できます。
`App` クラスはアプリケーションのエントリポイントです。依存性注入を通じて`LotteryAdministration`と`LotteryService`のインスタンスを作成し、それらを使用してさまざまなタスクを処理します。
public class App {
public static void main(String[] args) {
var injector = Guice.createInjector(new LotteryTestingModule());
// start new lottery round
var administration = injector.getInstance(LotteryAdministration.class);
administration.resetLottery();
// submit some lottery tickets
var service = injector.getInstance(LotteryService.class);
SampleData.submitTickets(service, 20);
// perform lottery
administration.performLottery();
}
}
`LotteryAdministration`クラスは、宝くじラウンドの管理を担当します。新しいラウンドを開始し、宝くじを実行し、宝くじをリセットするメソッドがあります。
public class LotteryAdministration {
private final LotteryTicketRepository repository;
private final LotteryEventLog notifications;
private final WireTransfers wireTransfers;
@Inject
public LotteryAdministration(LotteryTicketRepository repository, LotteryEventLog notifications,
WireTransfers wireTransfers) {
this.repository = repository;
this.notifications = notifications;
this.wireTransfers = wireTransfers;
}
public Map<LotteryTicketId, LotteryTicket> getAllSubmittedTickets() {
return repository.findAll();
}
public LotteryNumbers performLottery() {
// Implementation details...
}
public void resetLottery() {
repository.deleteAll();
}
}
`LotteryService`クラスは、宝くじチケットの管理を担当します。チケットを送信し、チケットのステータスを確認し、当選チケットを取得するメソッドがあります。
public class LotteryService {
private final LotteryTicketRepository repository;
private final LotteryEventLog notifications;
private final WireTransfers wireTransfers;
@Inject
public LotteryService(LotteryTicketRepository repository, LotteryEventLog notifications,
WireTransfers wireTransfers) {
this.repository = repository;
this.notifications = notifications;
this.wireTransfers = wireTransfers;
}
public Optional<LotteryTicketId> submitTicket(LotteryTicket ticket) {
// Implementation details...
}
public LotteryTicketCheckResult checkTicketForPrize(
LotteryTicketId id,
LotteryNumbers winningNumbers
) {
// Implementation details...
}
}
Appクラスのメイン関数を実行すると、次の出力が生成されます
11:06:58.357 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was submitted. Bank account 334-746 was charged for 3 credits.
11:06:58.359 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for arnold@google.com was submitted. Bank account 114-988 was charged for 3 credits.
11:06:58.359 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for ollie@google.com was submitted. Bank account 190-045 was charged for 3 credits.
11:06:58.359 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for peter@google.com was submitted. Bank account 335-886 was charged for 3 credits.
11:06:58.359 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for ray@google.com was submitted. Bank account 843-073 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was submitted. Bank account 334-746 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for lisa@google.com was submitted. Bank account 024-653 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for harriet@google.com was submitted. Bank account 842-404 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for larry@google.com was submitted. Bank account 734-853 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for lars@google.com was submitted. Bank account 746-936 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for tyron@google.com was submitted. Bank account 310-992 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for xavier@google.com was submitted. Bank account 143-947 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for kevin@google.com was submitted. Bank account 453-936 was charged for 3 credits.
11:06:58.360 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for yngwie@google.com was submitted. Bank account 241-465 was charged for 3 credits.
11:06:58.361 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was submitted. Bank account 334-746 was charged for 3 credits.
11:06:58.361 [main] ERROR com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for larry@google.com could not be submitted because the credit transfer of 3 credits failed.
11:06:58.362 [main] ERROR com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for larry@google.com could not be submitted because the credit transfer of 3 credits failed.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for mary@google.com was submitted. Bank account 234-987 was charged for 3 credits.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for edwin@google.com was submitted. Bank account 895-345 was charged for 3 credits.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for jacob@google.com was submitted. Bank account 444-766 was charged for 3 credits.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for ollie@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for jacob@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for peter@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for ray@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for lisa@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for harriet@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for larry@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for lars@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for tyron@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for xavier@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for kevin@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for yngwie@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for calvin@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for mary@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for arnold@google.com was checked and unfortunately did not win this time.
11:06:58.362 [main] INFO com.iluwatar.hexagonal.eventlog.StdOutEventLog -- Lottery ticket for edwin@google.com was checked and unfortunately did not win this time.
この例では、`LotteryAdministration`クラスと`LotteryService`クラスがアプリケーションのコアです。それらは、依存性注入を通じて`LotteryTicketRepository`、`LotteryEventLog`、および`WireTransfers`などの外部インターフェースと対話し、コアビジネスロジックを外部の懸念から分離した状態に保ちます。これは、コアアプリケーションが入出力システムの中央にあるヘキサゴナルアーキテクチャパターンの基本的な例です。
実際の例を用いたヘキサゴナルアーキテクチャパターンの詳細な説明

Javaでヘキサゴナルアーキテクチャパターンを使用する場合
ヘキサゴナルアーキテクチャは、特に次のシナリオで有益です
- アプリケーションが複数の外部システムと対話する必要がある場合。
- 高いテスト可能性と保守性の要件がある場合。
- アプリケーションが外部インターフェースの変更の影響を受けないようにする必要がある場合。
Javaにおけるヘキサゴナルアーキテクチャパターンの実際のアプリケーション
- Springのようなフレームワークを活用するエンタープライズアプリケーション内で広く実装されています。
- サービス間の明確な境界とプロトコルを維持するためにマイクロサービスアーキテクチャで使用されます。
- ビジネスロジックに影響を与えることなく、さまざまなデータベースや外部APIとの統合が必要なシステムに採用されています。
ヘキサゴナルアーキテクチャパターンの利点とトレードオフ
利点
- テスト可能性の向上:外部コンポーネントとは独立してコア機能をテストできます。
- 柔軟性:コアビジネスロジックを変更することなく、アプリケーションと対話するコンポーネントの追加または交換を容易にします。
- 保守性:外部インターフェースへの依存関係を減らし、アップグレードとメンテナンスを簡素化します。
トレードオフ
- 複雑性:システム設計と理解を複雑にする可能性のある、より多くの抽象化とレイヤーを導入します。
- オーバーヘッド:より単純なアーキテクチャパターンで十分な、単純なアプリケーションの場合、オーバーエンジニアリングになる可能性があります。
関連するJavaのデザインパターン
- レイヤードアーキテクチャ:コードを責任ごとに編成するという概念を共有しています。ただし、ヘキサゴナルは外部要素とのポートベースの対話を重視しています。
- マイクロサービス:多くの場合、サービス間の明確な境界とプロトコルを定義するためにヘキサゴナルアーキテクチャと組み合わせて使用されます。