playframeworkでBOT生成アプリを作ってみました

cloudbees+playframeworkの環境で、試しにBOT生成アプリを作ってみました。

twitter BOT生成アプリケーション

twittbotの劣化アプリ*1です。一応Reply返したり定期的につぶやいたりするくらいの機能はあります。無料アカウントなのでスケールはしないと思いますがw
開発にかかった時間はプロトタイプで2日程度、画面綺麗にしたり独自認証追加するのに1日くらいでした。一番大変だったのはOAuth周りだった罠*2。中の人がAJAX関連の知識に疎いので、UIは昔ながらのWebアプリですが、今後jQuery使ってAJAX化していこうかなぁと思っています。たいしたアプリではないけど、それでも環境作成含めて4日程度で開発できちゃうのは、生産性高いなぁと思いますね。というわけで、自分なりに気がついたことを乱雑にメモってみます。

○良い点
・簡単なアプリを作るのであれば他のライブラリやOSSを使用する必要がない

フルスタックを謳うだけのことはあり、普通のサイト開発をする範囲では*3、ライブラリを外から引っ張ってくる必要はなさそうだと思いました。特にデータベース周りについて、初期開発ではほぼ何もしなくていいのが楽です。デフォルトでhibernateの自動スキーマ生成がONの状態になってるっぽいので、モデルクラスに属性追加してアプリを実行するだけでテーブルが作成されます。結局hibernateがやってくれてるだけなんですけど、特に準備せずとも最初からそういう状態にセットアップされているのは、やはり楽ですね。また、ジョブや認証など、Web系以外の機能でもとりあえず必要なものはだいたいあります。今回Bot作成なので、スケジューラどうしようと思ってCloudbeesにcronがないか探してたのですが、結局playframeworkが持っている機能でこと足りたというオチでしたw
Cloudbeesの環境作成の簡単さも考えると、とりあえずゼロからプロトタイプを作るための環境としては良いなと思いました。

・使い方が直感的で、ひとまず使い始めるまでの敷居が低い

概念が簡単です。

  1. リクエストに対して、コントローラクラスに定義したstaticメソッドが呼び出される。(メソッド名がURLに対応。)
  2. デフォルトではクラス名とメソッド名に応じたHTMLテンプレートがレンダリングされる。(当然変更可能)
  3. 画面から、コントローラクラスのメソッドを呼び出すようなイメージで、HTMLのリンクやFORMのURLを記述できる。
  4. ビューも基本的にはgroovyのスクリプトで、素のHTMLにタグやスクリプトを埋め込むような感じなので、わかりやすい。
  5. リダイレクトをする場合は、フォワード先のURLに対応するコントローラのメソッドを呼び出すだけで良い(裏でリダイレクトされる!)

シンプルなのは良いことだと思います。JSFみたいな小難しい概念がなく*4直感的なので、とにかく最初のとっつきが良いです。

・開発環境が軽い

ローカルの開発環境の話ですが、かなり軽いです。開発用にアプリケーションサーバーを立てる必要はなく、playのプロセスを起動するだけで良いので結構サクサクです。前の記事でちょろっと書きましたが、playframeworkはeclipseプロジェクトを直接実行時に参照可能 *5なので、少なくとも一人でごちゃごちゃやってる分には開発環境と実行環境の区別もないし、WTPみたいに同期コストかかったりもしないので、今回作った範囲ではほとんどストレス感じませんでした。

・cloudbeesを使っている場合は、本番環境と開発環境がシームレス

前にも書きましたが、cloudbeesを使っている場合はローカルの開発環境からcloudbeesへのデプロイは非常に簡単です。playが提供するコマンドを一発叩くだけです。データベースも、ローカルからcloudbeesに作ったDBを参照するようにしてしまえばよいのでこれも楽。本番と開発環境の差異をほぼ感じませんでした。(私が作業するときには、DBは開発と本番用で分けて作成しました。)

・エラー時の追跡がわかりやすい

