ヘキサゴナルアーキテクチャ

動機

わたしが担当しているWebアプリケーションがいろんなサービスを扱っていて、変更が予期せぬところに影響を及ぼすようになってしまっています。そこで、Webアプリケーションを分割しようと思い、マイクロサービスについて調べようと思いました。
まずはじめにマイクロサービスアーキテクチャを読み始めました。すると、すぐにヘキサゴナルアーキテクチャについて記されていました。

Alistair Cockburnによるヘキサゴナルアーキテクチャの概念は、ビジネスロジックが隠れることがある階層化アーキテクチャから離れるように導きました。

レイヤ化アーキテクチャが好ましくないような記述に疑問がわいたので、しっかり理解しようと思います。

書籍マイクロサービスアーキテクチャにあったヘキサゴナルアーキテクチャについてのURLは2020年5月23日現在、改装中でした…こちらに日本語訳がありました。

PoEAAの中でのヘキサゴナルアーキテクチャ

翻訳者の方のコメントにもあるように、PoEAAに記載があるということで、早速読んでみました。

ヘキサゴナルアーキテクチャについてはかなり序盤でふれられていました。以下がその引用になります。

(中略) プレゼンテーションレイヤとデータソースレイヤには多くの類似点があるように見える。どちらも外部との接続に関するレイヤだからだ。これは、Alistair Cockburnのヘキサゴナルアーキテクチャーパターンの背後にあるロジックである。ヘキサゴナルアーキテクチャは、外部システムへのインターフェースで囲まれた核としてシステムを視覚化したものである。ヘキサゴナルアーキテクチャでは、外部にあるものは基本的にすべて外側のインターフェースであり、したがってこれは対照的なビューであって、私の言う非対称のレイヤ化スキーマではない。

さらに、以下のように続きます。

しかし、私はこの非対称性こそ有用だと思っている。他へのサービスとして提供するインターフェースと、他のサービスを使用することとの間には、歴然とした違いがあるからだ。核心に触れていえば、これこぞが私の言うプレゼンテーションとデータソースとの違いなのである。(中略)これらを分けて考えることは有用であると私は考える。

両者の考え方はわかれていてちょっと対立しているようにも捉えられます。
プレゼンテーションとデータソースは外側のインターフェースであるという共通点はあるものの、利用用途を考えると別のものと認識するのがレイヤ化、どちらも外側のインターフェースであるという共通点を持っているので同じものと考えるのがヘキサゴナルアーキテクチャということでしょうか。

ヘキサゴナルアーキテクチャ

翻訳いただいた内容をもとにまとめいきます。意図や動機、構造など書かれているので、GoFのデザインパターンの説明みたいな感じです。

ヘキサゴナルアーキテクチャは別名Ports and Adapter*Ports and Adaptersパターンといいます。
Portsは外部との接点という感じでしょうか(プレゼンテーション、データソースなど)。TCPのポート番号と同じようなイメージです。
Adaptersはその具体的な外部(HTTPなど)とのインターフェースを統一するためのアダプタです。

意図

アプリケーションを、ユーザー、プログラム、自動テストあるいはバッチスクリプトから、同じように駆動できるようにする。そして、実際のランタイムデバイスとデータベースから隔離して、開発とテストをできるようにする。

外部のインターフェースに依存しないようにアプリケーションを構築するということだととらえました。すなわち、アプリケーションの外側に対して同じインターフェースを提供し、ビジネスロジック自体はそのインターフェースの外には実装しないということだと思います。

動機

数年来、ソフトウェアアプリケーションで一番怖いことのひとつは、ビジネスロジックがユーザーインターフェイスコードに侵入することだった。これが引き起す問題は、3つある:
・はじめに、システムを自動テストスイートで綺麗にテストすることができない。なぜなら、テストを必要とするロジックの部分が、フィールドサイズやボタン配置など、頻繁に変わるビジュアルの詳細に依存するからだ。
・同じ理由により、人間駆動のシステム使用から、バッチ処理システムに移行することが不可能になる。
・これも同じ理由から、他のプログムからプログラムを駆動したくなったときに、そうすることが難しいか、または不可能になる。

ビジネスロジックがユーザーインターフェースコードに侵入するのは確かに問題ですね。ユーザーインターフェースが交換可能ではなくなってしまいます。

(多くの組織によって繰り返し)試みられた解法は、アーキテクチャに新しい層を足すことだ。そのときには、今度は、本当に絶対に、ビジネスロジックが新しいレイヤーに置かれることはないという取り決めをする。しかしながら、取り決めへの違反が起きたときに検出する仕組みはなく、組織は、数年後、新しいレイヤーがビジネスロジックでとっちらかっており、同じ問題が起きたことに気付く。

