Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Domain Driven reDux - or Redux as CQRS

2f374df92882247e5985413dad8b39b9?s=47 fsubal
December 08, 2018

Domain Driven reDux - or Redux as CQRS

ピクシブ社内エンジニア勉強会(2018-12-07)の資料です

2f374df92882247e5985413dad8b39b9?s=128

fsubal

December 08, 2018
Tweet

Transcript

  1. Domain Driven reDux あるいは Redux as CQRS pixiv Inc. f_subal

    2018/12/07
  2. 2 誰 • pixivFACTORY フロントエンド • 巨大Reactコンポーネント建造業 • グッズ制作画面とか作ってます @f_subal

  3. 3

  4. 4 グッズの種類 グッズの仕様 テンプレート 材質 ページ レイヤー グッズの バリエーション アイテム

  5. ドメインロジックが厚い フロントエンドを作っていく話 5

  6. • Redux は ただのクライアントサイド CQRS だよ • C と Q

    をドメインごとに切ると捗るよ ◦ けど純粋な ducks パターンはきついよ • ドメインモデルはプレーンな json と純粋関数で持つと良いよ • ある程度 Redux 習熟してる人向けです 6 話すこと
  7. 7

  8. • みんな大好き状態管理層(強いグローバル変数) • 単方向データフローと相性がいい • フロントエンドでCQRSするやつ ◦ そのための pub /

    sub と middleware の仕組みを提供するライブラリ ◦ https://speakerdeck.com/yamatatsu/reduxdebizinesurozitukuwogorigorishu-ku ?slide=12 8 Redux ってなんだっけ
  9. 9 http://krasimirtsonev.com/blog/articl e/my-take-on-redux-architecture

  10. 10 ThunkAction ( ≒ C 更新系) Selector ( ≒ Q

    参照系) Action (ドメインイベント) http://krasimirtsonev.com/blog/articl e/my-take-on-redux-architecture
  11. • CQRS とは ◦ Command(更新系)と Query(参照系)で実装を分離しようぜっていう考え ◦ 同じエンティティでも更新系と参照系では関心が異なるという前提に基づく • flux

    は「データが単方向に流れる」という点から説明されることが多いが ◦ 実は Store の更新と参照を別のフローに分離したという点が結構重要 11 Redux as CQRS
  12. Action 12

  13. • flux における Action には2つの意味がある ◦ Domain Event を発行する ActionCreator

    ◦ UseCase としての Action( ex: redux-thunk, redux-saga, redux-observable ) • アプリケーション内で「起こった出来事」を表す ◦ ので、過去形で命名するようにしている • UseCase としての Action は、複数の Domain Event を投げることがある 13 Action = 更新系
  14. • Action = アプリケーション内で「起こった出来事」 ◦ ので、過去形 or 完了形で命名するようにする ◦ 命令

    とか 処理を表す名前にすると、実装者が責務を誤解する • ◎ → USER_PROFILE_LOADED // よい • △ → FETCH_USER_COMPLETE // まだマシ • × → FETCH_USER_BY_ID // やめて 14 Action = 起こった出来事
  15. 15

  16. 16

  17. • 以下、暗に redux-thunk の使用を想定する • 「Ajax リクエストをして成功したら USER_LOADED を、失敗したら USER_LOADING_FAILED

    を dispatch したい」みたいな、複数の action を発行しうる一連 の手続き • CQRS の C( Command )の部分 • Action との統一の都合上こちらも過去形で命名している 17 ThunkAction = ユースケース
  18. 18

  19. • Redux 始めた人が最初に悩むやつ • Action と Reducer に何をどこまでやらせるか曖昧になりがち • ベストプラクティスとして

    reducer には複雑な処理を書かない、と言われるが ◦ 言われるだけでなんでダメなのか分かってない人もいると思う ◦ 各種ドキュメントはあんまりこの辺教えてくれない 19 Action と reducer の責務問題
  20. • case SET_NEW_ITEM: みたいな命名をしていると、あたかも reducer で副作用を起こし ていいかのような誤解が生じる ◦ SET_* 系の命名マジでやめたほうがいいと思う

    • case NEW_ITEM_LOADED: と命名すれば、ロード自体はもう終わっていて、良いから後 は store に反映して、という理解になりやすい(たぶん) • 「アプリケーションで起こった出来事に反応して自身を更新」という構造にする 20 Action と reducer の混同は命名で矯正できる よ(過激派)
  21. 21

  22. • 特定のドメインで起こりうる出来事の一覧を enum + ActionCreator として定義 ◦ 過去形で表現されるドメインイベントの一覧 • 複数の

    Action を発行することのできるユースケースを Thunk Action として定義 ◦ 統一のため thunk も過去形で命名している ◦ ex) userProfileRequested() という thunk を投げると、USER_PROFILE_LOADED が dispatch される • reducer は Action の発生を見守る(何か起きたら自身を更新する) 22 factory における Action + Reducer
  23. 参照系 23

  24. • 前提として Redux の Store はでかい • アプリケーションドメインが全部入った 1枚のJSON 24

    Selector = 参照系
  25. 25 グッズの種類 グッズの仕様 テンプレート 材質 ページ レイヤー グッズの バリエーション アイテム

  26. • コンポーネントがこのでっかい JSON から値を引く際、Store の内部構造を知らなくても すっと引ける仕組みが欲しい • これが selector(実装には自動メモ化機能などがついた reselect

    が使われる) • CQRS の Q の部分(参照系のビジネスロジック) 26 Selector = 参照系
  27. 27

  28. ドメインごとに切る 28

  29. • action, reducer, selector をどういう構成で置くかはプロジェクトごとに結構違う • 一番良く見るのは次の形式 /actions user.ts /reducers

    user.ts /selectors 29 redux のディレクトリ構成
  30. • ファイル移動が多くなりがち • 「俺は user が規約に同意したことを true にしたいだけなのに、なんでディレクトリ 4つもま たいでるの、アホなの」問題

    • 対抗策としていわゆる ducks パターンという設計が出てきた 30 /actions 形式の問題
  31. • 同じドメインの action, reducer, selector を1ファイルにまとめる設計 • 各 ducks は完全に中に閉じる(基本相互に関係しあわない)

    /modules /user duck.ts /item duck.ts 31 ducks パターン
  32. 32 https://webbibouroku.com/Blog/Article/redux-ducks

  33. • ducks パターンだと流石に閉じすぎててつらいということから出てきた(多分) • ドメインごとに切る点は踏襲してるが、ファイルは別々 /domains /user action.ts reducer.ts selector.ts

    33 re-ducks パターン
  34. • だいたい re-ducks パターンの変形 • 各ドメインは相互に干渉し会える ◦ 「Product の thunk

    が Specification の actionを発行」とかを許容している ◦ 純粋な ducks パターンで 1 ファイルにまとめる と ↑ がやりずらくなるのでやめた 34 factory のファイル構成
  35. • 実はリニューアル前の旧エディタは /actions のようにディレクトリを切っていた • 結局の所 Store 内の 1個の値を更新するのにファイル移動が異常に多くて萎えた •

    新しい設計でもファイル移動は発生するが、同じドメインなら同じフォルダなので面倒さは 少ない • ドメインごとにフォルダを切ったことでコンテキストが境界づけられたのも良かった • 結論おすすめです 35 factory のファイル構成
  36. ところで 36

  37. • 型定義 + 関数 + 定数 の集まり • みんなよく types.ts

    とか userUtil.ts とか constants.ts とか作るけど、あれを1ファイルに纏 めたもの • action と selector、あるいはコンポーネントからも 呼べる共通関数とかおける • 別の機会にこれだけで話したい …かも 37 model.ts って何や
  38. 38

  39. まとめ 39

  40. • Redux は ただのクライアントサイド CQRS だよ • C と Q

    をドメインごとに切ると捗るよ(けど純粋な ducks パターンはきついよ ) • ドメインモデルを純粋な形で持つようにすると良いよ 40 まとめ
  41. Redux as CQRS あるいはドメイン駆動 Redux pixiv Inc. f_subal 2018/12/07