CleanArchitecture入門

# CleanArchitectureについて学ぶ目的
- 可読性の高いコードをかけるようにする
- チーム内の共通認識として持てるような実装方針を習得する

# 要約
- CleanArchitectureとは、関心の分離に着目したソフトウェアの設計手法のこと
    - アーキテクチャといいつつインフラ設計ではなくコードの詳細設計や実装に関するもの
- CleanArchitectureの規約はコード全体を4つの階層に分けて**依存関係の向きをビジネスロジックと遠いものから近いものへと統一**させることだけ
- ビジネスロジックとフレームワークを遠ざけることで変更に強く寿命が長いコードを目指す

# CleanArchitectureとは
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3239333336382f37636531666231302d353034652d313665302d383933302d3237386238613766393432642e6a706567.jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1981935/91f2d947-9aac-7611-7711-7b105632b635.jpeg)
ソフトウェアの設計手法の一つで、**規約は以下の一つのみ**

まずアプリを以下の4つの階層に分ける
- <font color="Gold">**Enterprise Business Rules**</font>
- <font color="Red">**Application Business Rules**</font>
- <font color="LimeGreen">**Interface Adapters**
- <font color="SkyBlue">**Frameworks & Drivers**

そして依存関係を<font color="SkyBlue">**Frameworks & Drivers**</font>→<font color="Gold">**Enterprise Business Rules**</font>
という方向に統一する

例を出すと
:o:
- <font color="SkyBlue">**Frameworks & Drivers**</font>→<font color="LimeGreen">**Interface Adapters**</font>
- <font color="LimeGreen">**Interface Adapters**</font>→<font color="Gold">**Enterprise Business Rules**</font>

:x:
- <font color="Gold">**Enterprise Business Rules**</font>→<font color="Red">**Application Business Rules**</font>
- <font color="Red">**Application Business Rules**</font>→<font color="SkyBlue">**Frameworks & Drivers**

## 各階層について
上で整理した階層についてそれぞれの役割を確認する

### <font color="Gold">Enterprise Business Rules</font>
CleanArchitectureの最も内部にあるレイヤー
主にモデルと呼ばれるUIやDB等と一切依存関係がないビジネスロジックをカプセル化したクラスを定義する

例
- WEBサービスのユーザークラス
    - 名前、メールアドレス、年齢、名前のバリデートメソッドetc

```typescript
export class User {
  public name: string;
  public age: number;
  public email: string;

  constructor(name: string, age: string, email: string) {
     // init
  }

  public validateName(): boolean {
     // validate
  }
}
```

### <font color="Red">Application Business Rules</font>
Enterprise Business Rulesの外側にあるレイヤー
ユースケースを書くことになる

ユースケースとはモデルを操作する一連の処理をまとめたクラスないし関数のこと

例
- ユーザーを新規作成するユースケース
    - ユーザーのインスタンス生成→DBやファイルストレージへ保存→完了メッセージを返すなど

```typescript
export class CreateUserUsecase {
  private userRepository: UserRepository;

  public execute() {
    const user = new User();
    this.userRepository.add(user);
  }
}
```

:::note
ある処理をモデルに書くかユースケースに書くかの判断基準としては以下の通り

- UIやDBと依存しない→モデル
- UIやDBと依存する→ユースケース

ユーザーを新規作成する場合はそのユーザーを何らかのリポジトリに保存する必要がある=DBとの依存関係があるのでユースケース
:::

### <font color="LimeGreen">Interface Adapters
Application Business Rulesの外側にあるレイヤー

クライアントやDBなどアプリの外側にあるものとアプリ本体との橋渡し役
HTTPリクエストやHTML Formイベントのバリデート、DBのレコードとプログラムのオブジェクトの相互変換など
また、ライブラリもFrameworks & Driversに置くことになるのでそれの抽象化をしたい場合もここ

```typescript
export class UserRepository {
  private datebase: Database;

  public add(user: User) {
    this.database.add(user);
    this.database.flush();
  }
}
```

### <font color="SkyBlue">Frameworks & Drivers
CleanArchitectureで一番外側にあるレイヤー

各種フレームワークやDBに関する処理を記述する
MySQLにコネクションを貼る、WEBフレームワークで仮想DOMを記述するなど

## 変更に強いコード
上記の通りレイヤーを切って実装すると以下のようになる
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1981935/ff2b7f88-a1bb-a967-f473-ba1b4e16267a.png)
変更頻度が高いレイヤーほど他レイヤーから依存されにくく、飛行頻度が低いレイヤーほど他レイヤーから依存されやすい

ここで、<font color="Gold">Enterprise Business Rules</font>と<font color="SkyBlue">Frameworks & Drivers</font>それぞれが変更されたケースを考える

### <font color="Gold">Enterprise Business Rules</font>
<font color="Gold">Enterprise Business Rules</font>が変更されたとき、このレイヤーは<font color="Red">Application Business Rules</font>に依存されているためこちらも変更する必要がある
さらに、<font color="Red">Application Business Rules</font>は<font color="LimeGreen">Interface Adapters</font>に依存されており...と芋づる式に次々と変更の必要性が生じてしまい大変
しかし、そもそも変更頻度が一番低いレイヤーなので(正しく設計できていれば)このリスクは十分許容範囲内