playframeworkは実行系でソースコードを管理しているらしく、実行時にエラーがおきたらソースのどこでエラーになったかを画面に出してくれます。いちいちログを見なくていい。これ地味に便利です。
http://playdocja.appspot.com/documentation/1.2.2/images/usability-exception

○良くない点

・テンプレートの機能が弱い気がする

Strutsなどでは当たり前の機能がなかったりします。自分がまだ調査してないからかもしれませんが、マニュアルナナメ読みしている範囲では少なくともなかった…。


1)サーバサイドエラー時にフォームに入力項目書き戻す処理は自分で実装しないとダメ
<select>タグとかで選択したアイテムをselectedとかにするのは超面倒。また画面表示を指示するrenderというメソッドがあり、コントローラから呼びだす必要があるのですが、


public static void sayHello(String myName) {
render(myName);
}
基本的に*6テンプレートからは、renderに引き継いだ値しか参照できません。なので書き戻しのためには全部renderに突っ込む必要がありちょっと面倒。明示的なかき戻しが必要なのはいまいちですね。



2)クライアントサイドバリデーションがない。
自前でJavaScriptですか…。



ただ画面系は自分でタグを定義するための仕組みがあるらしいので、これをちょっとあたってみようかなと思います。

・全てがstaticなのはどうなの?

全てというと言い過ぎになりますが、コントローラのメソッドはstaticで定義する必要があります。そのため画面間で共通的な処理(サーバサイドバリデーションでエラーに成った場合の処理とか)のためにテンプレートメソッドパターンを適用できません。またコントローラの実装をするためにはコントローラクラスに定義されているstatic関数を呼びまくらないと機能実現できません。なので、Controllerから別のクラスに機能移譲できるかどうかも微妙なところです。というか、やってちゃんと動くかわからない不安感が一杯です。

例えばPlayではコントローラに定義したローカル変数名は、テンプレートでレンダリングする際にその変数名で参照できる仕組みがあります。実際はおそらくバイトコードエンハンスをしまくってるはずです。この環境下でstatic縛りを破って実装しようと思うと、記載されていない裏仕様を踏んでバグリそうな気がしてならないわけで…。

・言語仕様通り実装してるのに怒られる…

上記の続きですが、関数シグニチャの引数名をURLパラメータ名に対応させたり、ローカル変数名をテンプレートから参照できたりとバイトコード操作をおそらくしまくっているので、Java的に普通の実装をしてもplayの環境上でコンパイルされるときにエラーになることがたまにあります。コントローラに定義した関数の間で引き渡す構造体的なオブジェクトをコントローラのインナークラスとして定義し、属性をpublicとして定義したら怒られました。不条理だ…。まぁエラーの理由がわかりやすく報告されたのでまだ許せましたが…。

あとは細かいですが、基本的に実装変更したら即反映のHOTDeployなのですが、エンティティ関連のクラスはよくClassCastExcepton的な挙動示すので結局再起動することが多くなります。まぁこのあたりはしょうがないかと思いますが。。

といろいろ書いて見ましたが、実際のところ生産性が高いのは事実だし、良くない点については私の理解が及んでないところも多い*7と思うので誤解している点についてはご指摘頂けると嬉しいです。個人的に何か作る目的で、この環境を当分使おうかなと思います。

*1:使ったことないけど…ww

*2:http://blog.unfindable.net/archives/1697が大変役に立ちました。そもそもユーザーに認証ボタン押させるの自動化できないかとか変な方向で悩んで時間潰したなぁ…

*3:気がついた範囲ではMOMと大規模バッチが足りなそう

*4:あんなの理解できるのかなみんな…仕様書のページ数だけで引くんだけど

*5:*正確にはplayframeworkが作成したアプリケーションのフォルダをeclipseでも編集できるようにする。そのためのコマンドをplayが提供してる。

*6:別途rendorArg変数に直接突っ込んでも良いのですが。まぁ結局同じこと

*7:実はyabeまだやってません…次やります