Redux(react-redux)における適切な配列要素の更新
2021年8月23日…
久しぶりにReactを使用したいと思い、現代的な設計は何か調査し、色々と検討をしていたところふと思ってしまった疑問である。
私が最後にReactで開発をしていたのは、2017年末である。当時も、高度な状態管理の技術スタックの定番は、やはり現在と変わらずRedux + Sagaミドルウェアであった。
当時はSagaの適用箇所がさほどなかったこともあり、あまり気にかけていなかった。しかし、あらためてフラットな状態でこの技術スタックを見てみると、Reduxの「Sagaミドルウェア」に関し、なぜ流行っているのかよく理解できないと思ってしまったため、その疑問点をまとめてみた。
Sagaパターンについて調査すると、いわゆるマイクロサービス化されて、アプリケーションごと異なる場合で、アプリケーションにトランザクションをもたらす必要がある際に適用するデザインだと思っている。アプリケーションにトランザクションの実装ともなると、実装コストや難易度が非常に高いものとなるであろう。
調べていて、クライアントサイドに適用されている実例が見つけられなかったため、Reactの界隈が若干特殊な傾向なのでは?という印象を抱いてしまった。
端的にいうと、1つのアプリケーション内でSagaパターンを導入するには、多くの場合にファットすぎない?ということ。Sagaパターンの本来の想定されるであろう用途は疑問1の通りで、そもそもReact内の状態管理でいうと、アプリケーションをクライアントとみなすと、クライアントからストレージに接続しているのは唯一つであるわけで、クライアントが1つの場合になぜSagaパターンでなけばダメなのか、という点が理由として希薄に思える。
ReduxのSagaミドルウェアの主張として、存想像するに、UIからフックされるイベント(ReduxでいうAction)をクライアントと見立てており、またReduxのStoreをデータストアとして、ああデータストアに対して、非同期でたくさんイベントが飛んでくることが想定されますね、と雰囲気は分かるのだが…。
仮にそうだとしても、アプリケーション内における、非同期のデータフローの交通整理を行うデザインパターンで良いのでは?と思ってしまう。
トランザクションにおける問題解決は、データストアに対する変更が競合した場合のロールバック処理が特にウェイトが大きいと思われる。トランザクションのような精緻な整合性の担保が、多くの場合にクライアントサイド内で完結して実装されている必要があるかが疑問であった。
今回でいうと、1つのアプリケーション内部に限った話であり、だとしたら、アプリケーション側で対処するのではなくて、トランザクションはアクセス先のデータストア側の提供する機能でなんとかならないのか?という話でもある気がする。
Webの辞書によると、Sagaの意味は、「壮大な歴史物語や冒険物語、ファンタジーなど」ということだ。略称か何かで、意図せずこういう命名になったにせよ、これはデザインパターンの名前にしてはカッコ良すぎるため、疑問を覚える他ない。
Sagaパターンは、デザインパターンの要件レベルで私には重すぎた…。では、Reduxの高度な状態管理にSagaパターンではない何を使うか?であるが、Observerパターンが良いのではないかと思っている。
1つのアプリケーション内において、状態管理にObserverパターンを適用する、はよくある話なのでReduxの取り回し向上のため、拡張的に適用するにも何ら違和感がない(というか、ReduxがReactと結合して状態を購読するあたり、Redux自体もObserverパターンを踏襲しているので理解もしやすい)。Observerパターンの実装をサポートするライブラリでは、有名なものではReactiveX(通称: Rx)は多くの開発言語で提供されている。一方で、Observerパターンを補助なしで書こうとした場合に、その仕組みが簡素であるので、実装時の難易度がさほど高くはないという点もポイントだ(Observerパターン自体の要件が軽量であるのが良い)。
今回論点となったReduxのSagaミドルウェアはもしかしたら魅力的なのかもしれないが(テストがしやすいなどの理由があるのかもしれないが)、デザインパターンの本質のみを突き詰めた場合に、自分が想定する多くのクライアント実装には要件として大き過ぎて、合わなそうであった。よって、Reactでの高度な状態管理にはObserverパターンのRxを使用することにしようと思う。
2020年9月14日追記:
そもそも、非同期処理をアプリケーションの唯一のデータソースの操作に組み込まないというルールのもとやれば、最近はこういったより複雑な非同期処理のライブラリがある程度までは不要になるのではないのかと思っている(これに気づいて一生懸命どれが良いのか調べていたわけだが、ある時気づいた)。この手の非同期処理をデータフロー中でサポートするライブラリは、データソースの構造が複雑であったりとか、私が認識していないさまざまな事情がある場合にsagaであったりが出てくるという認識である。
Sagas
https://microservices.io/patterns/data/saga.html
sagaを使用したマイクロサービスのデータ一貫性https://www.infoq.com/jp/news/2018/03/data-consistency-microservices/
Read Me · Redux-Saga
https://redux-saga.js.org/
出版-購読型モデル – Wikipedia(Observerパターン)
https://ja.wikipedia.org/wiki/%E5%87%BA%E7%89%88-%E8%B3%BC%E8%AA%AD%E5%9E%8B%E3%83%A2%E3%83%87%E3%83%AB
プログラムを書きながらTranceを聴くのが良いですね。みなさんも聴いたほうがいいですよ、Trance。EDMよりハードトランスでしょ。
Discussion about this post