[grails]Grailsベストプラクティス
InfoQ記事の翻訳です(日本語版で翻訳されない…orz)。
わたし(Amit Jain氏)はIntelliGrapeというGroovy&Grailsを専門とする会社で働いています。この記事は、私たちのGrailsプロジェクトが従う、メーリング・リスト、スタック・オーバーフロー、ブログ、ポッドキャストsおよび内部議論から集めたベスト・プラクティスの基礎的なリストです。コントローラー、サービス、ドメイン、ビュー、taglibs、テストおよび一般に分類しています。
コントローラー
- コントローラーが他の役割を兼ねてはいけません。コントローラーの役割は入力リクエストを受け入れ、パーミッションをチェックし、結果をドメインあるいはサービスに確認し、HTML、JSON、あるいはXMLなどの期待されるフォーマットでリクエスト側に結果を戻すことです。コントローラーはできるだけ薄くしてください。コントローラー内で、ビジネス・ロジックの実行や、クエリーあるいはアップデートを実行してはなりません。
- コントローラーが単一のドメインクラスに対応している場合は、「
コントローラー」で使用される標準的な命名規則に従ってください。 - コードの重複を回避してください。共通のオペレーションはクロージャまたはメソッドとして抽出されるべきです。詳細は、このブログ・エントリーを参照してください。
- 複雑なデータはコマンド・オブジェクトに分離して下さい。コマンド・オブジェクトをリッチに(リッチなドメインクラスのように)することができます。コマンド・オブジェクトの階層を作ることは、いくつかのシナリオで役立つかもしれません。
サービス
ビュー
- できるだけ単純なビューを維持してください-この層にビジネスロジックあるいはデータベース・ロジックを入れる誘惑は振り払ってください。
- アプリケーションのすべてのページもしくはそのサブセットのページ群において、共通する一貫した外観を保証するには、layoutを使用してください。
- ビューをDRY(「繰り返さない」)に維持してください。繰り返される内容はテンプレートに分割してください。
- カスタムTagLibsを共通のUI要素に使用してください。
ドメイン
- ドメイン固有のロジックは、ドメインクラス自身に置きなさい。わずかの依存性をもっていて、単一のドメインに当てはまるものは、そのドメインクラス内にあるべきです。しかし、そうするのはそのドメイン特有のロジックだけにしておいてください。複数のドメインを処理するより複雑なビジネス・ロジックは、サービスに所属させます。
- 共通の部分的なクエリーを再使用する場合、あるいは複雑なロジックを分解する場合、名前付きクエリを使用し、必要に応じてそれを連結しなさい。jQueryでの関数呼出しを連結するように。
- domainフォルダー中には、他のユーティリティクラスやバリューオブジェクトは含めず、src/groovy配下に置きなさい。もしそれらのクラスでバリデーションをサポートする必要がある場合、@Validatableアノテーションを使うことができます。
- ドメインオブジェクトをインスタンス化する際には、不完全な状態を避け、かつ有効なオブジェクトだけを構築するためにsensibleなコンストラクタを利用してください。
TagLib
- タグの処理内容は肥大化させないように。タグは他のタグを呼ぶことができますし、必要なら再利用可能な「サブタグ」にタグを分解しても良いでしょう。
- TagLibはMVCアーキテクチャーのビュー層の一部とみなされます。しかし、表示するデータを組み立てたり、フォーマットしたりするために必要なドメインクラスを手繰っていってデータを取り出すのは構いません。また、ドメインとの直接の相互作用は最小化する、というアプローチに従ってください(全面禁止ではない)。
- TagLibはレンダリング処理よりもロジックの方を多く含んでいるべきです;ごく少しのレンダリングは良しとします。
- よりよい構成にするために、多数のカスタムtaglibsを使用してください。
テスト
Config.groovy
- serverURLなど、環境によって異なる定数値は、すべてConfig.groovyに置きます。
- 個人のセッティング(ローカル・データベースのユーザー名、パスワードなど)は、ローカルConfig.groovyファイル中に維持し、バージョン管理の無視リストに設定しておきます。その結果、チーム・メンバーはそれぞれそれらの特定のニーズに応じて上書き設定することができるようになります。
- ときどき論争の的になりますが、私たちのアドバイスは、ドメインの保存時のバリデーションが失敗したらすぐに例外が投げられるように「grails.gorm.failOnError = true」と設定するということです。こうしておけば、保存が成功したかどうかをいちいちチェックする必要はありません。
- Grails 2.0ではデフォルトで「grails.hibernate.cache.queries=true」なので、cache:trueしなくてもクエリが自動的にキャッシュされてしまいます。これはfalseに設定し、真に性能が向上する場合に限りcache:trueでキャッシュするようにします。
他のいくつかのTIPS
- Grailsの規約を理解し従ってください。Grailsは規約指向です。これらの規約を使用することで、開発者ライフを簡単にしてくれます。
- 異なるパッケージ中にGrailsアーティファクトを置くとき、com.businessname.appname.domainとcom.businessname.appname.controllerの配下に置くのやめましょう。そうしなければ、FooControllerでは、Fooクラスが自動importされます。Grailsは異なるフォルダーにこれらのアーティファクトを保存しますが、それらをさらに分離する必要はありません。このブログを参照してください。
- Fixture pluginは、開発中の初期データを準備するのに使えます。
- アプリケーションの再使用可能部品はGrails プラグインとして開発してください。これらのプラグインは個々にテストすることができ、それらを使用する側であるメインアプリケーションの複雑さを除去することができます。他の人もそれらから利益を得る場合があると思えばパブリックなpluginリポジトリで公開することを考慮してください。
- あなたのプロジェクト固有のビュー&コントローラーを生成するために、scaffoldedテンプレートを更新してください。
- 静的スキャフォルドよりも動的スキャフォルドを好みなさい。動的コントローラではもはや用を足さなくなるまでは。例えば、「save」アクションだけを修正する必要があるときには、「save」アクションだけをコントローラで再定義すれば、実行時に動的に生成されるコードを上書きすることができるのです。
- DataSource.groovyの中のデータベースre-connectionプロパティを常に提供するのが良いでしょう。
- 外在化されたコンフィグ・ファイル(それが空ファイルでも)を含むことを常に確認してください。その結果、productionで無視される必要のあるどんな設定も、新しいwarファイル生成せずに設定することができます。
- 既存のpluginを少しだけ変更する必要があるとき、たとえばquartz monitor pluginのlist.gspを見た目だけ修正する場合、pluginをこの変更のためにアプリ内に展開(インライン化)してしまう代わりに、同じディレクトリ・パッケージ構造に従ってlist.gspを置くことで、これらのファイルを上書きすることができます。アプリケーションは、使用するプラグインよりも高い優先権があるので、そのように動作します。
- ドメインのカスタムバリデータを、複数のドメインで使われる制約で再利用したいとき、共有バリデータファイルに入れておくことができます。例については、ここで見てください。
- pluginをアプリケーションにインストールするのに、install-pluginコマンドを使用するのではなく、BuildConfig.groovyの中で宣言するほうがよい。詳細な説明のためにこのスレッドを読んでください。
何かを見逃したかな。プロジェクトか構成で従う、Grails開発に関連するベスト・プラクティスは何ですか。私たちが記事をさらに豊かにすることができるように、コメントとしてそれらを共有してください。