こまぶろ

技術のこととか仕事のこととか。

リレーショナルモデルにおける制約とCQRS・SQLQL

前回の記事で、リレーショナルデータベースの役割として、以下の3つを挙げ、ドメイン駆動設計においては最後のものにあまり重きが置かれていないことを指摘した。

  • 集合演算によるリレーションの導出(検索)
  • ディスクへの書き込みによる永続化(蓄積)
  • 各種制約によるデータの整合性の確保

ky-yk-d.hatenablog.com

本記事では、リレーショナルデータベースの特性を改めて検討し、その特性からの帰結としてCQRSとSQLQLを位置付けてみたい。

リレーショナルモデルにおける整合性の確保

整合性の確保をリレーショナルデータベースが担うという発想は、決して新奇なものではない。リレーショナルモデルの父であるコッドの1970年の論文「A Relational Model of Data for Large Data Banks」*1でも、データの整合性(consistency)というテーマが大きく取り上げられており、それを維持するための制約宣言文(constraint statement)を定義するというアイデアも提起されている。

現実のリレーショナルデータベースにおいても、制約は確かに存在している。一意性制約や参照整合性制約、チェック制約などがそれである。また、制約という呼び方は通常しないが、トリガもまた、データの整合性を守る仕組みとして利用できる。『リレーショナルデータベース入門』では、以下のように記載されている*2

これらの制約を表現するためのツールは、現実のリレーショナルデータベースにおいては限定的な実装を受けるに留まっている。それにはパフォーマンスの問題も関係しているだろう*3。運用上も、制約というデータベースの定義の変更は大規模なロックを伴うから*4、ビジネスルールをデータベースの制約の側に大きく寄せることはリスクが大きい。現実のアーキテクチャは、現実のリレーショナルデータベースに基づいて構築されなければならないし、構築されているだろう。次に、リレーショナルデータベースの特性に応じたアーキテクチャについて考えてみる。

リレーショナルデータベースの特性から考えるCQRS

制約は、更新時にどのようにデータの整合性を守るかを関心事としている。これは、実際のリレーショナルデータベースにおいては、参照整合性制約などの限られた形で実装されるに止まっている。その一方で、参照を行うための言語であるデータサブ言語、その実装としてのSQL(のSELECT文)はかなり発達している。

以上のような事情から、リレーショナルデータベースは、参照には柔軟に対応できる(対応しても危険が少ない)のに対し、更新には柔軟に対応できない(対応すると整合性が守れない)という特性を持っている。更新の操作を提供する場合には、リレーショナルデータベース側では担えない制約を一枚外側のレイヤ(具体的にはアプリケーションのコード)でかけておく必要が生じる。

前回の記事で指摘したように、『エリック・エヴァンスのドメイン駆動設計』においては、この「更新には柔軟に対応できない」というリレーショナルデータベースの特性を補うものとして、ドメイン層のクラスが役割を果たす。具体的には、ドメインモデル上の集約に不変条件を結び付け、トランザクション整合性の単位として厳格に守るような工夫をするのである。

一方で、参照であれば、データの整合性を維持する役割をアプリケーションが担う必要もそれほどない*5。このことをアーキテクチャに反映させたのが、『エリック・エヴァンスのドメイン駆動設計』(2004年)から9年後に描かれた『実践ドメイン駆動設計』(2013年)で大きく取り上げられているCQRS(コマンド/クエリ責務分離)だと言える。


CQRSにおいては、書き込み系と読み取り系とでモデルを使い分ける。業務ルールに基づくデータの整合性に配慮すべき書き込み系のモデル(ドメインモデル、ライトモデル)から読み取り系のモデル(クエリモデル、リードモデル)を切り離すことができるというのが、そのポイントになる。

CQRSの着眼点は、書き込み系と読み込み系とではアプリケーションに対する要求が異なるということであり、必ずしもリレーショナルデータベースの特性に着目したものではない。しかし、先に指摘したリレーショナルデータベースの特性から考えてみると、自然な帰結としてCQRSを導くこともできたのではないだろうか。

