Slide 1

Slide 1 text

clean architectureの実践 (in React with Redux)

Slide 2

Slide 2 text

自己紹介 張 たいよ (GitHub: @neutron63zf) 東京大学理学部物理学科 4年 ● ventus-inc ○ JavaScript ( Vue.js / Nuxt.js ) ○ Golang / Firebase ● (元)東京大学五月祭常任委員会 ○ AWS / Nginx / Docker ○ Node.js ( Express )

Slide 3

Slide 3 text

構成 ● 動機 ● 前提知識 ● clean architectureの概要 ● reactでやってみる ● まとめ

Slide 4

Slide 4 text

動機:「vue/reactに振り回されたくない」 ● フレームワークに振り回されている気がする ○ (例)処理を全部 storeの中に書いてしまい、読みづらいコードになってしまっている。 ○ (例)vueの限界で、配列をいじるときは直接代入ができない ● テストしたいけど、テストしづらいコードができてしまった ● ロジックの部分は大して変わってないのに変更が多くて大変 「vue/reactに振り回されて、肝心の『本質』以外で消耗している気がする」

Slide 5

Slide 5 text

前提知識 ● React ○ 状態を更新することによって、描画が(ほぼ)自動で更新される。 ○ コンポーネントを組み合わせることで、ウェブサイトを作れる。 ○ (性質だけなら) Vueも近い。 ● Flux Architecture(ここではredux) ○ (すごくざっくり言うと) Storeというものに状態をまとめ、それに対して操作をする。 ○ 「一方向のデータフロー」を課すことで、挙動を予測しやすくする。 ● TypeScript ○ JavaScriptに型アノテーションをつけることができる。 ○ 予測変換が強くなる。便利。 ○ 型にまつわるエラーをある程度コンパイル時に検知できる。

Slide 6

Slide 6 text

clean architecture の概要 (出典:https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)

Slide 7

Slide 7 text

全体像 普通は「DB」や「フレームワーク」が最下層に あって、それらの上にアプリケーションを構築 していくが、clean architectureは逆に、 DI(Dependency Injection; 依存オブジェクト の注入)により、「DB」や「フレームワーク」を最 外層に追いやり、どちらにも依存しないコード を書く 赤丸で囲ったところは普通は最下層にいるが、これ を外に出すことで、影響を減らす

Slide 8

Slide 8 text

内層:ビジネスロジック いわゆるロジックにあたる部分。 フレームワークに依存するコードなどは基本的 には書かず、データ構造だったり、「このアプリ ケーションでは何ができるのか 」を表現する。

Slide 9

Slide 9 text

外層:入出力 入力をデータベースに受け渡したり、逆に画面 に出力したり、 「純粋なロジック」と「外部のフレームワーク・ データベース」の間をとりもち、媒介する層

Slide 10

Slide 10 text

DIって? (非常にざっくり、語弊を恐れずに言うと、) 右下のように、実行時に依存しているオブジェ クトを指定すること。 たとえば、上のコードでは、クラス B以外のrun メソッドを呼び出すにはコードを書き換えるほ かないが、下のコードでは、コンストラクタで別 のrunメソッドを持つオブジェクトを指定してや れば良い。 これにより、より柔軟なコードが書けるようにな る。

Slide 11

Slide 11 text

reactでやってみる リポジトリをあげておきました

Slide 12

Slide 12 text

todoアプリからのスタート 「TypeScriptで Redux + React チュートリア ル」のページをもとに、「追加だけできる Todo アプリ(?)」をさくっと作る。 今回はこれにclean architectureを適用してみ る。

Slide 13

Slide 13 text

内層を書く 内層のEntitiesとUseCasesの「interface」だ け書いておく。実際に下の UseCaseを実装す るのはまた別のクラス。 この10行かそこらがこのアプリのできることを 要約している。 普通はstoreなどのデータ構造に忖度して、 id を入れたりするが、なくても良い。 また、getTodosが引数(しかもany)をとってし まったの理由は後で解説する。 (src/structure/entities/todo_interface.ts) (src/structure/usecases/todos_interface.ts)

Slide 14

Slide 14 text

storeを外層に書く src/structure/store/store_repository.tsにインターフェースを、src/store_repository_react.tsに具体的な実装 を書いている。 storeはモデルと同等の扱いを受けがちだが、コードを実際に書くと、 フレームワークの制約を非常に厳しく受け るため、内層ではなく外層に書いている。

Slide 15

Slide 15 text

useCaseとcontrollerの実装 まず、useCaseの方は、リポジトリにデータを引き渡し、さまざまな永続化などを行う 。今回は割愛したが、APIで バックエンドにデータを保存する場合などはここに書くことになる。 次に、controllerの方は、ユーザーの入力を整形し、 useCaseに整形された入力を引き渡す 。

Slide 16

Slide 16 text

(補足)factoryの追加 少し蛇足だが、作ったこれらのクラスを実際に 使うときは、まず、実際のstoreを引数にとっ て、インスタンスをどんどん作ることになる。 ただ、毎回何回もnewを書くのは面倒なので、 factory関数を作ってあげる。 具体的には、右上のコードだけでコントロー ラーが取得できるようにしておく 。 (src/TodoComponent.tsxのconstructor内) (src/todo_controller_factory.ts) (src/structure/todo_controller_factory.ts)

Slide 17

Slide 17 text

(補足)getTodosが引数を取る理由 getTodosが引数を取らないと、右の 「renderTodoList」が「this.propsに依存してい ない」とreactに判断されるのか、addTodoをし ても表示が更新されない。 たいへん気持ち悪いが、しかたなくこの実装に した。 (src/TodoComponent.tsx)

Slide 18

Slide 18 text

まとめ:処理の流れを追ってみる 実際にconsole.logして処理を追ってみると、 右にあるように、 「component→controller→ interactor(usecase)→repository」 となり、階層をまたいでデータが流れているこ とがわかる。

Slide 19

Slide 19 text

まとめ:良かった点 ● 責務が分割されている ○ つまり、「どこを変えればいいのか」がわかりやすく、また、煩雑にもなりづらい。 ● ストアが軽くなりそう ○ 今回は元からある storeを使ったが、storeの中身(reducerやactionsなど)もclean architectureのusecaseなどで 扱えそう ● テストがしやすい ○ インターフェースに依存しているだけなので、同じインターフェースさえ満たせば、テスト用のオブジェクトなどを 入れることで比較的簡単にテスト可能

Slide 20

Slide 20 text

まとめ:微妙だった点 ● めんどくさい ○ 見ての通り、todoアプリでは圧倒的にめんどくさい。 ○ 大規模になれば、あるいは、大規模になる見込みがあるコードベースでは役に立つ。 ● フレームワークの影響を完全に遮蔽することはない ○ getTodosみたいなのはそれの例。 ○ 行けなくはないのだろうが、さらに大変になりそう。

Slide 21

Slide 21 text

参考資料・出典 ● https://programmagick.com/blog?slug=react_typescript_redux_tutorial ○ 「TypeScriptで Redux + React チュートリアル」 ○ react + redux + typescript のサンプルとして ● https://nrslib.com/clean-architecture/ ● https://nrslib.com/clean-flow-of-control/ ○ 「実践クリーンアーキテクチャ」 ○ 「クリーンアーキテクチャの右下の図」 ○ 図の解説がより詳しく、加えてコード例も含めて載っている