オニオンアーキテクチャを整理してみた

# 背景・目的

# まとめ
下記に特徴を整理します

|特徴|説明|
|:--|:--|
|階層化アーキテクチャの問題点|結合に欠点を持ち、各レイヤーは、その下のレイヤーに結合され各レイヤーは様々なインフラの関心事に結合される<BR><BR>UIとビジネスロジックをデータアクセスに結合していることが最も大きな問題点<BR><BR>結合によりシステムの一部を簡単にアップグレードできない場合、ビジネスではシステムを後回しにして修理不能な状態にするしかない|
|オニオンアーキテクチャの特徴|結合を制御することを前提としている<BR><BR>基本的なルール<BR>・すべてのコードはより中心にあるレイヤーに依存する<BR>・コードはコアから離れたレイヤーに依存できない<BR>・すべての結合は中心に向かっている<BR><BR>依存性逆転の原則に大きく依存している|
|依存性逆転の原則|高レベルのポリシー設定モジュールから低レベルの依存モジュールに確立された従来の依存関係が逆転し、高レベルのモジュールが低レベルのモジュール実装の詳細から独立する|
|オニオンアーキテクチャの4つの原則|・アプリケーションは独立したオブジェクトモデルに基づき構築される<BR><BR>・内側の層はインターフェイスを定義する。外側の層はインターフェイスを実装する<BR><BR>・結合方向は中心に向かう<BR><BR>・すべてのアプリケーションコアコードはインフラとは別にコンパイル、実行が可能|


# 概要
下記の記事を基に整理します。

https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/

## オニオンアーキテクチャ Part1
### 現状の問題点
> 私は「オニオン アーキテクチャ」と呼んでいる特定のタイプのアーキテクチャについて何度か話してきました。システム全体で関心の分離を強調するため、このアーキテクチャはアプリケーションの保守性を高めることがわかりました。先に進む前に、このアーキテクチャの使用の背景を説明する必要があります。このアーキテクチャは小規模な Web サイトには適していません。長期間使用されるビジネス アプリケーションや複雑な動作を伴うアプリケーションに適しています。動作契約のインターフェイスの使用を強調し、インフラストラクチャの外部化を強制します。  

- オニオンアーキテクチャは、小規模なWebには向いてない
- 長期間使用されるビジネス アプリケーションや複雑な動作を伴うアプリケーションに適している
- 動作契約のインターフェイスの使用を強調し、インフラストラクチャの外部化を強制する

> ここで示す図は、従来の階層化アーキテクチャを表しています。これは、私が最も頻繁に使用している基本的なアーキテクチャです。後続の各レイヤーは、その下のレイヤーに依存し、その後、すべてのレイヤーは通常、いくつかの共通のインフラストラクチャとユーティリティ サービスに依存します。このトップダウンの階層化アーキテクチャの大きな欠点は、それが生み出す結合です。各レイヤーは、その下のレイヤーに結合され、各レイヤーはさまざまなインフラストラクチャの関心事に結合されることがよくあります。ただし、結合がなければ、システムは何も役に立ちませんが、このアーキテクチャは不要な結合を生み出します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/a105d728-e897-7584-a96a-134e36902d3d.png" width=400 />

※出典：[オニオンアーキテクチャ：パート1](https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/)

- 従来の階層化アーキテクチャ（トップダウン階層化アーキテクチャとよんでいる）
- 後続の各レイヤーは、その下のレイヤーに依存する
- すべてのレイヤーは通常、いくつかの共通インフラとユーティリティサービスに依存する
- 結合に欠点を持つ
    - 各レイヤーは、その下のレイヤーに結合され各レイヤーは様々なインフラの関心事に結合される

> 最も大きな問題 (そして最もよくある問題) は、UI とビジネス ロジックをデータ アクセスに結合していることです。はい、このアプローチでは、UI がデータ アクセスに結合されています。推移的な依存関係は、やはり依存関係です。ビジネス ロジックがなければ、UI は機能しません。データ アクセスがなければ、ビジネス ロジックは機能しません。ここでは、インフラストラクチャについては意図的に無視しています。これは通常、システムごとに異なるためです。データ アクセスは頻繁に変更されます。歴史的に、業界では少なくとも 3 年ごとにデータ アクセス手法が変更されています。したがって、ビジネスにとってミッション クリティカルな、健全で長寿命のシステムでは、3 年後にはデータ アクセスを変更する必要があると予想できます。システムを最新の状態に維持することは不可能であるため、多くの場合、システムを最新の状態に維持しません。結合によってシステムの一部を簡単にアップグレードできない場合、ビジネスではシステムを後回しにして修理不能な状態にするしかありません。このようにして、レガシー システムは古くなり、最終的には書き換えられます。

