LoginSignup
0
0

Hexagonal Architecture

Posted at

最近、ヘキサゴナルアーキテクチャが流行しています。多くの企業で様々な開発者が試みているのがわかります。Alistair Cockburnによって紹介されたこのアーキテクチャは、Clean Architecture[Robert17]で紹介されたOnion Architectureに似ている(または同じ?)アーキテクチャで、ブログの意図部分を見れば目的が明確になります。

Intent

Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases.

要約すると、アプリケーションはDetailsから隔離された環境で開発・テストされ、提供されるべきであるという意味です。そして重要な文は、「isolation from its eventual run-time devices and databases.」(最終的にランタイムのデバイスやデータベースからの隔離)です。このIntentを念頭に置きながら、事例を見ていきます。

用語説明

Driving/Primary/Driver Port/Adapter:同義語
Driven/Secondary Port/Adapter:同義語

Case Study (1) 우아한형제들

示唆点 (1) 依存関係グラフ

ウアハンヒョンジェ(Woowa Bros)の例を見ると、依存関係グラフが次のように描かれていることがわかります。Applicationで使用するPortをSecondary Adapterで依存性逆転(Dependency Inversion)することで、Application Layerを保護しています。Bootstrap(APIサーバー、Primary Actor)ではApplication Layerを直接呼び出しています。

Dependency Graph :

  • BootStrap → Application ← Framework
  • Application → Domain

ヘキサゴナルアーキテクチャでは、ApplicationはRun-timeの依存性から完全に隔離されていなければなりません。もしApplicationモジュールがFrameworkモジュールに依存すると、その瞬間に方向性が生じ、ヘキサゴナルの意図が損なわれます。ヘキサゴナルが意図するのは、方向性が生じるLayered Architectureよりも、Micro Kernel Architecture(also known as Plug-In Architecture)に近いものです。実際にCockburnが対称性(symmetric)について悩んでいる文言が見られます。

This gives them an asymmetric appearance, …
The hexagonal, or ports and adapters, architecture solves these problems by noting the symmetry in the situation: there is an application on the inside communicating over some number of ports with things on the outside. The items outside the application can be dealt with symmetrically.

示唆点 (2) Configuration

POJOで開発し、他の領域でDIを制御する必要がありますが、「Spring frameworkを捨てて他のDI Frameworkを使用する余地があるか?」という問いに対して、「そうではない」という結論に至り、各機能(usecase)についてServiceアノテーションを使用したServiceとして定義しました。

ヘキサゴナルアーキテクチャの意図は、Application、つまりBusiness Logicをテストしやすくするために、Run-timeでBusiness Logicが使用するPortを決定できるようにすることです。しかし、Application Layerでこれらを決定することになると(例えばbuild.gradleのモジュールimplementation)、テスト環境でもMockオブジェクト注入なしではそのままRun-timeで決定されるため、意図とは異なる結果を招くことになります。

この内容に関連して最も共感できたブログを紹介しますと、ドメインはPOJOとPortインターフェース、そしてPOJOだけでビジネスルールを実装したDomain Serviceで構成されており、アダプターが分離されているのがわかります。そして、PortとAdapterの実装関係はconfigパッケージによって決定されます。設定の明示性を確保するためには、上記のように設定する責任を別途分離している方が良いと思われます。

우아한형제들ではアノテーションを使用してすべてのポートに対して一度に実装を決定し、テストではmockkを使用してモック化することが見られます。Cockburnはポートは常に実装されたテストと存在すると述べていますが、その文脈が明確には見られない点が残念です。

CockburnのSmallerWebHexagonの例やJuan Manuelのbluezoneの例を見ると、それがさらに明確になります。ポートは常にスタブされたテストクラスと共に存在し、すべてアプリケーションの開始点またはテストでポートの実際の実装を選択して構成されることが確認できます。

また、上記の内容がポート&アダプター(ヘキサゴナルアーキテクチャ)で最も重要視される「設定可能な依存性(Configurable Dependency)」という文脈に一致しているように思われます。実際にCockburnも講義でこの言葉を何度も口にしていました。

Case Study (2) LINE

非常に簡単です。むしろ一般的に見られるSpring Projectと似た文脈さえ見られます。ウアハンヒョンジェ(Woowa Bros)の例のようにモジュールレベルでの分離ではなく、パッケージレベルでの分離が行われ、Port & Adapterで重要とされるインターフェースと実装が分離されています。テストでは匿名クラスの実装を通じて注入していることが確認できます。示唆点はウアハンヒョンジェ(Woowa Brothers)と似ていますが、LINEの事例から見られるのは、Port & Adapterの実装が思ったよりも簡潔になるという点です。

Case Study (3) Netflix

Netflixの事例は詳細な実装が示されていないため、ウアハンヒョンジェ(Woowa Brothers)のように構成されているかはわかりませんが、関連する話がほんの少し出てきます。以下の文を基にCockburnの例や、共に紹介された例やブログのように構成されているように感じられます。

This as well enables us to decouple deployment and activation, as we can decide which data source to use through configuration.

Netflixの事例でさらに注目すべき点は、ヘキサゴナルアーキテクチャの構成要素を少し明確に提示していることです。そして重要なのはInteractorsの部分です。

Entities are the domain objects (e.g., a Movie or a Shooting Location) — they have no knowledge of where they’re stored (unlike Active Record in Ruby on Rails or the Java Persistence API).

Repositories are the interfaces to getting entities as well as creating and changing them. They keep a list of methods that are used to communicate with data sources and return a single entity or a list of entities. (e.g. UserRepository)

Interactors are classes that orchestrate and perform domain actions — think of Service Objects or Use Case Objects. They implement complex business rules and validation logic specific to a domain action (e.g., onboarding a production)

InteractorはDomain Actionを実行したりオーケストレーションする役割を果たし、Usecase、Serviceとも呼ばれます。Service Layer[Fowler02]について少し説明すると、Service LayerはApplication ServiceとDomain Serviceに分かれますが、上記のServiceはApplication Serviceに近いと思われます。Application ServiceはTransaction Scriptを作成するレイヤーで、よく整理され分離されたDomainオブジェクトを組み合わせる(Orchestration)レイヤーです。つまり、これはInteractorsレイヤーが一つのDomain Modelに依存しないことを意味します。

もちろんです。以下にあなたの文章を日本語に翻訳しました。

結論

ヘキサゴナルアーキテクチャを三行で要約すると次のようになります。

  1. Configurable Dependency:Business Logicは分離されていなければならず、そこで使用する付随的なもの(outside part)はRun-Timeに決定されなければならない。
  2. Primary ActorとSecondary Actorに分かれる。
  3. Portはテスト用クラスの注入が可能でなければならない(Test Double)。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0