Presentaion at Play meetup
Posted on 2014-06-02 by takezoux2Play Framework 2 Meetupで発表してきました。
5月24日に開催されたPlay Framework 2 Meetupで発表してきました。
内容は、DSLからのコードジェネレーションで楽々Play開発です。
イベントページのほうで、他の人の発表資料もだいたいみれるので、興味がある方は見てみて下さい。
イベント中にライブコーディングした部分は、スライド中にのせてあるgithubのレポジトリにコミットしてあります。
会場や懇親会で出た質問や、補足を書いておきます。
Q. 発表時のライブコーディングで、DSL中に記述している型で不正な型を入れるとどうなるの?
ライブコーディングのコードだと、DSLのパース中に例外が投げられてそこで停止します。 実際のプロジェクトで使ってるものは、任意の型を取れるようにしてるのでパース中ではなく、その後の型解決を行う際に例外になるようになってます。
Q. 発表時のライブコーディングで、DSLの構文が間違ってた時のエラーは?
ScalaのParserCombinatorが優秀なため、デフォルトで何行目の何文字目で構文エラーがあるかわかるようになっています。
Q. ジェネレーションギャップ問題(という呼び方でいいかな?)はどうするの?
コードの再生成を行った時に、コード生成されたファイルを編集してしまっているとファイルが上書きされて、実装の書き直しが発生してしまう問題です。
この問題はだいたい、ジェネレーションギャップデザインパターンで解決しています。
実装ファイルと、自動生成で作成されるインターフェイスの定義ファイルを分離しておくことで、コード生成は実装部分を壊さず変更があった部分はコンパイルエラーで検出できます。
もう一つは、ファイルの上書きを賢く行うという方法をとっています。 部分置換や、ファイルをチェックしてすでに実装が存在する場合はそれを壊さず新しいコードを挿入するなどしています。
Q. 実際のプロジェクトでは、役に立っているか?
細かな仕様変更の際に非常に役に立っています。弊社ではスマートフォン向けゲームを多数開発しており、サーバーとはJsonフォーマットのAPIでサーバーとクライアント間通信を行っています。 開発初期だと、そのAPIやまたはサーバーのデータベースなどの新規開発や、フィールドの追加、削除、変更などがバンバン入りますが、
DSLの記述 -> コード生成 -> コンパイル -> コンパイルエラーの出たところを修正
という機械的な手順で、楽+早い+ミスが少なく行えています。
実際のプロジェクトではコード生成で
データベース周りの場合は
- Create table文(SQL)
- DBモデルクラス
- テーブルとモデルクラスのマッピング
- CRUDを行うDBクラス
- DBアクセス部分のラッパーの雛形
API周りの場合はサーバーとクライアント用のコードを生成しており、
- 通信用モデルクラス(サーバー+クライアント)
- モデルクラスとJsonのマッピング(サーバー+クライアント)
- Play frameworkのroutesファイル
- Play frameworkのControllerクラス
- クライアントのAPIの呼び出しクラス
などを生成しています。
逆に言えば、コード生成なしの場合仕様変更のたびにこれらのファイル全てを手作業で変更する必要があるということになります。
Q. コードジェネレータ使うならPlay2じゃなくてもいいのでは?
ぶっちゃけPlayじゃなくてもOKです。Playの層はかなり薄く作っています。
補足
コードジェネレーションを行う事自体にかなりのコストが掛かるので、その点は注意が必要です。 ただし、個人の考えですが、 「将来のデスマッてる時の10分を削るために、開発初期段階の1時間を使っておく」 ということも有りなのではと思います。
あと、コードジェネレーションをするつもりなら、プログラム設計自体もそれにあわせたほうが良いです。 ドメイン駆動デザインの推奨するレイヤードアーキテクチャーは、コードジェネレーションにかなり親和性の高い設計だと思います。