- UIとビジネスロジックをデータアクセスに結合していることが最も大きな問題点
    - UIがデータアクセスに結合されている
    - 推移的な依存関係だが、依存関係に変わりはない
    - ビジネスロジックがな変えれば、UIは機能しない。データアクセスがなければビジネスロジックは機能しない
- データアクセスは頻繁に変更される
    - 歴史的に、業界では少なくても3年ごとにデータアクセス手法が変更される
    - ビジネスにとってミッションクリティカルなシステムでは、3年後にはデータアクセスを変更する必要があると予想される
    - 多くの場合、システムを最新状態に維持しない。結合によりシステムの一部を簡単にアップグレードできない場合、ビジネスではシステムを後回しにして修理不能な状態にするしかない
    - その結果、レガシーシステムは古くなり、最終的には書き換えられる

### オニオンアーキテクチャの提案
> 私はアーキテクチャに対する新しいアプローチを提案します。  正直に言うと、完全に新しいものではありませんが、私はそれを名前付きのアーキテクチャ パターンとして提案しています。パターンは、ソフトウェア プロフェッショナルにコミュニケーションのための共通の語彙を提供するので便利です。オニオン アーキテクチャには多くの側面があり、このアプローチを説明する共通の用語があれば、より効果的にコミュニケーションできます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/acf5c282-74fc-be8a-7225-f44c5a7f689b.png" width=500 />

※出典：[オニオンアーキテクチャ：パート1](https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/)


> 左の図は、オニオン アーキテクチャを示しています。主な前提は、結合を制御することです。基本的なルールは、すべてのコードはより中心にあるレイヤーに依存できますが、コードはコアから離れたレイヤーに依存できないということです。言い換えると、すべての結合は中心に向かっています。このアーキテクチャは、オブジェクト指向プログラミングに明らかに偏っており、オブジェクトを他のすべてよりも優先します。

- 結合を制御することを前提としている
- 基本的なルール
    - すべてのコードはより中心にあるレイヤーに依存する
    - コードはコアから離れたレイヤーに依存できない
    - すべての結合は中心に向かっている

> 中心にはドメイン モデルがあります。これは、組織の真実をモデル化する状態と動作の組み合わせを表します。ドメイン モデルの周囲には、より多くの動作を持つ他のレイヤーがあります。アプリケーション コアのレイヤーの数は異なりますが、ドメイン モデルが中心であり、すべての結合が中心に向かっているため、ドメイン モデルはそれ自体にのみ結合されていることに注意してください。ドメイン モデルの周囲の最初のレイヤーには、通常、リポジトリ インターフェイスと呼ばれる、オブジェクトの保存と取得の動作を提供するインターフェイスがあります。ただし、オブジェクト保存の動作は、通常データベースが関係するため、アプリケーション コアには存在しません。アプリケーション コアにあるのはインターフェイスだけです。端には、UI、インフラストラクチャ、およびテストがあります。外側のレイヤーは、頻繁に変更されるもののために予約されています。これらのものは、アプリケーション コアから意図的に分離する必要があります。端には、リポジトリ インターフェイスを実装するクラスがあります。このクラスは、特定のデータ アクセス メソッドに結合されているため、アプリケーション コアの外部にあります。このクラスはリポジトリ インターフェイスを実装し、それによって結合されます。

- ドメインモデルが考え方の中心
    - ドメインモデルの周囲には、より多くの同左を持つ他のレイヤーがある
    - アプリケーションコアのレイヤーの数は異なるが、ドメインモデルが中心
    - すべての結合が中心に向かう
    - ドメインモデルは、それ自体にのみ結合されている
- ドメインモデルの周囲の最初のレイヤーは、通常リポジトリインターフェイスと呼ばれるオブジェクトの保存と取得の動作を提供するインターフェイスがある
- オブジェクト保存の動作は、通常データベースが関係するため、アプリケーション コアには存在しない
- アプリケーションコアにあるのはインタフェイスのみ
- 端には、UI、インフラ、テストがある
    - 外側のレイヤーは頻繁に変更されるもののために予約されている
    - アプリケーションコアから意図的に分離する必要がある
