Unityで始めるオニオンアーキテクチャ　はじめの一歩

# 今回の内容
Unityでオニオンアーキテクチャを採用して開発をするための第一歩として、
スクリプトの構成のルールや導入したライブラリ等をまとめたものになります。

本記事の対象読者
1.ドメイン駆動設計の概要を理解している方
2.オニオンアーキテクチャの概要を理解している方
3.Unityの「Assembly Definition File」の概要を理解している方
4.Unityでアーキテクチャ設計を実践してみたいと考えている方

# 目次
1.ドメイン駆動設計とは
2.オニオンアーキテクチャとは
3.Assembly Definition Fileとは
4.フォルダレイアウト
5.asmdefの設定の例
6.その他
7.まとめ

# ドメイン駆動設計とは
> ドメイン駆動設計（Domain-Driven Design, DDD）は、複雑なビジネスドメインを効果的にモデリングし、ソフトウェア開発においてビジネスロジックを中心に据える設計手法です。DDDの主な目的は、ビジネスの要件を正確に反映し、柔軟で保守性の高いシステムを構築することです。

#### ドメイン駆動について詳しく知りたい方向け
#### 書籍
[ドメイン駆動設計入門 ボトムアップでわかる！ドメイン駆動設計の基本](https://amzn.asia/d/fDBr3wc)
[エリック・エヴァンスのドメイン駆動設計](https://amzn.asia/d/cp0kHEN)
#### 記事　
[ドメイン駆動設計とは何か？その基本概念と重要性について](https://www.issoh.co.jp/tech/details/3580/)
 [ドメイン駆動設計とは？目的やメリットなどをわかりやすく解説](https://it.webcli.jp/topics/domaindrivendesign/)
 
# オニオンアーキテクチャの概要
オニオンアーキテクチャとは、DDDの原則に基づいて設計されたソフトウェアアーキテクチャです。
このアーキテクチャは、システムを4つの層に分割し、外から中心に向かって依存をします。

アーキテクチャ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116386/58a6b953-0161-e718-967d-b5609b58b74c.png)

1.ドメイン層
>アプリケーションのビジネスルールとエンティティ（モデル）を定義します。

2.アプリケーション層
> ドメイン層のビジネスロジックを使用して、具体的なユースケースを実現します。
※インターフェースのみ配置する場合もあります。

3.インフラストラクチャ層
> インフラストラクチャリソース（データベース、メッセージキュー、APIクライアントなど）を提供します。

4.プレゼンテーション層(UI層)
> ユーザーがシステムとやり取りを行う。UnityにおけるMonoBehaviourとの連携を行う。

オニオンアーキテクチャについて詳しく知りたい方向け

https://qiita.com/cocoa-maemae/items/e3f2eabbe0877c2af8d0

https://qiita.com/k_yamaki/items/bf99d3bf64a84258a3a1

#### その他、設計について参考になる書籍
[良いコード/悪いコードで学ぶ設計入門](https://amzn.asia/2r4pP6b)
[Clean Architecture 達人に学ぶソフトウェアの構造と設計](https://amzn.asia/4ZihS5A)
[Adaptive Code C#実践開発手法　第2版](https://amzn.asia/d/4VA7gUI)

# Assembly Definition Fileとは
.asmdef拡張子を持つアセンブリ定義のプロパティが定義されたファイルで、Unityが提供している機能です。
以下、Assembly Definition Fileをasmdefとします。
#### asmdefファイルを追加する目的
各レイヤ（オニオンアーキテクチャのレイヤ）ごとに、モジュール化することで依存関係を明確にするためです。
asmdefファイルは、どのDLLに依存するかを設定できるため、アーキテクチャのルールを強制することができます。（例：ドメイン層はインフラ層に依存しないなど）
また、Unity Test Runnerを使ったユニットテストも特定のレイヤのみをテストすることできるので、テストの効率が向上し、コードの保守性を高めることができます。

## フォルダレイアウト
Unityでオニオンアーキテクチャを実践する際は、各層の責務を明確に分けることが重要です。
以下は、私が個人で開発するにあたって採用したフォルダレイアウトになります。

```
Assets
    └─ Scripts
        └─ Domain        
            └─ UserInfo 　　　　　　 // モジュール化 
        └─ Application                    
            └─ UserInfoServices 　　// モジュール化
        └─ Infrastructure        
            └─ UserInfoRepository 　// モジュール化
        └─ Presentation  
            └─ Title 　　　　　　　  // モジュール化
                ├─ Models                 
                ├─ Presenters
                └─ Views
            └─ Home                 // モジュール化
                ├─ Models                 
                ├─ Presenters
                └─ Views
            └─ Profile              // モジュール化
                ├─ Models                 
                ├─ Presenters
                └─ Views
```
※ モジュール化 (DLLを分割する単位)

### モジュール化する単位について

__ドメイン層、アプリケーション層、インフラ層__
- 分割単位: 機能単位
- 利点: 各層が独立して動作し、変更の影響範囲を最小限に抑えることができます

__プレゼンテーション層__
- 分割単位: 画面単位
- 利点: UIの変更や追加が容易になります

### モジュールの依存関係を示すダイアグラム
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116386/26a58830-40cc-1296-8715-1cd4af6cc6a9.png)

# asmdefの設定の例
#### 各レイヤーの共通項目
__RootNamespace__ とアセンブリ名を同じ文字列にする
__Auto Referenced__ のチェックを外す。(Assembly-Csharpから参照をさせない)

##### ドメイン層
- __No Engine References__ にチェックを入れ、UnityEngineへの依存を切る
- その他ライブラリの参照もできるだけ避ける。ただし、__UniTask__ や __R3__ が必要になる場合は、これらのライブラリを参照してもよい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116386/667372ac-5812-bd3d-0564-ea397e6a6ca7.png)

#### アプリケーション層、インフラ層、プレゼンテーション層
- 基本方針は上記と変わらない
- __Assembly Definition References__ に参照するアセンブリを設定する。このとき、アーキテクチャのルールに従う
- __MonoBehaviourを継承するのは、プレゼンテーション層のみ__ する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116386/08688d7f-2a71-853c-f431-7905e52ccbb8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116386/ab2f53e1-a522-40df-a6af-3341940fee19.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116386/a2086c59-7838-5dc7-eabe-bc5fb304a8c4.png)
※プレゼンテーション層は、参照するアセンブリが増える

# その他
__DI Container__ の利用が必須になります。
下記のブログで紹介されている __ScrrenSystem__ は、
必要なライブラリ等も揃っているので、かなりとっつきやすいと思います。

https://tech.mirrativ.stream/entry/2023/09/22/112042

# まとめ
Unityのゲーム開発でオニオンアーキテクチャを実践するにあたって、私が実践したフォルダレイアウトやモジュール化の単位、必要なルールについて記載しました。
これにより、保守性が高く、将来の変更や追加に対応しやすいシステムを構築するための重要なステップを踏むことができます。
この記事が皆さんの開発に少しでも役立てば嬉しいです。
ぜひ、参考にして、実際に試してみてください！