No OOP/DDD in Frontend
フロントエンドでのOOP方式DDDを採用しない理由
OOP(オブジェクト志向)とReactは相性が悪く、OOPでのDDDはReactに導入する場合は発生するコストやリスクを踏まえて導入を決めます。
ReactはRe-renderingの仕組みとして、オブジェクトの場合、参照等価です。
React compares old and new props by shallow equality. If you create a new object or array each time the parent is re-rendered, even if the individual elements are each the same, React will still consider it to be changed.
つまり、親が再レンダリングされるたびに新しいオブジェクト・配列を生成すると、中身が同じでもReactは変更とみなします。
一般的なSaaSの場合、フロントにおけるユーザーは大抵一人のケースが多く、StoreでUserを管理すると、OOP wayではシングルトンでの実装とすることが多いと思っているのですが、そうなると、深いネストを持った同一インスタンスがStoreに保存される形となり、Renderingの条件と噛み合いにくくなる副作用があります。
その解決策としては、 Immer を使って immutable として取り扱うことです。Zustandでは Immer middleware が提供されており、相性がよいです。
個人的には言語仕様として相性が悪いものは採用しないほうがシンプルであると考えていますが、その前提でOOP/DDDを採用するなら良いと思います。
逆に、関数型としてのDDDや Immutable な取り回しを前提としたものも良いと考えています。が、DDDにおけるビジネスロジックはバックエンドに集約させる方が良いと考えており、Frontend(React)もプレゼンテーション層の一部のViewであると捉えるのが今の支持です。
昨今はAPI RequestのCache戦略として TanStack Query や SWR などでGraphQLのように、バックエンドのデータストアをクライアントのStoreとして扱えるようなキャッシュ機構が増えています。
極力ViewとしてのReactアプリケーションと割り切ると、クライアントアプリケーション内でRoot的なStore管理をする必要が減り、Request CacheとLocal Stateの最小2つで管理することができうると考えています。
参考
- Shallow Compare - React Legacy
- props がオブジェクト・配列・関数の場合にコンポーネントが再レンダーされる - React Docs
- DDD and react - r/reactjs