- 端にはリポジトリインターフェイスを実装するクラスがある
    - このクラスは、特定のデータアクセスメソッドに結合されているので、アプリケーションコアの外部にある
    - リポジトリインターフェイスを実装し、それにより結合される

> オニオン アーキテクチャは、依存性逆転の原則に大きく依存しています。アプリケーション コアにはコア インターフェイスの実装が必要であり、それらの実装クラスがアプリケーションのエッジに存在する場合は、アプリケーションが何か有用なことを実行できるように、実行時にそのコードを挿入するメカニズムが必要です。

- オニオンアーキテクチャは、依存性逆転の原則に大きく依存している
- アプリケーションコアにはコアインタフェイスの実装が必要、それらの実装クラスがアプリケーションエッジに存在する場合は、アプリケーションがなにか有用なことを実行できるように、実行時にそのコードを挿入するメカニズムが必要

> データベースは中心ではありません。外部にあります。   データベースを外部化することは、アプリケーションを「データベース アプリケーション」として考えてきた人にとっては大きな変化です。オニオン アーキテクチャでは、データベース アプリケーションは存在しません。データベースをストレージ サービスとして使用するアプリケーションはありますが、それはアプリケーション コアにとって意味のあるインターフェイスを実装する外部インフラストラクチャ コードを介してのみです。アプリケーションをデータベース、ファイル システムなどから分離すると、アプリケーションの存続期間中のメンテナンス コストが削減されます。

- DBは中心ではない。外部にある
- オニオンアーキテクチャでは、データベースアプリケーションは存在しない
    - DBをストレージサービスとして使用するアプリはあるが、アプリケーションコアにとって意味のあるI/Fを実装する外部インラフコードを介してのみ
    - アプリをDBファイルシステムから分離すると、アプリケーションの存続期間中のメンテコストが削減される

### 依存性逆転の原則
下記を基に整理します。

https://en.wikipedia.org/wiki/Dependency_inversion_principle

> オブジェクト指向設計において、依存性逆転の原則は疎結合ソフトウェアモジュールに特有の方法論である。この原則に従うと、高レベルのポリシー設定モジュールから低レベルの依存モジュールに確立された従来の依存関係が逆転し、高レベルのモジュールが低レベルのモジュール実装の詳細から独立するようになる。

- オブジェクト指向設計では、依存性逆転の原則は、疎結合ソフトウェアモジュールに特有の方法論
- この原則に従うと、高レベルのポリシー設定モジュールから低レベルの依存モジュールに確立された従来の依存関係が逆転し、高レベルのモジュールが低レベルのモジュール実装の詳細から独立する

> この原則は次のように述べている。
> - 高レベルモジュールは低レベルモジュールから何もインポートしないでください。両方とも抽象化 (インターフェースなど) に依存する必要があります。
> - 抽象化は詳細に依存すべきではありません。詳細 (具体的な実装) は抽象化に依存すべきです。

- 原則
    - 高レベルモジュールは、低レベルモジュールから何もインポートしない
        - 両方とも抽象化（I/Fなど）に依存する必要がある
    - 抽象化は詳細に依存すべきではない。詳細（＝具体的な実装）は抽象化に依存すべき

> この設計原則は、高レベルオブジェクトと低レベルオブジェクトの両方が同じ抽象化に依存しなければならないと規定することで、一部の人々がオブジェクト指向プログラミングについて考える方法を逆転させます。 

- この設計原則は、高レベルオブジェクトと低レベルオブジェクトの両方が同じ抽象化に依存しなければならないと規定する
- これにより、一部の人々がオブジェクト指向プログラミングについて考える方法を逆転させる

#### 伝統的なレイヤーパターン
> 従来のアプリケーションアーキテクチャでは、下位レベルのコンポーネント（ユーティリティ層など）は、より複雑なシステムの構築を可能にする上位レベルのコンポーネント（ポリシー層など）によって使用されるように設計されています。この構成では、上位レベルのコンポーネントは、何らかのタスクを達成するために下位レベルのコンポーネントに直接依存しています。この下位レベルのコンポーネントへの依存により、上位レベルのコンポーネントの再利用の機会が制限されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/347db217-ed6f-2818-ec02-a69b6c596d48.png)

