Grails勉強会
先週の金曜日にワークスとの共同勉強会がありました。題材はGrailsでした。諸般の事情により資料の公開はできません。GroovyもGrailsも基本的にゼロ知識で聞いたので、どちらの知識も僅か1時間程度の知識という前提で以下を読んでください。
Grailsの感想は、くやしいけど良くできている、です。くやしがるいわれは何もないのですが。今、何の偏見も予断も持たずに、Ruby on RailsとGrailsを見たら、Grailsを選んでしまいそうです。現実には、偏見と予断があるので、Railsを選択しています。
RubyとGroovyを見比べても、Groovyの方が良く見えてしまいます。Groovyは、書こうと思えば変数の型を明示できたり、Javaのクラスをそのまま使えたり、リテラル表現の簡易さはRubyと同程度にできそうだったりと、良いところだらけです。Rubyの方が良いところって何があるんだろう、と考えてしまうほどです。たぶん、あると思いますが。Rubyの良いところを探すために、Groovyを調べるのも不毛なので、特にGroovyを調べてはいません。
RailsとGrailsの違いで気づいたことのひとつが、Grailsの方は明示的なクラスの継承を書かない点です。Railsでは、例えばデータベースのテーブルに対応するモデルクラスは、次のようにActiveRecord::Baseクラスを継承して書く必要があります。
class User < ActiveRecord::Base end
こう書くことで、usersという名前のテーブルを探して、必要なインスタンス変数やメソッドをUserクラスに定義します。
内部的にはinheritedという、子クラスが作られた時に呼ばれるコールバック関数がRubyにあり、Railsはそれを利用してします。次のコードを実行すると、Derivedクラスを定義したタイミングで、親クラスのinheritedメソッドが呼ばれます。
class Base def self.inherited(subclass) p subclass p subclass.class end end class Derived < Base end
ActiveRecord::Baseクラスのself.inheritedメソッドで、子クラス(上の場合だとUserクラス)への参照と名前が分かるので、名前からテーブルを探して、子クラスを改造します。
Grails(Groovy)の内部的な仕組みは知りません。
もう一点、RailsとGrailsの違いで気になったのは、用語の差です。Railsのappディレクトリの下には、controllers、helpers、models、viewsの4つのディレクトリがあります。このうち、helpersはビューの下請け処理用のディレクトリなので、置いておきます。その他は、いわゆるMVCアーキテクチャの用語そのままです。
Grailsはcontrollers、domains、services、viewsの4つのディレクトリがあります(helpersがあったかは未確認)。GrailsのdomainがRailsのActiveRecordに相当します。個人的には、Grailsの区分の方が好みです。
Railsのアプリで、いわゆるビジネスロジック的な処理をどこに書くべきかを最初迷いました。viewsの下に書くのは論外なので、controllersの下かmodelsの下です。コントローラが太るのは好みに合わないので、消去法でmodelsの下になりました。しかし、個人的には、データベースと結び付いたクラスとそうでないクラスの間に線を引きたいと思いました。そのため、modelsディレクトリの下にfoo_service.rbのような、サービスクラスを作ることに決めました。
Grailsのことは知りませんでしたが、Grailsと似た区分をしていたことになります。もっとも、Grailsの「ドメイン」の用語の使い方は微妙です。ドメインがそのままデータベース定義に等価になるのは、用語として微妙に感じます。ActiveRecordパターンだからそういうものだ、と言われてしまうと返す言葉も無いのですが。
個人的な用語の好みは、データベースへのアクセス層と、Webアプリのロジックを提供する層のふたつに分けて、前者をエンティティ層、後者をサービス層と呼ぶスタイルです。ビジネスロジック層とサービス層に分けて、サービス層は薄いAPI層であるべきだという反論もあるかもしれません。その辺の宗教論争をする気はありませんが、個人的には、データベースに結び付いた層とそれ以外、という2層で充分だと思っています。つまり、Grailsの区分と同じということです。
勉強会の中でコントローラクラスのインスタンス化の話がでました。Railsのコントローラクラスのインスタンスオブジェクトは、リクエストごとに生成されます。JavaのServletでコントローラクラスがシングルトンオブジェクトなのと対照的です。
一見、リクエストごとにインスタンスを生成するRailsは非効率に見えます。実際には、コントローラクラスのインスタンスは軽いのであまり問題にならないはずです。更にもうひとつ仕掛けがあります。Railsのコントローラクラスのインスタンスは、そのままビューから参照されるコンテキストの役割も負います。Spring Frameworkの用語を使うと、「狭義のモデル」の役割を、Railsのコントローラクラスは負っているのです。ビューから参照したい状態があれば、Railsのコントローラオブジェクトは、ビューに渡すコンテキストオブジェクトを新たに作るのではなく、自分自身のプロパティに状態を持たせます。JavaのServletのコントローラしか知らない人にとっては驚きの動作ではないでしょうか。この動作により、結局、リクエストごとに必要なインスタンス化の回数はRailsでもJava Servletでも同程度になる気がします。裏は取っていませんが、Grailsのコントローラクラスのインスタンス化の仕組みもRailsと同じだと思います。
勉強会の中でクロージャの話題がでました。クロージャとクラスメソッドの関係について書いておきます。最初に結論を書くと、クロージャとクラスメソッドはそもそも異なる概念ですが(なので、関係ありますか、と聞かれたら関係無いが答えです)、クロージャを使うとクラスメソッド的なことが実現できます。クラスメソッド的なことを実現するのに、(C++やJavaのような)暗黙のthisパラメータによる手法以外に、クロージャでも実現できる、ということです。
クロージャを教科書的に言えば、「関数+環境」です。「関数」の部分は関数オブジェクトでも関数ポインタでもどちらで考えても構いません。「環境」は教科書的な意味はともかく、関数が定義された場所のスコープで見えている変数と考えてください。結果的に、クロージャは、関数が定義されたスコープで見える変数の状態を持った関数になります。「状態」は本当は「環境」と別に定義された専門用語ですが、ここでの状態は、一般用語に近い用語で考えてください。クラスのメソッドも、ある意味、状態を持った関数です。クロージャで、クラスベースのメソッドと同様のことができるのが想像できると思います。もちろん、クラスメソッドを実現するには、thisポインタの方が効率的でしょう。なので、Groovyのクラスメソッドがクロージャという点に関しては、理屈上の問題は無いと思いますが、真偽に関しては不明です。
- Category(s)
- カテゴリなし
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/inoue/grails/tbping