ikeike443のブログ

ソフトウェアビジネスに関心がある系のブログ

なぜ Play は Servlet を使っていないのか(Why there is no servlets in Play 翻訳)

まだ正月休みなのです。暇なので訳してみました。


この記事は 1年半以上前に Play の生みの親である Guillaume Bort がブログに書いたものです。
(2012/8/19追記: リンク切れしていたためリンクを貼り直しました)

なぜ Playframework では Servlet が一切使われていないのかについて、簡潔に書いています。

丸山先生が Play に注目し始めた今、Play2.0 のリリースが間近に迫った今、あらためて読むと面白いかも知れません。



なぜ Play は Servlet を使っていないのか


Servlet API に準拠せずに Java web フレームワークを作ることはかなり変に思えるかも知れない。大抵の人はなぜこんな普通じゃない選択をしたのかを聞いてくる。気に入ってくれる人も何人かいるが、大半は毛嫌いする。正直に言うと、 Play フレームワークの一番最初のバージョンは Servlet を使い、Servlet コンテナの上で稼働するようになっていた。しかし、この要件を外すに至ったのには幾つもの理由がある。説明してみよう。


Play フレームワークの重要な特徴は2つある(他にも多くの特徴がある中でも): 完全なステートレスアーキテクチャモデルの上に構築されていること、魔法のように自動的にコードの変更を反映すること。実際、この2つの特徴は密接に重なり合っている。


コードのホットスワップを可能にするには、アプリケーションをステートレスに作ることが欠かせない。あなたは疑問に思ったことはないだろうか。なぜ PHP ではホットスワップ出来るのに、JEE だと出来ないのか、と(ここで言っているのは、バックグラウンドで war をデプロイし直すのではなく、本当にアプリケーションコードをホットスワップするという意味だ)。PHP に出来るのは PHP は徹頭徹尾ステートレスだからだ。PHP の場合、2つの連続したリクエストの間で、都度まっさらな新しいプロセスが起動する(確かに今は FastCGI を使っていくらかの最適化を図ることがあるが、根本的なモデルを変更するわけではない)。アプリケーションがステートレスでなかった場合、コードスワップの後にメモリ上の状態を再構築することなんてできない。きちんと動くケースもあるだろうが、重要な変更があった場合はまず動かないだろう。


Play をステートレスな web フレームワークとして作ることにした理由は、コードのホットスワップを実現したかったからだけではない。この話はこのポストの論点ではないが、基本的に、WEB 自身がステートレスアーキテクチャを採用しているのがその理由だ。そして WEB がステートレスアーキテクチャを採用していることにも幾つものとてもいい理由がある。


Servlet API を使ってステートレスなアプリケーションを作ることは可能だ。しかし、HttpSession や servlet の forward の仕組みなどを使わないようにしなければならない。Play フレームワークの一番最初のバージョンではそんな風にやっていた。


しかし正味の話、皆 servlet API が好きだから使っているわけではない。Servlet API がこれまで考案された HTTP API の中でもダメな部類であるという事実には皆同意している。だが、servlet filter とかその他色々な servlet に依存したコンポーネントを再利用したいがためにこの API を使っているのだ。


これらのコンポーネントは、大抵の場合設計がまずいという問題を抱えていることが多い。開発者の知らないところで、HTTP リクエストのオブジェクトとレスポンスのオブジェクトをごっちゃにしてセッションに格納したりする。だからこのようなコンポーネントをインストールすると、Play の初期処理で行っているステートレスな取り決めを破壊したり、クラスのリロードやキャストに多くの問題を引き起こしたりする結果になり得る。これは Play で書かれたアプリケーションコードをリロード出来るようにするために、コードを Play のカスタムクラスローダーの中で動かしている理由でもある。そして Servlet コンポーネントServlet コンテナのクラスローダーの中で動いている必要がある。これらのコンポーネントを協調して動かす必要があるのだろうか? もちろんあなたにはあるだろう。そしてそれは悪夢となる。


実際のところ、Servlet ベースのコンポーネントには2種類ある。私がこの問題に直面したのは、Play 用の captcha ライブラリを探していた時だった。2種類あるうちの一方に属するライブラリ群の作りは、2つの層に綺麗に分かれていた。1つは captcha を生成するロジックで、もう1つは Servlet API との結合だった。もう一方に属するライブラリ群はぐちゃぐちゃにコードが折り重なっていて、Servlet API なしには利用することが出来ない作りだった。よく出来ている方のライブラリを Play にインストールした場合、Play のユーザーはそれを使って本来の面白い部分を作ることに集中することが出来るが、ダメな方のライブラリをインストール出来てしまった場合、ユーザーのアプリケーションは壊れてしまう可能性が高いだろう。


最後に、我々が Servlet API を金輪際使わないことにしたのにはもう一つ理由がある。Servlet コンテナはオールドファッションな ”1リクエストにつき1スレッド” モデルを採用している。幾つかのアプリケーションにとってはそれでも問題ないだろう。だが、Ajax とロングポーリング呼出しが必須となった今日において、これでは不十分だ。


根本的な問題は、 JEE サーバと HTTP 層を結ぶには Servlet APIを使う以外に選択肢がないことだと思う。おそらく、 java のエコシステムには Rack の様なものが必要なのではないだろうか。つまり、HTTP を扱う本当に低レベルでポータブルな API が必要だと思う。少々欠陥のあるアーキテクチャ原則に基づいて構築された、半ばでたらめな HTTP API ではなく。