2017年5月17日水曜日

ASP.NET MVCでCQRSを利用してORMをうまく使う

以前(2013年頃)自分が設計した内容のメモです。
今はASP.NETの世界から離れて久しい。

はじめに

CQRS(コマンドクエリ責務分離)という考え方を使って、参照系と更新系でORMとSQLを使い分けていいとこ取りするという趣旨です。

サンプル

サンプルを作りました。
https://github.com/herara-ofnir3/cqrs-sample

CQRS(コマンドクエリ責務分離)とは

CQRSについて詳しくはぜひこちらをどうぞ。

[Greg Young流CQRS - Mark Nijhof]
http://d.hatena.ne.jp/digitalsoul/20100712/1278886009
※ 上記記事のサンプル
https://github.com/MarkNijhof/Fohjin

ORMを使いたい理由と使いたくない理由

更新処理がとても快適

煩雑なSQLの発行処理を書かずとも、エンティティの状態を変化させ、永続化してやればうまいこと更新してくれます。
特に one-to-many や many-to-many の関係をカスケードしてうまく処理してくれるのは、とても素晴らしいメカニズムです。

バッチ処理的な一括更新や大量データを高速に更新するのには向いていませんが、業務アプリケーションの通常の更新処理なら非常にマッチします。

参照系でしぬ

参照系の処理がやりにくいです。
普通なら簡単なSQLを投げてそのまま結果を表示するだけ、みたいな画面ですら、気にすることが多すぎます。

  • 遅延読み込みされるとまずい(N+1問題)から、これとこれをフェッチして...
  • 一回流してみて実際のSQLをチェックしないと...

みたいな調子です。
どうしてもデータの取得が冗長になりがちです。
特にHQLでSQLを再現していると泣けてきます。

よく言われるORMの問題点はこの参照系の問題に集中している気がします。
どう考えてもシンプルにSQL書いたほうがはやくて確実ですし。

ORMの弱点を補うためのCQRS

ORMの得意な更新系の処理だけORM使って、参照系はSQLを書けばいい、という考えに至りました。
そして、参照系と更新系の分割と一貫性のために、CQRSを適用しました。

CQRSはイベントソーシングとセットで語られることが多いのですが、イベントソーシングはスルーします。
データアクセスがクエリ(参照系)とコマンド(更新系)で違うだけの実装です。

その他利点

実際やってみると色々いいところがありました。

良い作りに縛れる
アプリケーションに必要な参照/更新操作がクエリ/コマンドという形でいい感じにコード上に浮き上がってきます。
いわいる「変な作り」というのがやりにくくなります。
テストがしやすい (疎結合になる)

コマンドの発行は全てコマンドバスに投げるだけになるので、
コントローラが依存するのはコマンドバスといくつかのクエリだけとなります。
そのため、アンチパターンとしてありがちなファットコントローラに陥りにくくなります。

依存関係が絞られますし、トランザクションなどの煩雑な処理が隠蔽されるため、テストが非常に簡潔になります。
自然に結合度が下がり、構造がシンプルになります。
おかげでメンバが積極的にテストを書いてくれました。

更新処理のログが簡単にとれる

全てのコマンド(更新操作)はコマンドバスを通して発行されるので、更新処理を簡単に確実にログできます。(コマンドバスにログ処理を挟むだけ)
このあたりの機構にイベントソーシングを組み合わせると強力ですが、ログをとれるだけでも大きな恩恵を得られました。

運用・保守をする上で、現状のデータに至るまでの経緯が全て記録されているというのは、極めて有効でした。

TFT 10.14 Peeba Comp

こちらのガイドの自分用まとめです。 https://www.reddit.com/r/CompetitiveTFT/comments/hraunp/tft_1014_break_the_meta_new_peeba_comp_set_35/ 難しいですが完成すると非常に強く、プレ...