この章はすばらしい。この章でLogic in SQLアプローチが不利な点をあげて、結論として速度よりも柔軟性を重視するドメインアプローチがすばらしい、などというのかなと思っていたのだが、ぜんぜんそんなことはない。
分かりやすさ(Understandability)
Fowlerさんはドメインモデルが一番わかりやすいという。確かにそうかもしれない。なぜならきちっとした思想の元で分割されているからである。しかし、SQLになれた私にはそうでもない。これは人による。だから、
という結論になるのは当然だろう。
重複排除(Avoiding Duplication)
つぎに、重複の排除という点から見よう。ドメインロジックはメソッドが適切に分割されていれば再利用は容易である。しかし、SQLは単なる文字列の羅列に過ぎず、再利用はできない・・・・・・というわけでもない。Fowlerさんはこういう。
重複排除問題でSQLに触れないのはフェアではないだろう。リッチなSQLアプローチでも、重複問題を避けることは出来るのだ。データベース熱狂者は必死になってこう言うに違いない。ビューを使え、と。
そのとおりだ!!!と声を大にしていいたい。ビュー愛好家の私はこの言葉を待っていた。なぜこのようなことを触れる本が少ないのだろうか?ビューを嫌い、SQLを簡単にするために安易な派生属性*1に頼ってしまう設計者のなんと多いことか・・・。(ってOOとはあんまり関係なかったか・・・)
たとえば、Fowlerさんの例を使うと、値引きの適用が可能かどうかということをデータとして格納してしまうような設計をよく見かける。更新は日時などのバッチで行ったり、リアルタイム性が必要な場合は注文の更新時の処理に入れてしまったりする。
皮肉なことに、ドメインモデルの場合のほうがこの考えがあっているかもしれない。この更新処理は当然ながらビジネスロジックの部分におかれるので、このような考え方も適用できる。検索処理の非効率性に悩むこともなくなる。
ただし、更新処理に負担をかけるとロックの問題や、データの不整合の問題に悩まされるかもしれない。よって、注意深く設計しなければならない。ちなみに、私はこのような設計は(よっぽど検索に速度を要求される場合を除き)シンプルでなくなるので大嫌いだ。夜間のバッチ処理で整合性チェックをしなければならない悪夢はもう勘弁願いたい。
カプセル化(Encapsulation)
ドメインモデルは、このカプセル化についても有利だ。というよりも柔軟性を確保している大きな要因になっている。
SQL in Logicはどうか。ビューがあるじゃないか!Fowlerさんの文章にはビューは更新ができないとあるが、そんなことはない。instead ofトリガというデータベーストリガを使えば更新もできる。アプリ側では単に表を(実はビューを)updateしているだけなのだが、裏ではストアードプロシージャで処理できる。実際のテーブルの構造によってSQLを書き換える必要はまったくないのだ!!!すばらしい。
Fowlerさんはここで、データソースビューとビジネスロジックビューに分けることを提案している。例で言えば、単にタリスカーの売り上げを集計するビューとタリスカーの売り上げによって割引を適用するかどうかのビューを分けてしまおうという。この場合では前者がデータソース、後者がビジネスロジックになる。
これはいい考え方かもしれない。ただ私なら、タリスカーの売り上げを集計するビューをデータソースビューにせず、商品ごとの売り上げを集計するビューをつくり、それにつかって、ビジネスロジックのビューでタリスカーという一商品を考慮すべきだと思う。
あと、もうひとつは、データソースビューとビジネスロジックビューに分けるんだったら、ついでにプレゼンテーションビューも作ってしまったほうがいいのではないだろうか。つまり、GUIや帳票上などユーザーの目に触れる形のビューである。というのも、GUI上のアプリケーションはよく似た検索を使用することが多く、流用可能なことが多いからである。プレゼンテーションビューはデータソースビューとビジネスロジックビューに依存するという形をとる。Fowlerさんの例で言えば、割引を適用するかどうかという検索はビジネスロジックビュー、それを注文IDや日付とあわせて出力するのはプレゼンテーションビューという分類になるだろう。そして、このプレゼンテーションビューにinstead ofトリガをつけておく。
ただ、このように多階層にビューを作り上げていく上で、ひとつだけ注意してほしいことがある。それはビューによってオプティマイザが変な実行計画を作ってしまうことがあるという点である*2。ここはとくに気をつけなければならないところだ。
データベース移植性(Database Portability)
ここはおっしゃるとおり、SQL in Logicアプローチの最大の欠点だろう。たとえば以下のようなSQLがあるが、これはDBMSに依存している。
SELECT orderID, date, customerID, name, total_cost,
CASE WHEN taliskerCost > 5000 THEN 'Y' ELSE 'N' END AS isCuillen
FROM dbo.OrdersTal
この中で、CASE WHENという関数*3はPostgreSQLでは使用できるだろうが、おそらくOracleは使用できないはずだ*4。OracleではDecodeを使用することになる。MySQLではIf関数を使用することになるだろう*5。
つまり、移植性を考えるならばリッチなSQLを書く選択肢はないということだ。