Clean Architectureを使ってみてのまとめ
例の図
ここの図について。
初めはこの図のレイヤー構成で作るものこそクリーンアーキテクチャだと思っていたけど、この図はあくまでも補助輪みたいなものだと今では思う。
確かに最初からこのレイヤーに従えばいいやとあまり考えずに乗っかれるのは楽だが、それぞれのレイヤーの役割や単語みたいなのが曖昧な部分もあり、最終的にこいつはどの層に入れるべきなんだろう...と迷うことがあった。
前提としてDDDの知識がないと辛いのでは、とも思った。(なおDDDはほとんど学習できていない)
なお、この図にとらわれる必要がないというのは本にも書かれていて、「円は概要を示したものである。(中略)この4つ以外は認めないというルールはない。」と明言されている。
クリーンアーキテクチャの教義
例の図=クリーンアーキテクチャではないとすれば、クリーンアーキテクチャとはなんなのか。
本には色々なアーキテクチャをまとめたアイデアと書いてあり、そのまとめたアーキテクチャ群の特徴は以下であると書かれている。
- フレームワーク非依存
- テスト可能
- UI非依存
- データベース非依存
ここでいう非依存というのは、気軽に変更可能と言い換えても良いと思う。
で、そういった非依存を実現するためのルールとして、
ソースコードの依存性は、内側(上位レベルの方針)にだけ向かっていなければいけない
と書かれている。
このルールを実現するために使うのがDI(Dependency Injection)によるDIP(Dependency Inversion Principle)の実現。
ということで、クリーンアーキテクチャは以下のような教義と理解すれば良いかなというのが現在の思い。
- フレームワークやUIやデータベースのような詳細に依存するな
- 詳細に依存しないために依存性は上位レベルにだけ向けろ
- 下位に依存する必要がある場合は、DIPを使って依存関係を逆転させろ(抽象に依存しろ)
Humble Objectパターン
テストしにくい振る舞いとテストしやすい振る舞いを分離するために生み出されたデザインパターン。
テストが難しい振る舞いを持つモジュール=Humble Objectとして分離する。
テストが難しい振る舞いを持つモジュールは、詳細を知っているモジュール。
これを分離することで、テスト容易性が高まる。
なぜなら簡単にMockに差し替えることが出来るから。
例えば、paramikoを処理の流れの中で直接呼び出さずに、Interfaceを介して間接的に呼び出すようにすれば、テスト時はparamikoの返り値を模した適当なメソッドを利用すればいい。
実機に依存する系の処理(DB,API,sshなど)は全てHumble Objectとするのが良いと思う。
Clean Architectureのメリット
実際に使ってみて感じてみたメリットは以下の通り。
詳細への非依存というメリットについては、今まで詳細が変わったこと(DBがMySQLからmongoDBに変わるとか)がないので良くわからない。
疎結合になる
- レイヤーを意識した実装になるので、いやでも疎結合になる
分業しやすい
- 疎結合になった結果、一つ一つのクラスの責務が小さくなる
- 結果、チームでの分業がしやすくなる
メンテナビリティの向上
- 疎結合及びレイヤーによる役割の明確化の結果、影響範囲が狭く修正しやすい
- バグ対応もかなり迅速に行える
テスタビリティの向上
- DIPに基づく実装によってHumble ObjectのMock化が容易
- DIPに基づく実装によって分業した場合でも他の完成を待つことなくテスト可能(In/Outは決めないとだが)
Clean Architecutureのデメリット
実際に使ってみて感じたデメリットは以下の通り。
レイヤーの定義
- 例の丸い図に従うにしても、レイヤーの名前をどうするんだというので悩む
- そしてオレオレレイヤーが誕生し、認識齟齬が生じる
理解に時間がかかる
- DI多用するので、初見で意味が分からない(まぁこれはClean Architectureの問題ではないか...?)
- いまだに「Gateway層がAPIの知識を持つことは詳細への依存なのでは?」みたいに、ルール認識がモヤッとしているところがある
- 多分DDDが前提知識としてあった方が良さそうだけど、鈍器読む余裕がない...(翻訳された洋書ってなんであんなに難しいんだろう)
ファイル増える
- レイヤー分割によりファイルが増えるので、何も知らない人が見るとウゲーってなる
- Goでやると同じディレクトリにtestがあるので、2倍ウゲーになる