オニオンアーキテクチャとは何か

# 概要
オニオンアーキテクチャはJeffrey Palermo氏により考案されたアーキテクチャパターンである。伝統的な<a href="https://ja.wikipedia.org/wiki/%E5%A4%9A%E5%B1%A4%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3">階層化アーキテクチャ</a>と<a href="https://ja.wikipedia.org/wiki/オブジェクト指向">オブジェクト指向</a>の考え方を踏襲しつつ、これまでよりも保守性、テスト容易性、依存性の点で優れたアプリケーションを構築することを目的としている。本記事ではこのオニオンアーキテクチャとは何かについて<a href="https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/">Palermo氏の記事</a>を参考にして考察する。


# 前提となる知識
オニオンアーキテクチャを理解する上で前提となるいくつかの知識を挙げる。

### オブジェクト指向
オニオンアーキテクチャは<a href="https://ja.wikipedia.org/wiki/オブジェクト指向">オブジェクト指向</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>がオブジェクトのモデリングに利用されている。

### ドメイン駆動設計
Entity, Repositoryといった<a href="https://ja.wikipedia.org/wiki/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88">ドメイン駆動設計</a>で提唱されているモデリングの考え方はオニオンアーキテクチャでも一部利用されている。

# 伝統的な階層化アーキテクチャが抱える課題
Jeffrey Palermo氏はオニオンアーキテクチャを説明する前に、伝統的な階層化アーキテクチャが抱える問題について言及している。
伝統的な階層化アーキテクチャの一例として、プレゼンテーション層(もしくはui層)、モデル層(もしくはビジネスロジック層)、データアクセス層、infrastructure層からなる階層化アーキテクチャを考えてみる。

![traditional_tier.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55214/be6cfd75-d192-9e36-83b8-1c7223d6f12d.png)

このアーキテクチャを利用すると、各層にあるロジックは通常その下の層に対して依存していく。加えて、基本的にはプレゼンテーション層、モデル層、データ層からinfrastructure層(File Access, DB Access, ORM, etc...)に対する依存が発生するため、全ての層がinfrastructure層に対して密結合になる可能性がある。infrastructure層にあるロジックに修正が発生した場合は、そのロジックを参照している全ての層のロジックも修正する必要がある。


# オニオンアーキテクチャの階層構造
オニオンアーキテクチャでは階層構造を円で表現する。オニオン(=玉ねぎ)という名称は、おそらくこの円構造からきているものと思われる。
全ての依存関係は円の中心の層に対して向かう。一方で、中心の層から外側の層へは依存しない。アプリケーションのコア(核)になる層の数は変化しても良いが、ドメインモデル層は常に中心に配置する。

![onion_tier.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55214/0ba5f566-f5bc-cddf-92e6-3bbef5040e42.png)

Jeffrey Palermo氏の<a href="https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/">説明</a>では階層構造が円で表現されているが、下記のように表現しても問題ないだろう。

<img width="357" alt="onion_architecure_custom_tire.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55214/ed946eb6-6546-3dc0-2a2e-ab1f53754520.png">




## 各層の役割
オニオンアーキテクチャの各層の役割について説明する。

### ドメインモデル層
ビジネスロジックに関連した状態と振る舞いの一体化したオブジェクトを配置する。ドメインモデル層のロジックは、他の層への依存関係を持たない。
E.g.
Entity, ValueObjectなど

### ドメインサービス層
ビジネスロジックに関わる振る舞いのロジック、interfaceなどを配置する。
E.g. 
DomainService, IRepositoryなど

### アプリケーションサービス層
アプリケーション固有のロジック、一般的によく利用される制御用のinterafaceなどを配置する。
E.g.
ApplicationService, IUserSessionなど

### UI, Infrastructure層
伝統的な階層化アーキテクチャで表現されるinfrastructure層のオブジェクト(File Access, DB Access, ORM, etc...)、ドメインサービス層で用意したIRepositoryの実態, MVC, やユニットテストなどをここに配置する。

# オニオンアーキテクチャを利用したクラス設計の例
上述の各層の役割を前提とし、簡易なクラス設計の例を下記に示す。
Controller、UserSession、Repository、FileAccessorといったオブジェクトはJeffrey Palermo氏の説明</a>を参考に、EntityとVOといったオブジェクトは<a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html/">Robert Martin氏の説明</a>やEric Evans氏の説明を参考にしている。
![onion_architecture_sample_class_diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55214/78c97b37-a4b7-f432-6e1f-9b616a5d3a8f.png)