ロジック・責務を持たせるクラスに迷った時、層を追加することはありますね。RailsでいうService層やDecorator層がまさにそれかなと思いました。層を足す=間に挟み込むようなイメージで実装しています。ControllerとModelの間にロジックを詰め込みたいみたいな感じですね。これがよくないと解釈しました。

解決法の本質

利用すべき非対称性は、アプリケーションの「左側」と「右側」ではなく、アプリケーションの「内側」と「外側」だ。従うべきルールは、「内側」の部分にあるコードが「外側」の部分に漏れ出さないようにすべき、ということだ。

プレゼンテーション(フロント)、ビジネスロジック、データソースと左からリクエストを受け付けてレスポンスを返すまでの絵を思い浮かべたりしますが、そうではなく、すべて内側と外側のやりとりであると考えるということですね。プレゼンテーションとデータソースは同じ外側であるという考え方をしましょうということです。
内側であるビジネスロジックはAdapterのインターフェースに依存し、外側もAdapterのインターフェースに依存するように実装すべきです。

ポート用のプロトコルは、2つのデバイスの会話を目的として、与えられる。
このプロトコルは、アプリケーションプログラムインターフェイス(API)の形を取る。

やっとマイクロサービスの本で紹介されていた理由がわかってきました。まさに外側と内側のやりとりをサービス間で行うべきということですね。

また、なぜ六角形なのかの説明も記載されていました。

六角形は、視覚的に、
1.内側と外側の非対称性と、ポートの似たような特性(1次元のレイヤーの絵と、それが想起させるものから完全に離れるために)と、
2.定義された数の異なるポートの存在 ー 2,3,あるいは4つの(4が、わたしがこれまで遭遇した中では一番多かった)
に焦点を当てるよう意図されている。

構造

アプリケーションは各ポートの責務を実装し、ポートは具体的な外部とやり取りするためにAdapterを実装します。
ここでの例はポートがuser-side APIdata-side APIで、user-side APIの具体的な外部には、http adapterGUI adapterなどが記載されていて、data-side APIの具体的な外部はDB access servicemock in-memory databaseとなっています。余談ですがデータベースへのインターフェースを考えるときに必ずSOLID原則のD、依存関係逆転の法則を思い出します。

構造については特に真新しいものはないですね。ですが、応用ノートにおもしろい内容が記載されていました。

応用ノート

ports and adaptersパターンは、意図的に、すべてのポートが基本的に類似しているふりをしながら書かれている。このようなふりをすることは、アーキテクチャレベルで有益だ。実装においては、ポートとアダプターには2種類のものがあることがわかる。すぐに明らかになる理由から、わたしが、「プライマリ」と「セカンダリ」と呼ぶものだ。これらは、「駆動する」アダプターと「駆動される」アダプターと呼ばれることもある。

構造の例でいうと、駆動するアダプタはuser-side APIのことで、駆動されるアダプタはdata-side APIのことでしょう。結局は外部を全て同等には扱えないということでしょうか。レイヤ化アーキテクチャとの大きな違いだと思っていた外部は全て同じように扱うという考え方ではなくなっている気がします。

まとめ

ヘキサゴナルアーキテクチャはシステムをビジネスロジックがある内側と、ビジネスロジックと相互作用する外側におおきくわけるという考え方。その意図はビジネスロジックが外部に侵入しないようにするため。

元々の引用

Alistair Cockburnによるヘキサゴナルアーキテクチャの概念は、ビジネスロジックが隠れることがある階層化アーキテクチャから離れるように導きました。

ビジネスロジックが階層化によって本来の場所ではないところに侵入する(から見えなくなる)ことをいっているのだと思います。マイクロサービスではビジネスロジック自体が一つのサービスとして稼働すると思うので、外部との境界をしっかりと認識することが重要かと思います。

ヘキサゴナルアーキテクチャはレイヤ化アーキテクチャをより抽象化したような考え方だという印象を持ちました。マイクロサービスを構築する際のサービス間の責務を考える際には有用かなと思いました。その場合も駆動する側、駆動される側という考え方はどうしても必要になるかと思います。駆動する、駆動されるサービスが多数になるので、レイヤ化よりヘキサゴナルアーキテクチャの方が視覚的にわかりやすく記述できるという利点があると思います。

次はヘキサゴナルアーキテクチャに似ていると言われているクリーンアーキテクチャについて考えたいと思います。