### <font color="SkyBlue">Frameworks & Drivers</font>
<font color="SkyBlue">Frameworks & Drivers</font>はライブラリのバージョンアップやインフラの移行に伴うDBドライバの換装など変更頻度が非常に多い
しかしこのレイヤーは他レイヤーから依存されることは一切ないため、変更の影響範囲はこのレイヤー内で完結する

:::note
CleanArchitectureの規約を遵守し変更頻度が高いモジュールを外側のレイヤーに配置することで影響範囲を最小限度にとどめることができる
これにより変更に強く寿命が長いコードを書くことが可能になる
:::

# CleanArchitectureのTIPS
CleanArchitectureの規約を守るため、あるいはこのアーキテクチャと特に相性がいいために使われるあれこれをまとめる

:::note
CleanArchitectureの規約は**依存関係の向きを統一させることだけ**
これ以降の話はこの規約を達成させるための手法、あるいは単に相性のいいツール類の紹介であってこのアーキテクチャの本質ではないことに注意
:::

## DIP(依存関係逆転の原則)
Interfaceを介すことによってクラス間の依存関係を逆転させること

CleanArchitectureにおいては以下のような問題を解決するために用いられる
例えば以下のような依存関係を考える
```plantuml
@startuml

package "Domain" #back:Gold {
  class User {
    +id: string
    +name: string
  }
}

package "Application" #back:Tomato {
  class CreateUserUsecase {
    -userRepository: UserRepository
    --
    +execute()
  }
}

package "Adapter" #back:LimeGreen {
  class UserRepository {
    -database: TypeOrm
    --
    +add()
  }
}

package "Infrastructure" #back:SkyBlue {
  class TypeOrm {
  --
  add()
  }
}

User <-- CreateUserUsecase
CreateUserUsecase --> UserRepository
UserRepository --> TypeOrm
@enduml
```
ユーザーを新規作成するCreateUserUsecaseの依存関係を表しているが、`CreateUserUsecase→UserRepository`と`UserRepository→TypeOrm`の依存関係がCLeanArchitectureの規約違反となってしまっている
このように規約違反となる依存関係にせざるを得ない問題を以下のようにinterfaceを介して解決する

```plantuml
@startuml

package "Domain" #back:Gold {
  class User {
    +id: string
    +name: string
  }
}

package "Application" #back:Tomato {
  class CreateUserUsecase {
    -userRepository: UserRepository
    --
    +execute()
  }
  interface UserRepository {
    +add()
  }
}

package "Adapter" #back:LimeGreen {
  class UserRepositoryImpl {
    -database: TypeOrm
    --
    +add()
  }
  interface Database {
    +add()
  }
}

package "Infrastructure" #back:SkyBlue {
  class TypeOrm {
  --
  add()
  }
}

User <-- CreateUserUsecase
CreateUserUsecase -right-> UserRepository
UserRepository <|-down- UserRepositoryImpl
UserRepositoryImpl -right-> Database
TypeOrm -up-|> Database
@enduml
```

このように依存先をクラス本体ではなくインターフェースにすることで自身の外側ではなく同じレイヤーに依存させることができCleanArchitectureの規約を遵守することができる

:::note
外側のレイヤーに依存せざるを得ない場合には同レイヤーにインターフェースを切ってそれに依存させ、外側のレイヤーでそのインターフェースを実装したクラスを書くようにして解決する
:::

## DI(依存性注入)
あるプログラムが別のプログラムに依存している状態を切り離し、外部からその依存性を注入すること
例えば以下のようなコード
```typescript
class CreateUserUsecase {
  private userRepository: UserRepository;

  constructor() {
    this.userRepository = new UserRepository();
  }

  public execute() {
    this.userRepository.add(new User());
  }
}
```

このコードではクラスのコンストラクタ内で依存関係のある`UserRepository`のインスタンスを生成している
このような依存のさせ方では外部から依存関係のあるインスタンスを注入することができないため単体テスト等が非常に面倒になってしまう
そのため以下のように書き換える

```typescript
class CreateUserRepository {
  private userRepository: IUserRepository;

  constructor(userRepository: IUserRepository) {
    this.userRepository = userRepository;
  }

  public execute() {
    this.userRepository.add(new User());
  }
}
```

こうすることでこのクラスを初期化する際に依存するモジュールを外部から注入することができるようになる
```typescript
// 通常の使い方
const createUserRepository = new CreateUserRepository(new UserRepoisotry());
// UTでモックを突っ込んでしまう
const createUserRepository = new CreateUserRepository({add: addMock});
```

### tsyringe
TypeScriptの場合[tsyringe](https://github.com/microsoft/tsyringe)というライブラリを使うことでDIを実現できる

DIコンテナと呼ばれるクラスに対して依存性を登録し、依存性の注入対象をアノテーションで指定することによって自動的に依存関係を解決してくれる

```typescript
import { container } from 'tsyringe';

// コンテナに依存性を登録
container.register('UserRepository', { useClass: UserRepository });

// 依存関係を解決
const usecase = container.resolve(CreateUserUsecase);
```

```typescript
import { injectable, inject } from 'tsyringe';

@injectable() // 依存性を注入する対象であることを示す
class CreateUserUsecase {
  constructor(
    @inject('UserRepository') // 依存性をこのフィールドに注入
    private userRepository: UserRepository
  ) {}

  public execute() {
    this.userRepository.add(new User());
  }
}
```

:::note
CleanArchitectureに則ったプログラミングではどうしてもファイル数、クラス数が嵩むのでDIによってインスタンス生成の手間とパフォーマンス低下を軽減しよう
:::