はじめに
あまり否定的なことは書きたくないのだが、この記事を読まれる方の問題提起となればと思ってアンチ パターンと思えるこのことについて、僕の考えを書く。まずは言語とかフレームワークに依存しない、設計全般の話題について。
例外というものについて
まず、プログラミングで言う「例外(Exception)」は、当然ない方がよい。プログラミングの人的ミスはバグと言われ、私たちが十全ではない以上、どこにでも潜んでいるものである。このバグを減らすために昔から様々な工夫がされてきた。その一つが静的言語というアプローチだ。C# などの静的言語の優れたところは、プログラムの実行時ではなく、コード開発中にプログラムを解析させることによって、その時点でバグ(間違い)が発見できることだ。そう、コンパイルができない、つまりプログラム自体が作成できないのだ。
「例外(Exception)」というのは、実行時に起こりうる、言わば障害である。月日が想定されるところに 13 月とか 32 日とかが入る余地があると、それは障害となるため、「例外」を発生させるような仕組みになっている。例外が想定されるところは、その例外を捕獲(catch)するように組んでおき、例外の場合の対処を書けば、障害を克服できる。しかし、本当は例外自体が起こらない方がよいのである。たとえば、先ほどの例ならば、あらかじめ月には 1~12 しか入らない、日付には 1~31 しか入らない部品など(組み込み型の DateTime など)を使えば、先ほどの月日の範囲についての例外のことは考えなくてよくなる。
なぜ NotSuppotedException を設計に問題ありというのか?
さて、題名に「NotSupportedException は設計に問題あり?」と書いた。問題ありと言おう。なぜか? この例外の意味は、「実行時に、サポートされていない機能が使われていてダメ!」ということだ。サポートされていない機能ならば、本来なら実行時ではなく、開発時にそれが使えないようにしておくのが良い設計だからだ。そうすれば実行時になってダメです、なんてことにはならない。
なのに、だ。NotSuppotedException が吐かれるということはつまり、開発時にはいかにも実行できそうな顔をしておいて、実行時にエラーとなる、というバグを潜在させるアプローチがこの例外なのだ。これは、静的言語の利点を無駄にしてしまう。
Entity Framework の欠点
さて、ここまでが設計デザインについて、言いたかったことだ。ここからは、よくないと思われる一例を挙げる。
Entity Framework というモノがある。これは、データベースなどを LINQ という統一された手法で、操作する技術だ。LINQ は表面的には SQL のように割と宣言的に、同一構造の複数データを相手に、こういうデータを取得したいという風に書ける。メモリー内に格納されているデータについて、LINQ は素晴らしい機能を提供している。しかし、問題は、表面的に同じ LINQ の書き方をしながら、データベースにアクセスする Entity Framework などである。Entity Framework が超カシコクて、メモリーにアクセスするのと同様に LINQ でスイスイと書けるならばよい。しかし問題は深刻だ。複雑な LINQ でも確かにスイスイと書ける。コンパイルは通り、プログラムができあがる。そしてそれを実行すると…… NotSupportedException が出て止まってしまうのだ。
何が起こったのか? つまり、Entity Framework は、そこまで賢くなく、機能に制限が大あり! ということなのだ。使える機能に制限があるならば、制限した機能を使って書くことができないようにデザインするべきなのだ。ここに落とし穴がある。どんな複雑な LINQ を書いてもスイスイと超賢く翻訳してくれるのなら問題はない。
メモリーについての LINQ、つまり LINQ to Object は、とてもよくできている。IEnumerable(T) という型(同一構造の複数データ)を相手にしている。Entity Framework が提供する LINQ は、LINQ to Entities と言って、IQueryable(T) を相手にしているのだ。実際には同一構造の複数データに直接アクセスするのではなく、それを取得するエンジンに対する命令を生成して投げているところが違う。つまり、LINQ を SQL などの命令に翻訳しているのだ。そして、これを使う場合、その翻訳がうまくできているのか、効率よく翻訳できているかをチェックしなければならないのだ。そのチェックは…… 実行しなければチェックできないのだ。
だから、データ ベースについての単純ではない問い合わせについては Entity Framework を使用するのは、私はあまりお勧めしない。
では、どうすればよいか?
では、SQL 文字列を埋め込むのか? いや、それなら Entity Framework の方がずっとマシである。文字列でしかない SQL など、実行時しか解析されない。
オススメの方法はこれである。→ 複雑な操作はユーザー定義関数(ストアド ファンクション)やストアド プロシージャーなどをデータベース上に SQL で作成しておき、それを Entity Framework で呼び出す方法である。この方法であれば、SQL は開発時に解析されるし、無理して複雑な LINQ を書いて怒られたり、チェックしたりする必要もない。
Entity Framework すべてを否定しているわけではない。要はバグを生みにくいように工夫して使えばよいのだ。
また、ライブラリーを作成するときには、なるべく実行時の例外を減らす工夫をしたいものである。