ヘキサゴナルアーキテクチャ(ポートアンドアダプター)とは何か

# 概要
ヘキサゴナルアーキテクチャ(別名ポートアンドアダプター)は<a href="https://en.wikipedia.org/wiki/Alistair_Cockburn">Alistair Cockburn</a>氏により考案されたアーキテクチャパターンである。
このパターンでは、システムをアプリケーション・コア、データベース、ユーザーインターフェースなどの疎結合なコンポーネントに分割し、従来のソフトウェアアーキテクチャが抱えている課題の解決を試みている。
本記事ではこのヘキサゴナルアーキテクチャとは何かについて<a href="https://alistair.cockburn.us/hexagonal-architecture/">Cockburn氏の記事</a>を参考にして考察する。

# 前提となる知識
### オブジェクト指向
ヘキサゴナルアーキテクチャは<a href="https://ja.wikipedia.org/wiki/オブジェクト指向">オブジェクト指向</a>を前提としたアーキテクチャである。

### GOFのデザインパターンのアダプター
ヘキサゴナルアーキテクチャはGOFのデザインパターンの<a href="https://ja.wikipedia.org/wiki/Adapter_パターン">アダプターパターン</a>を利用する。

### 階層化アーキテクチャ
ヘキサゴナルアーキテクチャでは<a href="https://ja.wikipedia.org/wiki/多層アーキテクチャ">多層アーキテクチャ</a>を利用している。

### 依存性逆転の原則
ヘキサゴナルアーキテクチャでは<a href="https://ja.wikipedia.org/wiki/%E4%BE%9D%E5%AD%98%E6%80%A7%E9%80%86%E8%BB%A2%E3%81%AE%E5%8E%9F%E5%89%87">依存性逆転の原則</a>がオブジェクトのモデリングに利用されている。

### MVC(Model View Controller)
有名なデザインパターンの一つである<a href="https://ja.wikipedia.org/wiki/Model_View_Controller">MVC</a>にはModel InteractorやModel View Presentorなどの派生パターンがある。ヘキサゴナルアーキテクチャのプライマリーポートのアイデアは、MVCから着想を得ている。

# ポートとアダプターについての基礎知識
Cockburn氏はヘキサゴナルアーキテクチャにおいてポートとアダプターという概念を利用している。ポートとアダプターについて簡単に説明する。

### ポート
アプリケーションは基本ポートを介して外部と通信している。多くのアプリケーションはユーザー側のポートと、データベース側のポートの2種類のポートのみを持つ。

### アダプター
外部のデバイスに対して接続する時は、通常アダプターを介して接続する。アダプターはAPIの定義をデバイス向けのシグナルに変換する。例えば、GUI(グラフィカルユーザーインターフェース)は、人の動きをポートのAPIにマッピングするアダプターの一例である。

# 従来のソフトウェアアーキテクチャが抱える課題
Cockburn氏による<a href="https://alistair.cockburn.us/hexagonal-architecture/">ヘキサゴナルアーキテクチャの記事</a>では、従来のソフトウェアアーキテクチャが抱える大きな課題の一つとして、ユーザーインターフェースにビジネスロジックが混入してしまう現象が挙げられている。
これまではこの問題を解決するために、階層を増やしていく対策が繰り返し実施されてきた。増やした階層にはビジネスロジックを混入させないということをルール化するわけだが、そうしたルールが守られているかどうかを検知する仕組みはない。数年後にはビジネスロジックを混入させないために作ったはずの階層にビジネスロジックが書かれており、同じ問題が繰り返されてしまう。
同じような問題はアプリケーションの外部にも存在する。アプリケーションのロジックがアプリケーションの外部のデータベースやその他のサービスと密結合になってしまう問題である。

