uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

ダイナミックファインダーの嬉しさ

とある集まりでGrailsの説明をしていたら

「ダイナミックファインダー(findByXXX(...)で呼び出すやつ)って何がうれしいの? (findBy('XXX', ...)でいいじゃんw)」

と言われてしまった、という話が、前回のGrailsソースリーディングで、山田さんより紹介されてました*1

結構面白い話題ですので考えてみました。


●DRYの効用

まず言えることは、finderメソッドの作成は、いままでは手書きで行われてきたということです。Javaでいままでもくもくとやってきた「手書きのfinderメソッド作成作業」に飽き飽きしてきた人にとっては、finderメソッドの動的自動生成は現世的利益に直結的にうれしいことだし、また、そのような作業を日常的にしてきているのでなければそのうれしさは直感的には・即座にはわからないでしょう。一言で言うと「DRYの利点」です。でもこれで終わってはつまらないし、そもそもポイントではないと思うので続けます。


●finderメソッドはそもそもなぜうれしいか

本来、finderメソッドの存在が有用なのは、finderメソッドを持つクラスやクラスの集合体が、データベースのアクセスコードやテーブル構造を、アプリケーションコードに対して隠してくれる、抽象化レイヤを形成するからです。


●「抽象化レイヤの存在の嬉しさ」

このような抽象化レイヤの存在は、システム内での祖結合を実現します。ちなみに、静的言語においては、これに加えて、抽象化レイヤを書き下しておくことで、コンパイル時チェックとか、javadocがかけるとかの利点もあります。動的なfinderの場合、それはできず*2、その抽象化レイヤが実行時に確定するということがポイントです。


●データベースとの、「システム間レイトバインディング

動的なfinderメソッドの生成機能は、動的な型、それもダックタイピングならではのひとつの応用例を表していて、オンデマンドでクラス・型を、必要に応じて作り上げる、というやりかたの典型的なものです。

finderメソッドの動的自動生成が嬉しいのは、データベースというアプリにとっての外部システムをアプリケーション内から扱えるモデルの一部にマップする際に、それを動的に、実行時にまで遅らせることができるという点です。

遅らせない場合、事前の整合性保証が必要で、そのことが、多くのマッピング設定をしなければならなかったり、自動生成させたとしてもその設定が必要だったりして、開発工数の増大を招いていました。


●余談:結合性の問題

一般には、静的型は、それがインターフェースを明示的に定義するので、それを介したアクセスによって、サブシステム間の結合性を低めるとされています。ここではしかし、「動的にすることで結合性を低める」ということで逆転しているかのように見えます。ちなみにたぶんここが動的・静的論争の要です。

思うに、結合性というのは、論理的にはかるものというより、作業工数(心理的負担量を含む)の多寡の問題です。

ビジネスロジックの変更があった場合、それに伴っての設定ファイル・静的クラス定義の変更工数が、設定ファイル・静的クラスが存在していることによっての稼動削減工数を上回る場合、結合性の逆転現象が始まるわけです。ここらの前提やトレードオフは、開発対象システムのビジネス要求や、開発組織によって異なってくることでしょう。


●余談:Groovy

余談ついでに言うと、この種の前提やトレードオフは、1つのシステム内でも異なってくる、というのが私の考えです。なのでそれぞれに向いた言語を使い分けたい。「マクロ言語」とかそういう考えですね。硬いところも必要で、ミドルウェアとかフレームワークとか言語処理系実装は硬い言語、ユーザカスタマイズや、ビジネスロジック寄りのところや、プラグインとかは動的言語、という使い分けが(速度面を考慮しても)いいのではないかと。JavaとGroovyの使い分けがそれにあたります。さらに、1言語の中で、動的型付けと静的型付けの使い分けがやれるというのが、Groovyのいいところでもありますが、それはまた別の話、別のところで語るとしよう。


●パラメータではなぜ駄目か

話を戻して、動的なのは良いとして、じゃあなぜ、条件をパラメータで渡すfindBy(XXX,...)では駄目かというと、私の考えでは、それはオブジェクト指向的ではないからです。

findBy(XXX, ...) におけるXXXはメソッド引数の処理の問題にすぎません。クラス図に表れてこない存在です。これに対して、findByXXXはクラス図にメソッド名として表れてくる存在です。ただしそれは、実行時に動的に変容するクラス図になります*3

findByXXX(..)にして嬉しいのは、それによってそのクラスに何ができるかをクラスインターフェースとして(というよりオブジェクトインターフェースとして)よりよく表すことができるから、です。メソッド処理実装やそのドキュメントの中に隠しこんだりせずに。ただし、そのインターフェースは動的なものなので、確かにソースコードや(静的な)クラス図にはメソッドの実体としては書き残っていません。しかし、たとえそうであって、実行時には、そして実行時のことに思いをいたすプログラマの思考の中には、存在し、意味があるのです。ダックタイピングとはそういう考え方です。


●まとめ

突き詰めると最初の問いは、「動的型オブジェクト指向の利点は何か」という結構深い問いの部分問題というわけです。上のような議論は、「mixin」とかオープンクラスについても同様に展開できるはずです。mixinとGroovyのuse(Objective CのCategory)の違いとかについても、検討してみたいと思います。
いじょでした。

*1:このようなfinderメソッドの生成は、Ruby on RailsでいうところのAcriveRecordsのDynaFinderの機能ですね。Grailsにもあるとのことですが、何と呼ぶのでしょうか。

*2:ドキュメントについてはメソッド単位ではできないという話であって、原理的にはできますが。

*3:それをクラス図と呼ぶべきか?