# オニオンアーキテクチャの教義

<a href="https://jeffreypalermo.com/author/jeffreypalermo/">Jeffrey Palermo</a>氏によると、下記がオニオンアーキテクチャの教義として挙げられている。

- アプリケーションのロジックは独立したドメインモデルを取り囲むように配置される。
- infrastructure層と別の内側の層にinterfaceを定義する。interfaceを定義した層とは別の外側の層がinterfaceを実装する。
- (依存性逆転の原則を利用しているため)依存の方向は常に外側の層から内側の層に向かう。
- application coreのロジック(*注1)はinfrastructure層から切り離される。

# 伝統的な階層化アーキテクチャとの違い
<a href="https://jeffreypalermo.com/author/jeffreypalermo/">Jeffrey Palermo</a>氏によると、オニオンアーキテクチャと伝統的な階層化アーキテクチャの違いは、階層間の呼び出し方や依存関係にあると説明されている。

## 階層間の依存関係の違い
伝統的な階層化アーキテクチャでは、基本的に一つ下の階層に依存する。UI層がData Access層に依存することはない。(*注2)

<img width="193" alt="traditional_architecture_comparison.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55214/ee94d890-3bc6-8972-919a-7a8df6534177.png">

一方オニオンアーキテクチャでは、外側の階層から内側の階層に依存する時、一つ下以外の内側の階層に対して依存することが可能である。

<img width="223" alt="onion_architecture_comparison.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55214/539e4ae3-8ec4-01a6-fdb5-764a2e106ebb.png">

## 円形による依存関係の表現
https://qiita.com/cocoa-maemae/items/e3f2eabbe0877c2af8d0#伝統的な階層化アーキテクチャが抱える課題
で説明したように、伝統的な階層化アーキテクチャでは、ビジネスロジックやデータアクセス層とinfrastrcture層の依存関係が密になってしまう特徴がある。
一方オニオンアーキテクチャでは、application coreからinfrastructure層のロジックを呼び出す際常にinterfaceを経由するため、infrastructure層の変更がビジネスロジック(内側の層)に影響を与えることがなくなる。よってビジネスロジックとinfrastrcture層の依存関係は伝統的な階層化アーキテクチャよりも疎になる。

![onion_dependency.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55214/d52e3185-1c44-068c-8b0d-69d5924d3ca8.png)


# まとめ
本記事ではオニオンアーキテクチャについて、階層構造、クラス設計、教義といった観点から説明してきた。オニオンアーキテクチャで新規性があるのは、依存性逆転の法則を利用してinfrastructure層とui(presentation)層を同じ階層位置として捉える点(*注3)と、ビジネスロジックを配置するdomain層とinfrastructure層の依存関係を疎にする点にあると思われる。この考え方は、オニオンアーキテクチャよりも後に提唱され、日本でも大ヒットしたクリーンアーキテクチャにも取り入れられている。


(*注1)Jeffrey Palermo氏のブログによると、application coreはapplication service, domain service, domain modelの３層に分離されているが、それぞれの層がどんな役割を持っているかまでは明確に説明されていない。

(*注2)Jeffrey Palermo氏はこの様に主張しているが、従来型の階層化アーキテクチャでもUI層からData Access層(ORMなど)を直接呼ぶことは可能であるため、この主張には疑問が残る。

(*注3)
オニオンアーキテクチャよりも前に提唱されたヘキサゴナルアーキテクチャも同じようにinfrastructure層とui(presentation)層を対称的な関係として捉えていた。


# 参考
- https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/
- https://jeffreypalermo.com/2008/08/the-onion-architecture-part-3/
- https://www.codeguru.com/csharp/csharp/cs_misc/designtechniques/understanding-onion-architecture.html
- https://tech.ovoenergy.com/onion-architecture/
- https://medium.com/@sergiis/stem-in-onion-architecture-or-fallacy-of-data-layer-9923f398f215
- https://blog.tai2.net/hexagonal_architexture.html
- https://qiita.com/gki/items/91386b082c57123f1ba0