出典：[伝統的なレイヤーパターン](https://en.wikipedia.org/wiki/Dependency_inversion_principle#Traditional_layers_pattern)

- 従来のアプリケーションアーキテクチャでは、下位レベルのコンポーネント（ユーティリティ層など）は、より複雑なシステムの構築を可能にする上位レベルのコンポーネント（ポリシー層など）によって使用されるように設計されている
- 上位レベルのコンポーネントは、何らかのタスクを達成するために下位レベルのコンポーネントに直接依存する
- これにより、上位レベルのコンポーネントの再利用の機会が制限される

> 依存性逆転パターンの目的は、抽象レイヤーの仲介によってこの高度に結合された分散を回避し、上位レイヤー/ポリシー レイヤーの再利用性を高めることです。

- 抽象レイヤーの仲介により、高度に結合された分散を回避し、上位レイヤー/ポリシーレイヤーの再利用性を高めることが目的


#### 依存性逆転パターン
> 抽象レイヤーの追加により、上位レイヤーと下位レイヤーの両方で、上から下への従来の依存関係が削減されます。ただし、「反転」の概念は、下位レイヤーが上位レイヤーに直接依存することを意味するものではありません。両方のレイヤーは、上位レイヤーに必要な動作を公開する抽象化 (インターフェース) に依存する必要があります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/0aae5057-54c0-ee4d-6f63-1406fab44382.png)

