Clean Architecture と React を組み合わせる

Clean Architecture と React を組み合わせるデモアプリが eduardomoroni/react-clean-architecture というリポジトリにあったので、コードを覗いたら勉強になった。

Clean Architecture を大づかみに理解する

よく出てくる図。

f:id:fuji_haruka:20190114195209j:plain

私の理解している限りでは、 Clean Architecture において重要なのはモジュールの依存関係に規律を導入することで、中でも「重要なビジネスルール」を中心に依存関係を整理することであると思っている。

SOLID原則とか小難しい用語がたくさん出てくるけど、要するにそれはモジュールをどう分割するか、モジュール同士をどう結合するかに関する原則で、Clean Architecture を実践的に導入しようとしたら必要になってくるものだろう。

でも上の図を理解するだけだったら、もっとシンプルに説明できる。

モジュールの依存関係は「変わりやすいもの」が「変わりにくいもの」に依存するようにせよ

だいたいこれだけ押さえておけば、上の図を読み解ける。

円は依存の方向を表現している。円の外側が内側に向かって依存するようになっている。円の中心に Entity と Use Cases が中心にあって、これらがアプリケーションにおいて最も変わりにくいもの、「重要なビジネスルール」である。そして、円の外側に目を向けると、Framework、Web、UI、DB、Devicesなどがある。これらは変わりやすいもの、「詳細」である。

これはちょっと考えると我々が普通に Web アプリケーションを作るのと違った考え方だとわかる。普通は何か Web アプリケーションを作るときにはフレームワークをがっつり依存する。ところが、Clean Architecture は「重要なビジネスルールはフレームワークに依存しないように設計せよ」と言う。

react-clean-architecture の依存関係

具体的に見ていく。モジュールの依存関係とはつまり、モジュールをファイルで分割したときの export / import の関係のことだ。

eduardomoroni/react-clean-architecture の counter アプリを見よう。

これはシンプルな counter アプリで、ボタンを押すと counter の値が増えたり減ったりするだけだ。

注目したいのは中身の具体的なコードではなく、モジュールの依存関係だ。

counter ディレクトリには core/web/native/ がある。ビジネスルールが core/ に固められていて、React で実装された web/ と React Native で実装された native/ がそれに依存している。

f:id:fuji_haruka:20190114195527p:plain f:id:fuji_haruka:20190114195538p:plain

そして、core/ の中の依存関係はこうなっている。

f:id:fuji_haruka:20190114195321p:plain

entities/ が依存関係の中心にある。これは他のいかなるモジュールにも依存しない。外部ライブラリも import しない。

entities/ に依存するのが useCases/ である。これは entities/ にだけ依存している。これまた外部ライブラリを import しない。

Redux フレームワークを使うのは frameworks/ であり、これは adapters/ を介して entities/useCases/ に依存している。

このようにして、core/ パッケージはビジネスルールが依存関係の中心にあって、フレームワーク(詳細)が外側に来るように設計されている。Clean Architecture の図のとおりになっている。

ビジネスルールをフレームワークから切り離すメリット

特にフロントエンド開発をしていると日常茶飯事なのが、フレームワークをアップデートしたらアプリケーションが動かなくなるという現象だ。React や Redux は開発サイクルが速いので、たびたび破壊的変更があったりする。

Clean Architecture を杓子定規に採用しなかったとしても、「変わりやすいものが変わりにくいものに依存する」という原則に則って、ビジネスルールをフレームワークから切り離すことにはメリットがあると思う。

ビジネスルールは変わりにくいが、フレームワークは変わりやすい。ビジネスルールがフレームワークに依存していると、フレームワークが更新されるたびにビジネスルールを担当するモジュールにまで影響が及ぶ。

フレームワークを依存関係の外側に押しやっておくことで、フレームワークの更新による影響範囲を限定できる。そういうメリットがある。

そういう意味ではフロントエンド開発にも Clean Architecture を(エッセンスだけでも)導入すれば、メンテコストが下がるかもしれない。