Clean Architecture の勘所は『鎖国』だ。

# ■ クリーンアーキテクチャって難しい。

![CleanArchitecture_Petit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/2a1e8fe9-5d9f-d6bb-c410-073558397292.png)

クリーンアーキテクチャって難しいですよね。
この有名な同心円状の図、何度見てもよくわかりません。右下にある矢印もよくわかりません。
様々な記事を見ても、やっぱり分かるような分からないような...

プロダクトに COM 通信が必要になったので勇んでクリーンアーキテクチャを採用したはいいものの、
どうにも理解しきれず泣きながら必死に試行錯誤をしていたところ、
ふと **クリーンアーキテクチャは『鎖国』に例えると分かりやすい** という事に気が付きました。

本記事では初心者なりにその言語化にチャレンジしてみたいと思います。
※ なお考え方そのものに着目するため、コードは全く取り扱いません。その点ご了承ください。

またクリーンアーキテクチャは、表面的なメリット(ユニットテストしやすい等)　だけを見て批判されてしまうことも有るようです。
その辺りについても少し触れてみようと思います。


--------
# ■ 結論: クリーンアーキテクチャ is 鎖国.

超絶ざっくり言うと、クリーンアーキテクチャとは、

#### **鎖国して、出島でのみ外界と貿易することで、国内をきれいに保つための『方法論』** です。

　
**貿易を出島でのみに制限する** ことで、列強諸国から **国宝のビジネスロジックを守る** のです。
ドメインを大切にする DDD 的な考え方ですね。

この**「鎖国」と「出島」**、**「外界」と「国内」** という概念のイメージがとても大切です。
**今までの多重円の図はいったん忘れてください。**

　
まずは導入として、下図をイメージすると良いでしょう。
この段階では、例の図とは違って **出島と業務ロジックの2層構造** になります。

![危険が一杯2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/45f6a6bd-36d1-55e6-a7e7-ae4332567f31.png)