リレーショナルデータベースの強みを活かす「SQLQL」

リレーショナルデータベースの特性からCQRSを導くとすれば、その先には「ユーザから直接SQLを受け付ける」という発想が見えてくる。yanchaさんが提案している「SQLQL」がそれである*6。SQLQLというのは、リモートのエンドポイントに対して、クライアントからSQLを文字列として送信することによってJSON形式の文字列として実行結果を得る仕組みを表している。

qiita.com

リレーショナルデータベースは、それ自体として柔軟な参照の仕組みを提供している。そうであるとすれば、

  • クライアントのアプリケーション
  • サーバのアプリケーション
  • リレーショナルデータベース

という構成をとった場合に、サーバのアプリケーションで一旦オブジェクトとして取り扱うことが、リレーショナルデータベースの柔軟さを殺すことになっているという解釈もできる*7

CQRSを採用するだけでは、上で指摘した事態は解消されない。参照側で、リードモデルとして静的なクラスを定義している場合はデータ構造に修正を施す必要があるし、データ構造を動的に生成している場合であっても、参照の仕方を変えるためにはサーバ側のクエリに手を入れる必要がある。

このような状況に対し、SQLQLを採用すれば、画面での参照の仕方を変えたい、欲しい属性が増えたという場合に、サーバのアプリケーションには一切修正を入れることなく対応できるわけである。柔軟な参照の仕組みを提供しているリレーショナルデータベースの能力を最大限に活かす考え方だと言えるだろう*8

終わりに

以上、参照は柔軟だが更新は柔軟でない(柔軟ではいけない)というリレーショナルデータベースの特性の自然な帰結として、CQRSとSQLQLを位置付けることを試みた。CQRSもSQLQLも他人の考えたものであるが、自分なりの整理ができたのではないかと思う。

本記事でできなかったことを挙げておく。まず、オブジェクト指向データベースやキーバリューストアなどのNoSQLデータベースには詳しくないので、それらとの比較はできなかった。また、大きな課題として、リレーショナルモデルとオブジェクト指向モデルの違いについても、検討が及んでいない。

オブジェクト指向には、単なるデータ構造としての意味だけでなく、振る舞いを持たせるという側面、あるいは人間のメンタルモデルとの一致を目指すという側面もある*9。今後の課題としたい。

*1:杉本啓さんによる対訳版を使用した。こちらの勉強会のページに原文および対訳版へのリンクがある。

*2:増永良文『リレーショナルデータベース入門』44ページ。ただし、ここでは整合性(consistency)ではなく「一貫性(integrity)」という表現が用いられている。両者の関係については、Quoraの回答が手がかりになる。

*3:コッドの1970年論文でも、整合性の検査が更新操作の速度を落としてしまうことへの懸念が述べられているとともに、対処するためのアプローチとしてバッチによる検査実行が挙げられている。

*4:データベースにおける制約の過度な利用については、『失敗に学ぶRDBの歩き方』に記載がある。それを読んでいた時の自分のツイートも参照。

*5:もちろん、柔軟に発行できる問い合わせのなかで「意味のある」ものだけを提供するという意味では、参照側もアプリケーションには意味がある。しかしそのアプリケーションは操作を隠蔽するだけで独自の操作を行うものではなく、ラッパー以上のものではないのではないかと思われる。

*6:SQLQLという概念の存在は、すえなみ(@a_suenami)さんに教えていただいた。

*7:「意味のある」参照のみを提供するということはもちろんある。先の注釈を参照。

*8:とはいえ、セキュリティなどの面でまだ実装上の課題は多いようだ。

*9:メンタルモデルとの一致という観点から、オブジェクト指向に対してDCIからの批判がある。この点については、「DCIアーキテクチャ - Trygve Reenskaug and James O. Coplien」を参照のこと。