最近Grailsを少しかじったのだけれど、その中で「Service」というArtefact(コンポーネント、みたいな意味合いのようだけれどGrailsの世界観ではこんなふうに表記するみたい)というのがよくわからなかった。 どうもDomainモデルとかそのへんと絡んでそう。 実は、自分の場合データ操作をどう設計するのかってめちゃくちゃ自己流、というか経験的な直感でクラス設計しまくっていたので、その辺、一般的・・・というかOOPの「意識高い」系だとどんなもんなんだろうと、ヒッジョーにイマサラナガラなんだけどPoEAA本ひっくり返してみて、SQLとの連携に使われるパターンを確認。 - Transaction Script - Domain Model - Table Module - Service Layer - Table Data Gateway - Rwo Data Gateway - Active Record - Data Mapper ・・・なんというか、自分の今までの直感と経験による言語化出来ない地雷回避感覚に基づくクラス設計が、そうそう外した設計にしてはいなかったようで、ホッと一安心。 あともう一つ気づいたのは、「これが一番正解」というようなパターンはなくって、RoRとかRails系だとActiveRecordがよく使われているけど、じゃぁそれがPoEAAで最も推奨されているのかというとそれほどでもなくて、割りと「規模によってはRow Data Gatewayでもいいんじゃね?」とか、Domain Model + Data Mapperの組み合わせとか、割りと、アプリケーションの規模に応じて組み合わせを変えて、結局のところバランス感覚で「ベストは無いのでベターを選ぶ」的なオチどころ探索の流れ。 逆に言うとActive Recordだけじゃ物足りないシーンも当然出てくるので、そうした場合は他のパターンでも全然OKな感じに書かれてる。 多分自分がActiveRecord嫌いなのは、これまでのお仕事の経験上、ActiveRecordのメリットが活かせない設計シーンが多かったからなのかなーと。 Servce Layer挟んでDomain ModelとかActive Record使う、という設計は全く違和感がなくて、いえむしろフレームワーク側でActive Record自動生成してくれるんなら両手上げてそっちに雪崩れ込みたいくらいです。 トランザクションをまとめて、しかもそれが単体テストの自動化にシームレスに組み込まれば、どんなパターン使おうと何もいうことはござーません。 で、GrailsのServiceに話を戻すと、結局のところやっぱりService Layerと同じ位置づけになってて、トランザクションを扱えます。ただしHibernateのトランザクションがそのまま透過されるのかというとちょっとその辺が勉強不足でよくわかりません。2.1.0の公式ドキュメントにも、rollback周りでいろいろ注意点が書かれてるんですが、流したくらいで熟読はしてないです。 とはいえSpringDICのおかげで、割りとPOJOとしてテスト出来る感じにしてくれてるので、個人的にはある程度複雑なデータ処理が絡むところはServiceにまとめてテスト可能な状態にしておきたいところです。(まぁView側でちょっとカテゴリとかのプルダウンメニュー表示するのに使いたい、位のロジックであればDomainそのまま使うかDomain側に実装しておいても問題無いと思います) 以下、参考: - 9 The Service Layer 2.1.0 -- http://grails.org/doc/2.1.0/guide/services.html - Using grails service in domain class - Stack Overflow -- http://stackoverflow.com/questions/2459897/using-grails-service-in-domain-class - Service クラスのトランザクション - Grailsとの接近戦 -- http://d.hatena.ne.jp/ofg/20080327/p1 --- 2008年時点で古めですが、内部まで踏み込んで書かれてます。 - Grails Service Transactions - Stack Overflow -- http://stackoverflow.com/questions/2072648/grails-service-transactions --- Serviceクラスを手動でnewして嵌った例。SpringによりDIさせなけりゃイカンので、注意。 ちなみに2.1.0の公式ドキュメントではtransactionのデフォルトの"propagation level"(・・・なにこれ?)というのがPROPAGATION_REQUIREDになっているとのこと。 よくわかりませんが、Spring 3.0系では、Transaction使う時のデフォルト値になってるみたいなので、恐らく大体のケースでは問題ない設定なのでしょう。多分。 - Spring 3.0でのJavaDoc -- http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/transaction/TransactionDefinition.html#PROPAGATION_REQUIRED --- 既にトランザクションが始まってればそれを使う、無ければ新しく作る、という意味のようです。 - ビジネスロジック部分の作成 - とあるITエンジニアの業務手帖 -- http://d.hatena.ne.jp/getbean/20071220/1198129499 このへんの「トランザクション」が、DB側の「トランザクション」と同意なのかはよくわかりません。