63
38

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ReduxAdvent Calendar 2017

Day 1

reduxのstateを正規化してCQRSの恩恵を受ける土台を作る

Last updated at Posted at 2017-11-30

2017reduxアドベントカレンダーの1日目が空いていたので、書いてみます。
よろしくおねがいしますー

書くこと

reduxのドキュメントのMotivationの頁にてCQRSに言及されています(微かに)
reduxのCQRSらしさを引き出してその恩恵を受ける方法を書いていきます。

CQRSってなんだ?

Command Query Responsibility Segregation
日本語だとコマンド、クエリ責任分離とかって訳されます。
コマンドは副作用が主目的の処理、クエリはデータを取ってくることが主目的の処理のことです。

マクロな話だと「データを書き換えとデータの取り出しは、サーバーもDBも分割してしまえ」という設計方式になります。
ミクロな話では「副作用を持つメソッドは戻り値を持つな、戻り値があるメソッドは副作用を持つな」という、コーディング原則(?)としても存在します。

ちなみに、fluxは(reduxも)生まれながらにCQRSです。
reduxは、CQRSとevent sourcingをリスペクトした関数型言語であるelmからインスパイア(というかパクった説も)されているので、この辺の勉強をすると設計がはかどります。

まずはstateをnormalize(正規化)する

reduxドキュメントには「stateは正規化しよう」と書いてあります。

jsonデータの正規化って?

「jsonデータの正規化とは?」という話はこのreduxドキュメントでも紹介されているnormalizrこちらのブログが大変参考になります。

非正規化されてるjsonデータ
{
  id: "123",
  author: {
    id: "1",
    name: "Paul"
  },
  title: "My awesome blog post",
  comments: [
    {
      id: "324",
      commenter: {
        id: "2",
        name: "Nicole"
      }
    }
  ]
}
正規化されてるjsonデータ
{
  "articles": { 
    "123": { 
      id: "123",
      author: "1",
      title: "My awesome blog post",
      comments: [ "324" ]
    }
  },
  "users": {
    "1": { "id": "1", "name": "Paul" },
    "2": { "id": "2", "name": "Nicole" }
  },
  "comments": {
    "324": { id: "324", "commenter": "2" }
  }
}

(どちらの例もnormalizrから拝借しています。)

normalizrとは?って話はすでに良き記事が出てるのでそっちとか本家のReadmeとかReduxのDocとか読んで頂ければと
Normalizrを使用したReduxの実装パターン

正規化されたデータはネスト構造が浅くなり、正規化以前にネストされてたデータへの参照(id)を持っています。
RDBの設計に似てると思います。

正規化されたデータの方が、書き換えが容易で、変更が多いデータに向いています。

CQRS的には

redux stateはCQRSで言うところのコマンドモデル(writeモデル)となります。
Screenshot from Gyazo
コマンドモデルを書き換えるとsubが反応してクエリモデルを書き換えます。

クエリモデルどこいった?

reselectにメモ化されたキャッシュ」がreduxにおけるクエリモデルに当たるかと思います。
reselectは本家でも紹介されていて、こちらのstackoverflowでもreduxのコミッターがおすすめしています。
日本語だとこの記事が詳しいです。

CQRS的には

実際のCQRSではコマンドモデルとクエリモデルを別々のストレージに記憶させますが、RDB一つを使って設計する方式もあります。その場合、テーブルviewをクエリモデルとします。
テーブルviewがキャッシュされるのと同じようにreselectもメモ化と言う形でキャッシュされるので、なんかそのへん意識して作られたんじゃないかなって思います。

クエリモデルは画面表示に特化させて、好き勝手やっていいです。jsonの形に特に縛りはないのでご自由に。

selector書くのめんどいよ

わかります。それでも書く価値がselectorにはあります。
それはstate、react間の腐敗防止層としての価値です。

selectorを書くことで、reactはstateの形を知る必要がなくなり、stateの形を知っているのは、reducerとselectorだけになります。これはアプリケーションが進化する過程でstateの形をリファクタリングしたくなったときに価値を出します。
またreact側の修正があった場合についても、stateの形を変更しなくても欲しい形のjsonを手に入れる事ができます。

以上の理由から、middlewareでstateを使う場合もちゃんとselectorを書いたほうが良いです。DDD話でいくと、selectorを用いてfactoryを作り、それを使って集約を構築する感じになります。
この辺はまた今度記事にできたら良いなって思います。

CQRSをもっと知りたい方はこちら

Greg Young流CQRS
CQRS Documents by Greg Young

実践ドメイン駆動設計にはCQRSやそれ以外のアーキテクチャについて、「ここにレイヤードアーキテクチャがあるじゃろ?」から始まり、なぜレイヤードアーキテクチャじゃないアーキテクチャが提唱されていったのかが説明されていて、ためになる本でした。

果たして幸せになったのか

stateを正規化しつつ、reactが非正規化データを受け取れるようになり、腐敗防止層も手に入れた。
しかし、もともとapiで受け取ったデータをそのままredux stateに突っ込んで、reactでもさほど困っておらず、かつAPIが大きく変更することもない、というプロジェクトでは「幸せになった気がせんな」という感じかもしれない。

reduxは、このCQRSとイベントソーシングによって、ユーザーイベント、外部API、redux storeの間に住まうドメイン世界をクリーンにかつ外界の依存関係を切り離して設計することができます。クリーンアーキテクチャ、イベント駆動アーキテクチャなどと相性が良く、ドメインにある程度の重さがあるとき、その複雑化を軽減させることができます。

あとがき

質問やご意見があれば頂けると喜びます。

ドメイン駆動設計、ドメインイベント、イベント駆動アーキテクチャ、イベントソーシングなどをreduxに当てはめる話も書けたら書こうかと思います。
reduxアドベントカレンダーがら空きだしね!

63
38
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
63
38

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?