# 課題に対する解決案
ビジネスロジックがいろんな場所に混入してしまう原因は、ビジネスロジックが外部向けのインタラクションと絡み合ってしまうためである。これを避けるためには、アプリケーションの"内側"のコード(ビジネスロジック)が"外側"に漏れないようにすれば良い。
Cockburn氏によるヘキサゴナルアーキテクチャ(ポートアンドアダプター)では、アプリケーションの構造の対称性に注目する。"内側"のアプリケーションをポートを介して"外側"と通信させることで、アプリケーションの"内側"と"外側"を対称的に扱うところに特徴がある。

# ヘキサゴナルアーキテクチャの構造
Cockburn氏が描いているヘキサゴナルアーキテクチャの図を下記に示す。下記の図では、ユーザー側とデータベース側の2つのポートと、各ポートに対して複数のアダプターを用意している。ユーザー側のポートを利用するのはユーザーやユニットテストコードであり、データベース側のポートを介してアクセスするのはデータベースの実態やモックデータベースとなる。
![hexagonal1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55214/59f9f0e3-47d0-0718-51ec-fd4ce7a75c8b.png)

上記の六角形の図を三階層の図で表現すると下記のようになる。
![hexagonal2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55214/cce31b8b-632f-a7fe-5013-330f2346e61a.png)

### なぜヘキサゴン(六角形)なのか？
Cockburn氏によると、6という数字自体に特別な意味はないらしい。アーキテクチャを図にした時、一次元の階層構造よりも六角形にすることで、複数のポートとアダプターを挿入することができるような余地を残したかったとのこと。

### プライマリーとセカンダリー
Cockburn氏によると、ヘキサゴナルアーキテクチャを実装する際は、2種類のポートとアダプターを意識すれば良いとのこと。2種類のポートとアダプターはプライマリーとセカンダリーと表現されている。上記の図でいくと、ユーザ側がプライマリーでデータベース側がセカンダリーになる。

### ポートは何個あればいいのか
Cockburn氏によると、ポートは何個あってもいいとのこと。意識すべきは上記で述べたプライマリーポートとセカンダリーポートの2種類であり、2種類のポートの中に複数のポートが作られて良い。もしくは、全てのポートをプライマリーポート1つ、セカンダリーポート1つに集約してしまう考えもありとしている。

### ユースケースとアプリケーションの境界線
Cockburn氏によると、ヘキサゴナルアーキテクチャを利用することで、ユースケースをより良く書くことができると言う。よくある間違いとしては、各ポートの外側にあるテクノロジーの知識をユースケースに書いてしまうことだが、ポートアンドアダプターを理解しておくと、ユースケースはアプリケーションの境界(六角形の内側)に書くべきであるということが明確化する。こうして書かれたユースケースは読みやすく、保守コストも低く、長期的に安定する。

# ヘキサゴナルアーキテクチャに対する批評
Martin Fawlor氏によると、ヘキサゴナルアーキテクチャはプレゼンテーション層とデータアクセス層の類似性を利用することで、対称性のあるコンポーネントを作成できる点がメリットだとしている。一方で、サービスの提供側とサービスの利用側の間の本来的な非対称性が見えなくなってしまう点がデメリットであるとしている。

# まとめ
本記事ではヘキサゴナルアーキテクチャとは何かについて、Alistair Cockburn氏の書いた記事を参考にして概念的な考察を行った。ヘキサゴナルアーキテクチャの考え方は数年後に発表されたJeffrey Palermo氏によるオニオンアーキテクチャや、Robert Martin氏によるクリーンアーキテクチャにも引き継がれている。次の記事ではヘキサゴナルアーキテクチャのより具体的な実装例についてAlistair Cockburn氏のHands Onを参考にして考察する予定である。

# 参考
https://en.wikipedia.org/wiki/Alistair_Cockburn
https://alistair.cockburn.us/hexagonal-architecture/
https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)
https://www.infoq.com/news/2014/10/exploring-hexagonal-architecture/
https://www.youtube.com/watch?v=th4AgBcrEHA&list=PLWECQhREqoSXYgR9usHoVNQc1cm2ZO6mN&index=5&t=1037s
https://github.com/tpierrain/hexagonalThis