「O/R マッピングの是非」に触発を受ける。PerlではClass:DBIやDBIx::Class, RubyではActiveRecordなど、今やO/Rマッパー全盛時代だ。確かに、開発効率や生産性について言えば、O/Rマッパーを使うとだいぶ楽な気がする。getter/setterを書かなくていいことに始まり、templateやvalidatorと強力に連携してあっという間にレコードのCRUDインターフェースを実現してしまう。

 一方で、チューニングの余地がほとんどない、安易なテーブル設計に流れがち、トラブル時のデバッグが面倒、などの点がデメリットとして挙げられる。

 DB設計の肝は、ディスクアクセスをいかに減らすかにある。シーク効率のために固定長レコードを指向し、テーブルを正規化して分離し、個々のテーブルサイズは抑え、必要なものだけjoinする。これが従来からの常識だ。

 ところが、さまざまなプレッシャーから実行効率よりも開発効率が追い求められ続けた結果、いわゆる「量の革命」の追い風もあって、こうしたパラダイムはないがしろにされつつある。

 冷静に考えれば、DBの帯域やCPUパワーなどの量的な力は、相対的にはさほど飛躍していない。サーバの単価あたり性能が数倍になっても、その間に利用者人口は10倍、100倍に膨れあがっている。企画から2,3ヶ月でサービス開始に漕ぎ着けるスピードは欠かせないが、運用や改修で泣きを見る例に事欠かないのもまた事実だ。

 後からリファクタリングしようにも、モデル層はカプセル化・ブラックボックス化されてしまっている。フレームワークの奥深くに手を入れてスパゲッティ化させるリスクを冒すのもためらわれる。ロジック層で打てる手は少なく、局所的なキャッシュや動的生成の静的化でしのぐのが精一杯。機能追加や改修においては常にパフォーマンスがネックとなるが、パフォーマンス予測を立てること自体も困難になっている。…といった具合。

 設計アプローチを考ると、そもそも、リレーショナルデータモデルにおいては整合性や効率に重きが置かれ、オブジェクトモデルにおいては可読性や再利用性に重きが置かれるものだ。こうしたギャップ(インピーダンスミスマッチ)を埋めるためにO/Rマッパーがあるのだ、という位置づけはしっかり理解しておかなければならない。O/Rマッパーを使う場合でも、ユースケースをきちんと分析してモデルを設計するということをしなければ、MVCの歯車をつつがなく回し続けることはできない。

 一般に、テーブル設計をクラス設計に擦り寄せれば、リレーションを駆使する必要は減る。この罠にはまると、オブジェクトクラスにそのまま対応させたテーブルを作ってしまい、コードの見かけはきれいでもデータはぐだぐだな代物ができがちだ。O/Rマッパーは可読性と開発効率をもたらすが、再利用性にはほとんど寄与せず、実行効率に至っては大きく犠牲にしている。このトレードオフのために、データの整合性を自ら捨てる手はない。

 パフォーマンスを考慮するならば、まずテーブル設計ありきの方針を徹底するべきだろう。O/Rマッパーは基本的にO/T(able)マッパーとして使い、R(elationship)については極力自分で面倒を見る。プログラム側で複雑なDB処理がある場合は、積極的にストアドプロシジャの利用を考える。

 短納期で設計フェーズもほとんどない開発の現場で、よいパラダイムを互いに啓蒙しあって共有し、いかに保守運用まで含めて品質の高いものを作るかというのは大きな問題だ。結局は知識とセンスだよな、と言うのは簡単だけれども。


Categories : Tech