状態管理ストアはユースケース

Katashin
·

Pinia などのフロントエンドの状態管理の文脈で言われるストアとはユースケースとかアプリケーション層なのではないか

  • 状態管理ストアはだいたいが Flux の影響を受けていそう

    • Flux では Action, Dispatcher と Store が別だが、最近の状態管理ストアの実装はこの辺が全部まとまってる

      • 最近は Action と Dispatcher の境目がない

        • ここが分かれているのは Action を serializable なデータにして、Dev tool とか logger で呼ばれた Action を追跡できるようにするためだったが、ツールの発達により必要なくなった

        • 今は Action というと実際に処理が書かれた関数を指す

  • Flux では Store にドメインロジックを書くとされているが、Flux に影響を受けたライブラリはみんな Store もライブラリの中に入れていて、ドメインロジックを書くのに適していない

    • ドメインロジックは依存されることはあっても依存するべきではないとされている

    • ライブラリを使ってドメインロジックを書いたら、そのドメインロジックはライブラリに依存している

    • だからこそこの辺をすべてカバーしようとするライブラリは少なくなってきて、もっと小さい機能だけを持つライブラリが増えてきたのかも

なにも考えずに書くとストアという名前からリポジトリっぽく書いてしまいがちだけど、そういうストアは後から結構つらくなる

  • 例えば、ショッピングカートを実装する時

    • 商品をカゴに入れるボタンを押した時

      • ストアの実装がリポジトリっぽく書かれていると

        • カゴに同一の商品がない時は addItem

        • 同一の商品がある場合は updateItemCount

        • みたいな条件分岐を書き分ける必要がある

      • ストアの実装がユースケースっぽく書かれていると

        • View からは addItem だけ呼び出す

        • ストア内で同一の商品がある場合とない場合の処理を分ければ良い

  • View 側ではなにも考えずにユースケースに沿ったストアの関数を呼べば良い

  • ストアが CRUD だと View 側でアプリケーションのロジックを書く必要が出てくる

    • これを防ぐためユースケース層を独自に書くと、ストアとの取り回しが悪くなる

      • ストアのインスタンスは View に DI されていることが多い

        • SSR の都合で、直接 import が推奨されない

        • 独自ユースケースからストアを呼ぶ時、そのストアは View から渡されるという歪なフローになりがち

          • ここを楽にするためにユースケースを composables (hooks) にしているケースも見たことあるが、View と混ざりがちなのでつらくなりそう

            • 人間には、同じ見た目のものに対して異なる概念を使い分けることが難しい

とはいえ普通のアプリとか Web ページだとフロントエンドのロジックは薄いことが多いので、ユースケースとリポジトリを合体させたようなストアでもなんとかなったりする

  • バックエンドにロジックを逃したり

  • インタラクションが厚いアプリだとストアじゃなくてもっと View に近い方にインタラクション関連のロジックが盛られていく

  • そもそもストアがいらない説もある

    • React の Context で十分みたいな論は結構聞いた

      • これは結局ストアに相当するなにかを自分で設計する必要はありそうだが

      • 設計の必要がないほど簡単なアプリならデータを Context で共有するだけでいいという話もありそう

    • 結局バックエンドのデータを選択して表示するだけだから Apollo Client だけでいい説とか

      • Apollo Client 自体がキャッシュとそのキャッシュを更新する仕組みを持つので、すごく単純なストアと見ることもできる