TypesafeのPlayチームがWebフレームワーク“Damiya”のバージョン2.4をリリースした。前回のメジャーリリースPlay 2.3からは,およそ1年ぶりになる。今回のリリースは,PlayのコントリビュータであったKate von Roeder氏を追悼して,Damiyaと命名されている。
2.3から依存性注入(DI)を採用して開始されたリファクタリングによるモジュール性の向上は,今回のリリースでも継続されている。その方針によって,Anormデータアクセス層やEbeanといったモジュールが別プロジェクトとして切り出された。また今回のPlayではJava 8が必須となり,ラムダやデフォルトメソッドがJava-APIで使用されている。
依存性注入はこれまでのバージョンでもサポートされていたが,今回からは初期状態で使用可能になるとともに,利用が推奨されるようになった – グローバルステートを提供ないし利用するAPIは,次のバージョンで廃止される予定だ。ドキュメント上の既定値はGoogleのGuiceだが,JSR 330実装を使用することもできる。一般的にコンパイル時の依存性注入と検証を好むScalaプログラマのために,こちらもサポートを継続する。長期的な目標はグローバルなアプリケーション状態を完全に取り除くことだが,Play 2.4ではまだ,現在実行中のアプリケーションインスタンスに対する参照が残っている。このリファクタリングによる最も明確なメリットは,アプリケーションのテストが容易になることだ。さらに,ステートレスなフレームワーク(サーバでセッション状態を保持しないことを意味する)という,Playの目標との整合性も向上する。
Play 2のリリース当初から常に重視されているのが,型安全性(Type Safety)だ。PlayはScalaで開発されている。ビューのテンプレートをコンパイルして,アプリケーション内部のルーティングをチェックすることによって,アプリケーション内のデッドリンク発生を防止する。しかし残念ながら,プロジェクトの循環依存を導入せずにモジュールの相互リンクを実現する場合には,これが原因となってアプリケーションのモジュール化が困難になっていた。今回導入されたAggregating Reverse Routers機能では,すべてのモジュールを共通依存関係をルータに集約することによって,これを可能にしている。
Play 2.4では,先日リリースされたSlick 3をベースとするPlay-Slickモジュールも新たに導入され,非同期Webアプリケーションの記述がさらに簡単になった。
InfoQは,Playの技術リーダであるJames Roper氏に,Play 2.4の変化点や今後の計画について聞くことができた。
InfoQ: Java 7のサポートが終了しましたが,ロードマップによると,このステップは実際には3.0リリースで実施する計画だったようです。APIでJava 8の機能を利用したからなのでしょうか,あるいは他に理由があるのですか?
これには面白い経緯があるのです。元々の計画では,Play 2.4をAkka2.4とともにリリースする予定でした。後になってAkka 2.4がJava 8しかサポートしないことが分かり,私たちもPlay 2.4では,Java 6とJava 7のサポートをドロップせざるを得なくなったのです。そこでこの機会を利用して,デフォルトメソッドなどJava 8の新機能を利用することにしました。さらにバインディング/バリデーションライブラリでも,Java 8の時間APIを最初からサポートすることにしました。Play 2.4のリリースが近づいた頃,Akka 2.4が数ヶ月遅れることが明らかになったのですが,私たちはそれを待たないことに決めました。ですが,私としては,Java 8のみをサポートするのがベストだと思います。デフォルトメソッドを使うことで,よりよいAPIをJavaユーザに提供できますし,リアクティブあるいは関数型プログラムスタイルをもっと完全な形で取り入れることができます。ラムダを使いたいユーザもたくさんいるはずです。
Java 7のサポートが5月で終了していることも忘れてはなりません。
InfoQ: Akka HTTPはNettyに代わる,新しい試験的なバックエンドですね。 Nettyと比較した時,Akkaをバックエンドにするメリットは何でしょう?
現在のPlay 2.4では,さほど多くはありませんが,将来的な計画では次のようなものを挙げています。
- HTTPモデリングの向上。Play 3では,Akka HTTPによるHTTPヘッダのアプローチをベースとした開発を予定しています。単純な文字列そのものではなく,完全に解析され,強く型付けされた,検証済のヘッダを利用します。これにはいくつかのメリットがあります。ユーザエクスペリエンスの型安全性が向上しますし,リクエスト間で変化しないヘッダを再度解析する必要がなくなるため,パフォーマンスも改善されます。
- metal IO処理との親和性向上。Play 3では,iterateeをリアクティブストリーム(というよりもAkkaストリーム)で置き換える予定です。Akka HTTP自体がAkkaストリーム上に構築されているので,アプリケーションと通信との間にあるレイヤの数を減らすことになり,パフォーマンスの向上が期待できます。
- その他,分散に関する機能。これは試験レベルですが,アクタシステムをクラスタに分散するのはとても簡単です。さまざまなリクエストをさまざまなノードに透過的にルートできる機能のようなものを,Playで提供できるのではないかと思っています。
InfoQ: 2.4での大きな変更点として,グローバルステートの完全な廃止に向けての,依存性注入の全面的なサポートがありますね。それが必要であることは議論を待ちませんが,では,次のステップは何ですか?
次のメジャーリリース,すなわちPlay 3では,残りの部分を削除します。 Play 3の前に準メジャーリリースのPlay 2.5があるかも知れませんが,互換性を損なうような大きな変更は行わない予定です。グローバルステートに関しては前進はないと思いますが,大きな変更のひとつとして,グローバルステートに依存するAPIで代替手段のあるものについては,非推奨の警告を追加することになるでしょう。
それよりも大きな疑問は,おそらくは,グローバルステートの何が残るのかという事でしょう。主なものは2つです。ひとつには要求ヘッダの解析が,特にセッションとフラッシュのクッキーに関して,グローバルステートに依存しています。これは
RequestHeader
オブジェクト自体が,データに遅延アクセスされる場合に使用します。この件は先程述べたように,これらを前もって解析しておくことで解決できます。もうひとつはアクションビルダで,デフォルトのボディパーザに依存しています。これは要求のボディの最大長やエラーハンドラのように,コンフィギュレーションに依存します。こちらは比較的大きな変更になると思います。おそらくは単純に,ActionBuilderにインジェクションすればよいと思いますので,アクションに対する影響は主として,Action {req=>...}
からaction {req=>...}
に変更して,アクションビルダをオブジェクトから注入フィールドに置き換える,というものになるでしょう。
InfoQ: Scala開発者は型安全性に力を入れているので,依存性注入という選択をしたことは,私にとっては意外でした。インジェクションの状況としては,実行時とコンパイル時,どちらがよいと思いますか?
確かに意外ですよね! Javaコミュニティは多かれ少なかれ,依存性注入というアプローチには同意しています(どのフレームワークを使うのか,という議論の方が多い)が,Scalaコミュニティはまだ,どのアプローチがベストかという議論を続けています。ですから私たちは自説に固執せず,PlayのDIサポートに関しても選択肢を大きく開いておきました。
コンパイル時DIに特別な思い入れがないのであれば,実行時DIの方をお勧めします。問題なく動作しますし,それを使えば間違いなく成功を収められるでしょう。あなたがScala好きでコンパイル時DIアプローチを望むのなら,それで試してみてください - そして大事なのが,あなたの経験をブログ記事で私たちに教えてほしいのです。個人的には,Playについてはmacwireに多くを期待しているのですが,PlayアプリケーションでScala開発者が使うアプローチとして,何がベストで何がもっともポピュラーかを決めるのは時期尚早だと思います。
InfoQ: Slick 2を使用して,依存性注入は利用していないPlay2.3アプリケーションが仮にあるとしましょう。これをどのようにアップグレードすればよいのでしょう?
2.4にアップグレードしたら,まず最低限の修正を行ってください。次に,一度にひとつずつ,DIにスイッチします。こうすることによって,サービスに取り出すべき共通機能を見つけることができると思います。ただし,一度にひとつのサービスのみとして,次のサービスを始める前に動作を確認してください。一度に全部やってしまいたいと思うでしょう - 私の経験から,アプリの規模が大きい場合は特に,大規模な変更へと膨らんでしまう可能性が非常に高く,諦めてしまうことになります。今日グローバルステートを使って動作しているのですから,明日もグローバルステートを使って動作するはずです。一度にすべてのグローバルステートを取り除く必要はありません。
Slick 3へのアップグレードについては – まずは
Await.result
を実行するユーティリティメソッドを作ることから始めるとよいでしょう。Slickによって返される機能をブロックするために,それを使うのです。そのコードが動作したら,ひとつひとつ,コードを非同期に書き換えます。なぜユーティリティメソッドかというと,誤ってコードをブロッキングのまま残したくないからです。すべて完了したら,ユーティリティメソッドを削除してください。直し忘れたコードがあれば,コンパイルできなくなります。
InfoQ: インタビューへのご協力,ありがとうございました!
変更部分の詳細については,Play 2.4ハイライトのページを参照してほしい。アプリケーションをアップグレードする場合は,マイグレーションガイドを見ることも忘れてはならない。その結果を,以下のコメントで教えてほしい。