出典：[依存性逆転パターン](https://en.wikipedia.org/wiki/Dependency_inversion_principle#Dependency_inversion_pattern)

- 抽象レイヤーの追加により、上位レイヤーと下位レイヤーの療法で、上から下への従来の依存関係が削減される
- 「逆転」の概念について
    - 下位レイヤーが上位レイヤーに直接依存することを意味するのではない
    - 両方のレイヤー上位レイヤに必要な動作を公開する抽象化（I/F）に依存する

> 依存性逆転の直接的な応用では、抽象は上位層/ポリシー層によって所有されます。このアーキテクチャは、上位/ポリシーコンポーネントと下位のサービスを定義する抽象化を同じパッケージにグループ化します。下位層は、これらの抽象クラスまたはインターフェースの継承/実装によって作成されます。

- 抽象は、上位層/ポリシー層により所有される

> 依存関係と所有権の反転により、上位層/ポリシー層の再利用性が促進されます。上位層は下位サービスの他の実装を使用できます。下位層のコンポーネントが閉じられている場合、またはアプリケーションが既存のサービスの再利用を必要とする場合は、アダプタがサービスと抽象化の間を仲介するのが一般的です。

- 依存関係と所有権の反転により、上位層/ポリシー層の再利用性が促進される
- 上位層は下位サービスの他の実装を使用できる
- 下位層のコンポーネントが閉じられている場合、またはアプリが既存のサービスの再利用を必要とする場合は、アダプタがサービスと抽象化の間を仲介するのが一般的


## オニオンアーキテクチャ：パート3
> このシリーズのパート 3 の目標は、オニオン アーキテクチャと従来の階層化アーキテクチャを比較対照することです。オニオン アーキテクチャをフラット化して、従来の階層化アーキテクチャと比較した場合の外観を確認し、階層化アーキテクチャをオニオンの形にします。形状はどちらでもかまいませんが、実際のアプリケーションの構造は、一般に知られ、受け入れられているものとは根本的に異なります。最後に、オニオン アーキテクチャの 4 つの原則を定義します。

- オニオンアーキテクチャと階層化アーキテクチャを比較する



> 復習しましょう。従来の階層化アーキテクチャは、右の図のような外観になります。各レイヤーは、その下のレイヤーと通信します。UI はビジネス ロジックと通信しますが、データ アクセスや WCF などとは直接通信しません。階層化アプローチでは、特定のカテゴリのコードを UI から除外する必要があります。大きな欠点は、ビジネス ロジックがインフラストラクチャの問題と結びついてしまうことです。データ アクセス、I/O、Web サービスはすべてインフラストラクチャです。インフラストラクチャとは、コモディティであり、アプリケーションに競争上の優位性を与えないコードのことです。このコードは、アプリケーションが何年もメンテナンスされるにつれて頻繁に変更される可能性が高くなります。Web サービスはまだかなり新しいもので、.Net の最初のバージョンである ASMX は、WCF に取って代わられて既に廃止されています。WCF の時代も終わりに近づいていると確信できます。したがって、ビジネス ロジックを WCF に密に結合するのは愚かなことです。データ アクセスは 2 年ごとに変更されるため、密に結合することは絶対に避けてください。長期にわたって使用するには、インフラストラクチャが変更されてもビジネス ロジックを変更する必要がないように、ビジネス ロジックをこれらのインフラストラクチャの問題から独立させる必要があります。

- 階層化アーキテクチャ
    - 各レイヤーは、その下のレイヤーと通信する
        - UIはビジネスロジックと通信するが、データアクセスやWCFなどとは直接通信しない
    - ビジネスロジックがインフラの問題と結びついてしまう
        - インフラとは、I/O、データアクセス、Webサービスなど
    - データアクセスは2年ごとに変更されるので密結合は避けるべき
    - インフラが変更されてもビジネスロジックを変更する必要がないように、ビジネスロジックをインフラの問題から独立させる必要がある

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/76a8a209-e8e8-9b0b-260f-4d91639613b8.png" width=400 />

出典：[オニオンアーキテクチャ：パート3＞従来の階層化アーキテクチャ](https://jeffreypalermo.com/2008/08/the-onion-architecture-part-3/)

> オニオン アーキテクチャを復習しましょう。オブジェクト モデルは中心にあり、ビジネス ロジックがその周りにサポートされています。結合の方向は中心に向かっています。大きな違いは、どの外側のレイヤーもどの内側のレイヤーも直接呼び出すことができることです。従来の階層化アーキテクチャでは、レイヤーはすぐ下のレイヤーしか呼び出せません。  これが、オニオン アーキテクチャが従来の階層化アーキテクチャと異なる重要なポイントの 1 つです。インフラストラクチャは、ビジネス ロジック コードが結合しないエッジに押し出されます。データベースと対話するコードは、アプリケーション コアにインターフェイスを実装します。アプリケーション コアはそれらのインターフェイスに結合されますが、実際のデータ アクセス コードには結合されません。このようにして、アプリケーション コアに影響を与えることなく、任意の外側のレイヤーのコードを変更できます。長期間使用されるアプリケーションにはテストが必要であるため、テストを含めます。アプリケーション コアはテストに結合されていないため、テストは外側に配置されますが、テストはアプリケーション コアに結合されます。UI とインフラストラクチャ コードをテストするときに、外側全体に別のテスト レイヤーを配置することもできます。

- オニオンアーキテクチャ
    - オブジェクトモデルは中心
    - ビジネスロジックがその周囲にサポートされている
    - 結合の方向は中心に向かう
    - どの外側のレイヤーもどの内側のレイヤを呼び出せる
    - インフラは、ビジネスロジックコードが結合しないエッジに押し出される
    - DBと対話するコードは、アプリケーションコアにI/Fを実装する
    - アプリケーションコアはそれらのI/Fに結合されるが、実際のデータアクセスコードには結合されない
    - アプリケーションコアに影響を与えず、任意の外側のレイヤーのコードを変更できる
    - 長期間使用されるアプリケーションにはテストが必要であるため、テストを含める

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/1df93dd8-60ce-0865-9983-f57828cfe308.png" width=500 />

出典：[オニオンアーキテクチャ：パート3＞オニオンアーキテクチャ](https://jeffreypalermo.com/2008/08/the-onion-architecture-part-3/)

### オニオンアーキテクチャの主要な原則:
> - アプリケーションは独立したオブジェクトモデルに基づいて構築されている
> - 内側の層はインターフェースを定義します。外側の層はインターフェースを実装します。
> - 結合方向は中心に向かう
> - すべてのアプリケーションコアコードはインフラストラクチャとは別にコンパイルおよび実行できます。

- アプリケーションは独立したオブジェクトモデルに基づき構築される
- 内側の層はインターフェイスを定義する。外側の層はインターフェイスを実装する
- 結合方向は中心に向かう
- すべてのアプリケーションコアコードはインフラとは別にコンパイル、実行が可能


# 考察
今回、オニオンアーキテクチャをまとめてみましたが、まだまだ理解できてない点が多く、本ページでは文章にまとめた程度です。
継続して学習していきたいと思います。

# 参考

https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/

https://jeffreypalermo.com/2008/08/the-onion-architecture-part-3/

https://en.wikipedia.org/wiki/Dependency_inversion_principle