**たとえそれが DB でも、キャッシュでも、WebAPI でも、フレームワークでも(！）、UI でも(！)、UI 入力でも...**
相手が何であれ、外界の都合つまり**『自分のビジネスロジック以外の都合』**を持ち込ませたくないのです。
そのため出島を作って、更に出島と国内を門と橋で隔てます。

全ては**『自分のシステムで本当に実現したいことだけ』** に集中できるように、モデルや関心、構造、依存関係を **『クリーン』** に保つためです。
だから**『クリーンアーキテクチャ』**なのです。

#### **『(ビジネスロジックが)クリーン(になる)アーキテクチャ』** と言うとイメージしやすいでしょうか。


------------

また、名前に 「アーキテクチャ」 とついていますが、**国内の細かな構造は実は指定されていないようです。**
統治の方法は民主主義でも共産主義でも封建主義でも何でもよくて、クリーンアーキテクチャの方向性に則ってさえいればよいのです。

原著には『4層でなくてもいい』とすら書かれています。
> No, the circles are schematic. You may find that you need more than just these four. 
There’s no rule that says you must always have just these four.

そう、有名な多重円の図は、あくまでもその **考え方の方向性** を示しているだけの資料です。
いきなり多重円の図を完璧に理解して寸分違わず作ろうすると辛くなります。

辛くならないように、この記事では順を追って図を詳細にしていきます。
※ 私自身が作ったシステムもこの図と全く同じようには作っていませんが、まずは理想論として掘り下げます。


------

# ■ 鎖国しないとどうなるか (今までの一般的なN層アーキテクチャ)


今までの**N層アーキテクチャでは、国内のいたる所にある港で、皆が好き勝手に交易** していました。
この状態でも上手く国が統治できている間は特に問題ありません。

しかし国土が増え人口が増加してくると、**目の行き届かない港** が出来てきます。
**そこに突如黒船がやってきて、彼らのとんでもなく汚いモデルや文化の合わないモデルを大砲で押し付けてくる** のです。
**宣教師を送り込んでくる** 場合もあります。

![4層(絶望).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/9e629680-36fe-399b-8599-ee3886d6d598.png)

言い換えましょう。
**ビジネスロジックの中で直接DBやCache、外部システムなどを利用している** ので、
**ビジネスロジックと外部の世界につなげるためのコードが癒着しやすく**、
**自分以外が作った使いづらいモデルや API に気が付かずに影響されたり、自分たちの仕組みを合わせざるを得なくなる** のです。(トランザクションとか)
**強烈なKUSO構造を押し付けられる場合もあります。** (COMとかマジきつい)
結果として、**ビジネスロジックへ、本質的にビジネスロジックとは関係のない知識が紛れ込んでしまう** のです。(依存強くて修正きつい)

　
こちらも本当は大砲で打ち返したいのですが **大抵の場合は外国の方がつよつよ** なので、
私達のモデルは砲弾で穴だらけにされ、焼け落ちた国土は毒で汚染され尽くしてしまい作物は育たず、
占領軍の暴虐無人な振る舞いにうつむき涙を流しながら残業を余儀なくされてしまいます。

### そう、「外国は全て敵」 なのです。



-------

# ■ ならば、自由に貿易させなければよい。

### これがクリーンアーキテクチャの **一番の勘所** です。

自分たちのシステムとその大切な業務ロジックを守るために、
**自分たちのシステムの一番外側に出島をつくり、そこでのみ外界との交易を許可する** のです。
(オニオン、ヘキサゴナルも同様です。)

危険なものを国内に持ち込ませないように。悪い文化に影響されないように。
**輸入するものも輸出するものも全て幕府が検閲する** ようにします。

![同心円プラス出島2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/5f27137b-b90f-5335-c647-7d86bc4777af.png)



具体的には、

  - 国内と出島を結ぶ橋を封鎖し門をつけて、国内から出島の存在を隠す
  - 輸入するものは汚いので、**「洗浄して」こちらの指定するきれいな木箱に積み替える**
  - 輸出する時は、木箱を勝手に使われて難癖つけられないように、**相手の指定する木箱に積み替える**

このような施策をとります。




**輸出入とその詰め替えが出島でのみ行われる** ため、
出島よりも内側にある **『ビジネスロジック』** では、浄化された「自分たちだけのきれいなモデル」を使うことが出来るようになります。

そこには外界の都合に一切振り回されない、自分たちのドメインが興味を持つ言葉のみで組み上げた幸せな世界があります。
(完璧にいかないことも多いけれど。)

　
> ただしご想像の通り、こうした理想郷を追い求めるがために、
> 一般的な N層アーキテクチャで作るよりも工夫が必要ですし、コード量も増大する傾向にあります。
> トレードオフってやつですね。当然向き不向きもあります。


--------


# ■ どうやって実装していくの？

## □ まずは一つの出島から考える
言葉だけだと難しいので、まずは **1つの出島だけを切り出してイメージ** してみます。

今まではただ**「出島」**と呼んでいましたが、**出島には「港(External Interfaces）」と「税関(Interface Adapters)」の2つがあります。**
またビジネスロジック部分も、元の多重円図の用語だと非常に紛らわしいのでイメージしやすいように
**「Application Business Rules」** を **「UseCase」** と、 **「Enterprise Business Rules」** を **「Business Logics」** と呼称します。

![一直線の場合_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/4745f968-ec88-8772-c485-477293e4cd3b.png)

いきなり図が詳細になってしまいました。
重要なポイントは以下のとおりです。

#### ビジネスロジックをクリーンに保ち、外界の都合に左右されないように・・・

- **依存関係を外から内の一方通行** とする。
- **外界から入ってくるもの** は **ExternalInterface で受け取り**、**InterfaceAdapters で綺麗なクラスへ詰め替える。**
- **外界へ出ていくもの** は **InterfaceAdapters で外部向けの形に変換して ExternalInterfaces から出力する。**
- **UseCases と BusinessLogics** は出島と外界の事を一切意識せず、**ビジネスロジックの実現だけに注力する。**


このような方法を取ることで、
**ビジネスロジックは ExternalInterfaces どころか、外界の存在や実装すら一切知らないクリーンな状態** で、
**自分の興味のある言葉や概念だけで表現した世界を作ることが出来ます。**
そしてそれこそが DDD で言うところの**「コアドメインの問題空間」や「ユビキタス言語」** なのです。
　
　
これで、例えば **『ユーザーを新規追加したい』** というビジネス上の希望を RDB でかなえるとき、
ビジネスロジックが **「ユーザーをデータベースに Insert する」** と考える必要はなくなりました。

そう、**ビジネスロジックにとっては、DAO やトランザクション、SQL、Insert などの考えそのものが異物** なのです。
**それは「ビジネスの本質」ではありません。**

これからは **「ユーザーを追加する」** とだけ考えればよくなります。

**ビジネスロジックに必要なデータの下準備や、個々のビジネスロジックを紡ぎ合わせることは UseCase が** やってくれます。
**外部に任せたい詳細な実装やSQLの定義、内外の変換は InterfaceAdapter が** やってくれます。
**ライブラリなどを使ったDB との通信やトランザクション制御などは ExternalInterface が** やってくれます。

ビジネスロジックが真の意味でビジネスの本質だけと向き合える、実に「クリーン」な考え方だと思います。

------------

## ★ 注意！！　InterfaceAdapter は ExternalInterface へ依存してはいけませんが、その関心ごとを知っていても OK です！

![一直線の場合_3ーEX.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/c5b2c820-c3d3-2495-5ab7-c3d7aa35ab9a.png)

#### ☆ ここを勘違いすると、**InterfaceAdapter から ExternalInterface に依存関係を向けたくなる罠** にはまります。

『依存関係が外から内のみである』 という言葉だけを見ると、『InterfaceAdapter が ExternalInterface の関心ごとを知っている』のは NG に感じます。
しかし InterfaceAdapter は、ユースケースの結果を **ExternalInterface にとって都合のいい構造に変換する役目** も持っているのですから、
当然 **ExternalInterface がどんな物か、何に興味があるのか** ある程度知っていなくてはいけません。

また **原著にも 『SQL は InterfaceAdapter 層に閉じ込めるよ』** って書いてあります。
> No code inward of this circle should know anything at all about the database. If the database is a SQL database, then all the SQL should be restricted to this layer, and in particular to the parts of this layer that have to do with the database.

SQL を InterfaceAdapter 層へ閉じ込める(配置する) という事は、
**InterfaceAdapter は「ExternalInterface が SQL を扱う」という都合を知っている** という事です。
「SQL を扱う」という都合に合わせて、ビジネスロジックから受け取ったデータ構造を SQL に変換してあげています。

#### **やはり『依存関係が外から内のみ』であっても、『InterfaceAdapter は ExternalInterface の関心ごとを知っていてもよい』** のです。

ただし **UseCase やビジネスロジックは、 InterfaceAdapter も ExternalInterface も知ってはいけません。** 
InterfaceAdapter と ExternalInterface の関係性だけが特別なのです。

だから、私の解釈はこれら2つを1つの「出島」として表現しています。



------------------------------


## □ 次にすべての出島を図に含める

先ほどの図は1つの出島だけを抜粋した図でした。
ここからは、色々な外界に対応した出島を図に含めます。

![本当の形_全体像_4_base.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/57ca14ec-da4c-c0dd-e374-571c6b8aaced.png)

これで**メインの図が完成しました。**
いよいよクリーンアーキテクチャっぽい図になりましたね。

元の多重円との違いは、**全体が完全なオニオン構造になっていないこと**です。
元の多重円の図を難しく感じさせる原因が『4重の円が全部が地続きである』という部分にあるのでは？ という仮説のもと、
この図では **ExternalInterface 層** を港、**Interface Adapters 層を『出島の一部と橋と門』として表現** してみました。

『4重の円が全部が地続きである』と内外を好きに出入りできてしまいそうですし、
どこを一番注視しなくてはいけないのかがはっきりしません。

この図のように描けば、何となく内側が守られている感が出るはずです。

------------

実際の処理では、**ある出島から入って、他の出島へ出ていく形** を繰り返すことになるでしょう。

例としてUI入力でDBから値を取得してUI出力する場合、例えば以下の図の黄色線のような処理の流れになります。

![本当の形_全体像_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/a39faf6c-2e62-75b6-0ec7-bb8591d54ae2.png)

なお『出島の切り出し方』は時と場合によって変わります。小さいものであれば、入出力は兼ねていてもいいでしょう。
DB や Cache などへの入出力に関しては CQRS を使う = 出島が分かれる、という事だってありますし、それを見据えてあらかじめ分けておいても構いません。

実際に原著に出てくる例では InputPort と OutputPort として、入出力の出島を分けて表現しています。

--------------

・・・で、
依存関係を一方向にするのはわかりました。
DI するのもきっとそうなんでしょう。

では **「何かを画面で入力して、それがどうやって出力される」** のかイメージできますか？
恐らくまだ難しい筈です。

その答えが、元の多重円の右下にある小さな矢印の図にあります。
次の章ではこの図をかみ砕いて、実際にどのように処理が行われるのか、流れを考えてみます。

---------

# ■ 依存関係を1方向にしたまま処理を行うには？ その流れとは？

#### とうとう右下にある小さな図を考えるときが来ました。
![FloｗOfControl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/2918a4cb-10a9-6dbe-d6f7-8ea8c1e5bc4f.png)

おそらく、クリーンアーキテクチャの図の中で最も難しいところです。
何回見ても難しいです。正直見るたびに混乱して分からなくなります。

　
この図を考えるにあたって最も重要なのは、

#### 『依存関係は外から内への1方向である』

ということです。

　
例えば UI入力の出島から、国内のビジネスロジックまで入ってきた後、
そのビジネスロジックが外部にある情報を必要としたとき、**どうにかして別の出島まで出ていかなくてはいけません。**
**内から外が見えないのに。**

**それを何とかするための工夫が詰め込まれたのが、この小さな図** なんです。


--------

## □ 発想を逆転させる

例として、『ユーザーの情報が欲しい』 という状況を考えます。

今までの **N層アーキテクチャ** では、**「DB のユーザーテーブルからクエリでユーザーの情報を取得する」** と考えました。
実際に、Infrastracture 層がビジネスロジックよりも下位の層に居るので、迷わず情報を取得することも出来ました。

しかし CleanArchitecture では、**ビジネスロジックは ExternalInterface 層を知ることが出来ません。**
というか **そもそも外の世界に興味がありません。**

ビジネスロジックにあるのは、**『この1業務をこなすにはユーザーの情報が必要である』という前提条件だけ** です。

したがって、そもそもの考え方を **「逆転」** してあげる必要があります。

> 異議あり！

----------

## □ 外が見えないなら「外から来てもらえば良い」

ビジネスロジックは目の前の業務にしか興味がないのですから、
**「その業務の前提条件をかなえてくれる誰かを、外から使者として連れて来てもらえばよい」** という風に考え方を逆転させます。

ビジネスロジックは **要望さえかなえてくれるのであれば、どこの誰が作業をしてくれても構いません。**
これを実現する仕組みが**『依存性の注入(DI)』** と、そのベースとなる考え方である **『依存関係逆転の原則(DIP)』** や **『制御の反転(IoC)』** です。

これがあの良く分からない図や線の正体です。
もう少し詳しく見ていきましょう。

--------


## 【ちょっと脱線】外から来てもらう為の手段: DI(Dependency Injection) って？

※ この章は DI についての概略なのでご存じの方は飛ばして頂いて構いません。
　
### **DI のイメージはいわゆる「派遣会社」ってやつ** です。

![haken.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/e2d101f4-206d-1f53-d558-315f4456d4b4.png)

　
出島っぽい例で考えてみましょう。
**ビジネスロジック**が、**『誰か知らんけど胡椒を取ってきてほしいわぁ』** と考えていたとします。当時は貴重品ですからね。

でも**クリーンアーキテクチャには「内から外を見ることが出来ない制約」**がある以上、好きな出島に行って胡椒を買い付けることはできません。
その代わりとして、**ユースケース** が **派遣会社(DI)に「胡椒を取ってきてくれる人」の派遣をお願いする** のです。

**派遣されてきた「胡椒を取ってきてくれる人」にお願いする** と、その人が **何らかの独自ルートで入手した胡椒** を手にすることが出来ます。
ビジネスロジックは胡椒が欲しいだけですから、どんな方法や経路で入手されたものでも構いません。
船で輸入してきてもいいですし、あらかじめ倉庫にあったものを持ってきてもいいのです。

どこからどうやって取ってきた胡椒なのかはは分かりませんが、
ユースケースから胡椒を渡してもらうことで、ビジネスロジックは **目的であった胡椒を手に入れることが出来ました。**

こんなイメージで、**外の世界を知らないまま、処理だけは外の世界にお願いできる** のが DI のミソです。

-------

具体的には、上記の話にでてくるものを、

  - **『誰か知らんけど胡椒を取ってきてほしいわぁ』** という要望 = **ユースケースの Interface**
  - **その想いを実現できる人材(実装)**  ＝ **出島(InterfaceAdapter) における Interface の実装**

として実現します。

　
例えば「ユーザーの情報が欲しい」という要望を叶える際に、
**派遣会社(DI) に登録しておく実装を変えるだけで、DB や Web など取りに行く先を変更することが出来ます。**
ユニットテストの時だけデバッグ用の固定値だけを返す人を用意することも出来ます。
そう、ビジネスロジックから Infrastracture の知識を追い出したことでテストもしやすくなるのです。

この仕組みにより、**「依存関係は外から内」のまま、「処理は内から外」にいける** ようになりました。
**「処理の流れ」と「依存関係の方向」を逆転** させています。だから **制御の反転(IoC)** なんですね。

**「処理が内から外」に行けるようになるのですから、UI や チャットツールへ情報を出力することだってできます。**

これで右下のちっこい図を読み解く準備が整いました。

　
(脱線終わり。)

--------

## □ まずはピンクの線を倒す

再掲します。
![FloｗOfControl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/2918a4cb-10a9-6dbe-d6f7-8ea8c1e5bc4f.png)

この図でまず着目したいのは、**"Floｗ Of Control" と書かれたピンクの線** です。
(※ **右側上下2つの Interface は初期の理解を妨げる罠** ですので注意してください。)

　
図から余計な部分を消してみます。

ピンクの線がつながる Controller は入口、Presenter は出口です。
名前からして、UI 入力とUI 出力でしょうか。
また UseCase Interactor は今はユースケースとして捉えましょう。


![右下の図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/9f7425c0-af27-8a1c-7894-ed01bc86749f.png)

**「UIからの入力があったら、ユースケースで何かの処理をして、その結果をUIへ出力する。」**
そう、ピンクの線だけ見ると実はフツーにいつも通りの図なんですよ。

でも思い出してください。
**CleanArchitecture では依存関係は外から内の一方通行** でした。
この図はこうなります。

![右下の図(問題).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/1e70a23e-2ce1-24bc-4916-8ef750e0ac5c.png)

**ユースケース(UseCases) から UI出力(ExternalInterfaces) へつながる矢印** は、**内から外を向いているので通れない** のです。
さあ困ったぞ....


-------------

## □ Interface と DI で壁を突破する。

**依存関係が外から内への一方通行**なのに、どうにかして**処理は内から外** へ出ていって画面へ出力しなくてはいけません。
そこで DI を活用します。

**ユースケースは `I処理結果` のような「やりたいこと」だけを定義** しておき、**その実装は UI 出力の出島で行います。**
**この実装をDI を利用して注入** することで、**依存は外から内のまま、結果を内から外へ伝えています。**

![右下の図(DI).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/8b05a959-17fd-5cae-2774-2490142a081e.png)


UI 出力は `I処理結果` を通じて処理結果を受け取って、それを画面に反映します。


-------------

## □ じゃあ右下の `UseCase Input Port` はなんなの？

### 最大の罠です。

![FloｗOfControl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/2918a4cb-10a9-6dbe-d6f7-8ea8c1e5bc4f.png)


この図では、**層の外から内に入っていく際にも、DI などを使って抽象化している** だけです。(今までは内から外はDIしようね、でした。)

日本語にしましょう。
こんな感じです。

![右下の図(DIx2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/55990bef-9e81-0797-b738-a2def9915896.png)


UI入力は Interface である `IUseCaseへの入力` を使う(呼び出す) のですが、その中身は Interface を実装した `ユースケース` クラス です。
それが DI によって UI入力 に注入されている、という図になります。

　
でもこの `UI入力` からの線って、依存関係の方向性は外から内なんですよ。
なのでその気になれば `IUseCaseへの入力` を使わずに、直接 `ユースケース` を呼んで処理をさせることも出来ます。
なのにそうしていない。

実際に原著を読んでも、外から内への処理を抽象化する理由はほとんど描かれていません。
さらっと『外から内でも DIP 適用しようね。』くらいのノリで書かれています。
内から外は NG だから DIP 適用しろよって記述は沢山あるんですけどね。

おそらく**内から外** だけではなく、**外から内** のやりとりも抽象化する。
すなわち**「全ての階層間のやりとりを相互方向に抽象化する」** ことで **究極にクリーンになるよ**、って事でなんでしょう。
だから相互作用といった意味を持つ単語 "Interact" を使って、`UseCase Interactor` という名前になっているのではないかと思います。

　
外から内も、内から外も、どっちも抽象化された Interface を参照していますから、お互いの変更に影響されにくいです。
確かに非常に「クリーン」な考え方だと思います。

------------
　
## □ ただし【個人的な意見】としては...

ここまでは、CleanArchitecture の基本に則った説明をしてきました。

しかし実は私は、先の例のように **「内から外」** だけではなく、**「外から内の参照まで抽象化」** してしまうと、**実装が重くなりやすい** と考えています。
したがって、**外(UIやWebAPIなどのInterfaceAdapter) が内の UseCase を呼ぶくらいはええんちゃう？** というのが私の落としどころです(※ビジネスロジックは呼んじゃダメです)。

結局、「内から外には DI を使う」という位が、**私の関わっているシステムの規模では丁度いい** んじゃないか、と。
![右下の図(DI).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/8b05a959-17fd-5cae-2774-2490142a081e.png)

　
同様に、**出島の中で DIP を『常に』適用するのも少しやりすぎ** かなと思っています。
C# であれば、DB などよほど重い部分以外は **InterfaceAdapter に相当するプロジェクトを作って、
そこに Interface やデータ型を配置** し **ExternalInterface でデータ変換までしてしまうこともあります。**
それを**『Stairway パターン』を適用** して、**ExternalInterface とビジネスロジックの双方から呼んでしまう形にしていました。**

それなりにクリーンに保ちながらも外部に頼りたいところとそうでない所の区別が付くので、割といい感じです。
**プロジェクト参照で層間の関係性や、参照関係をコントロールできるのが C# の良いところだと思います。相互参照はできませんし。**

　
また **層間のやりとり**で言えば、**外から中の欲するデータ型に値を詰めて送り込む** ようにしています。
層間のやりとりは全部 primitive でやれといった考え方もあるようですが、少し試しにやってみて非現実的だと悟ったためです。
BusinessLogics で interface を定義して DI して InterfaceAdapter を呼び出すこともあります(1層飛ばす)。

　
・・・と、このような感じで、私はクリーンアーキテクチャの考えを採用しつつも、
自分の **プロダクトの規模に合うようにダウンサイジング** して使っています。

あくまでも企業内向けの総利用者200人程度の小さなシステムの場合です。
プロダクトが大規模なものである場合など、ケースによっても考え方は変わってくるでしょう。

　
繰り返します。**クリーンアーキテクチャはあくまでも考え方の指針** です。
自分たちのプロダクトやチームに合ったようにカスタマイズしても構わないのです。
むしろ、試しながら **「カスタマイズすべき」** と考えます。

以上、**個人的な意見** でした。

----

# ■ まとめ

- クリーンアーキテクチャは、**鎖国して、出島でのみ外界と貿易することで、国内をきれいに保つための『方法論』**。
- **貿易を出島でのみに制限する** ことで、列強諸国から **国宝のビジネスロジックを守る**。
- **依存関係を外から内に絞る** ことで抽象化し、外部の影響を内部が受けないようにする。
- カスタマイズしてもいいししなくてもいい。

　
図を再掲します。

![本当の形_全体像_4_base.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530799/3b009ee6-ff2c-a6c7-c9a5-78537154004a.png)

-----

CleanArchitecture を適用すると、**副次的な効果として「外界とのつながりが疎結合」**になります。
当然、RDB から NoSQL に乗せ換えたりすることが容易になります。
ユニットテストのために、ダミーデータを返す実装にすることも容易になります。

**これらは確かにクリーンアーキテクチャの大きなメリットのひとつです。**

　
しかし **何よりも大切なのは、「自分たちの興味がある領域」以外をビジネスロジックが見なくて済む** ということです。

ここを勘違いしたまま、**ExternalInterface のすげ替えが簡単**　とだけ考えてしまうと、
クリーンアーキテクチャを採用するメリットがうっっっす～～～く感じてしまいますし、実際薄くなります。
というか、**それはクリーンアーキテクチャではなく DIP を採用したときのメリット** です。

クリーンアーキテクチャの目的は、**依存を極限まで取っ払って「ビジネスロジックをクリーンに保つ」** ことです。
ここを意識しておくと少し捗るかもしれません。

-----

一方、フレームワークを作るときやとんでもない量のアクセスを捌く必要があるときなどの場合は、
NoSQL や Redis などの **特定の技術やライブラリに「あえて強く依存すべき」時もある** でしょう。
あるいは高速化のために様々な手法や工夫を極限までこらすこともあると思います。

誤解を恐れず言うと、その場合は **そもそも Clean Architecture に適していない要件だ**、と言う可能性が高いです。
**『主眼がビジネスロジックにない』** からです。

クリーンアーキテクチャはビジネスロジックをとても大切にするので、速度は二の次(になりがち) です。
速度を求めるのであれば、Clean Architecture を採用しつつも、CQRS を利用するのも一つの手です。
C# はソリューション内にプロジェクトを複数作れますから、プロジェクトを分割して局所的にライブラリに依存しまくる構造にしても良いでしょう。
**もちろん、CleanArchitecture の採用をあきらめても構いません。**

**CleanArchitecture は決して万能ではありませんし、これだけ使っておけばいいって訳でもありません。**
全面適用すると重くなりがちですし、取っつきにくいのもまた事実です。
しかし**「ビジネスロジックをクリーンに保てる」という性質は、時には金よりも重い価値を持ちます。**

要件や期日、メンバーやスキルのバランス、様々なものを勘案してバランスをとりながら、
**あなたのチームにおける「クリーン度合い」を決めていく** 必要があります。

　

　
# ■ ・・・で、それってN層アーキテクチャだと出来ないの？

### **できます。**

(こんなに長文書いたのに..)

　
例えば、**Infrastructure 層が一番上にある N層アーキテクチャ** が存在します。

このアーキテクチャについては松岡さんの記事が非常～～～～にわかりやすいので、そちらを参照ください。
https://little-hands.hatenablog.com/entry/2018/12/10/ddd-architecture


----------

# ■ なら結局どのアーキテクチャがいいの？

個人的には、

- Clean Architecture
- オニオンアーキテクチャ
- Infrastructure 層が一番上にある N層アーキテクチャ

どれかを選んでおくのが現時点ではベターかな、と思います。


なぜ結局どれもおすすめなのかというと、
図の見せ方は違っても本質的な **「いかにしてビジネスロックを守るか」** という基本的な考え方は全て同じだからです。

違うのは切り分け方(名前の付け方)や、階層の考え方・実装の方向性(どこまで守るか)です。
個人的には、Clean Architecture を採用して、しっかり守るべきビジネスロジックが中心にあることを可視化するのが好きです。
しかし守れば守るほど実装が重くなるのも事実なので、実現すべき要件とQCD、人員などのバランスを見てあげる必要があります。

------

それぞれのアーキテクチャのメリットデメリットは以下の通りです。

- Clean Architecture と オニオンアーキテクチャ
  - **ドメインを世界の中心とする** と言うことを表現しやすい = クリーンに保ちやすい
  - **「外界は全て敵」** という考え方を魅せやすい
  - オニオン構造になっているので、必ず外から内、内から外　という考え方をせざるを得ない
  - 完全に準拠すると割と重くなりやすい

- Infrastructure 層が一番上にある N層アーキテクチャ
  - 今までのN層アーキテクチャの考え方をベースに出来る(**理解が容易**)
  - オニオン系アーキテクチャと比較して軽い

　
バランスを見極めながら、「あなただけのクリーンなアーキテクチャ」 を検討してみてはいかがでしょうか。

------------------
　
このような長文を最後まで読んでいただきありがとうございました。

本記事が何かの助けや切っ掛けになれば幸いです。