Day 21: Lack
これは fukamachi products advent calendar 2016 の21日目の記事です。
今日はLackについて話します。Rackではないです。
Clackの高速化
サムライトに入社してWooによるサーバーの高速化を主な課題と取り組んでいましたが、アプリケーション全体で見ればその基盤部分のClackの高速化も重要でした。Wooは十分に高速だけど、Clackに載ることで大きくパフォーマンスが下がるなら残念なことです。
まあ正直、当時でも十分な速度は出ていたんですけどね。ずっと高速化ばっかりやってたので頭がもう高速化脳になっていて、何でも高速でなければ気がすまなくなっていたんでしょう。
疎結合性を確保しつつなのでWooのようにinline化や型宣言などの高速化のテクニックは使えませんが、それでもClackに速度面で改善の余地はありました。
ClackではComponentもMiddlewareも全部CLOSクラスになっており、Clack.Builderでビルドしたとしても実行時にメソッドディスパッチが挟みます。これをフラットなクロージャーにするだけで少しは高速化できるのではないか、と考えました。
実はこれには違う目論見もありました。
Clackを使うメリットは疎結合性でした。けれどClackのコアは開発の過程でだんだん大きくなり、依存ライブラリもまた多くなりました。単にclackup
をしたいだけで、セッションを使わないアプリケーションだとしてもClack.Middleware.Sessionで使われているIroncladまでロードされてしまいます。
こういった目的意識を持って、高速に、もっと疎結合に、そういう意図を持って作り始めたのが「Lack」です。
LackはClackから分離したもの
LackはClackからアプリケーション構築フレームワーク部分を抜き出したライブラリです。ミドルウェアやLack.Builderなどがここに入ります。
Clackにはハンドラーが残り、Webサーバーの抽象化ライブラリの役割だけを与えました。
Common Lisperの多くはWeb開発に疎く、最近のWebアプリケーション構築にキャッチアップできているわけではありません。そういう中でClackは説明が難しかったですし、LackとClackの2つの目的別のライブラリに分離したほうがわかりやすいかなという意図もありました。
Lackの疎結合
Lackが提供する疎結合性は完全なものです。Middlewareはもはや単なるクロージャーを返すクロージャーであり、Clack.Middlewareを継承する必要がありません。これはLackのミドルウェアがLackにすら依存しなくてもよくなったという意味でもあります。
意味わかりますか。LackのミドルウェアがLackに依存する必要がないのです。単に呼び出すとappをラップしたapp (関数) を返すだけなんです。そのルールに従っていればLack.Builderに渡すことができます。
Lackというのはアプリケーションを構成するルールのようなものです。つまりは仕組みは単なる関数群ですし、自前でLackのような新たな疎結合フレームワークを構築することもできます。
ちなみにClackについても依存の形式は同じです。たとえば、WooがClackに依存していないというと驚かれることがあります。ningleやCavemanもClackに依存していません。ライブラリごとに必要な部分だけをロードできることでロード時間が短くなりますし、柔軟に部品を入れ替えてアプリケーションを構築できるようになります。
速度
リリース当時に取ったベンチマークによると、結果的にLackはClackの1.1倍程度の高速化に成功しました。
Hunchentootより1.25倍の高速化とも書いてあります。勘がいい人は不思議に思うかもしれません。ClackでもLackでも裏側はHunchentootなはずなのに、なぜ素のHunchentootより速いのか。
理由はHunchentootのセッションミドルウェアです。セッション処理が遅すぎるためHunchentootはClackと比較しても遅くなっています。
おわりに
LackはGitHubで公開されており、Starは30ついています。
明日のアドベントカレンダーは22日目のcl-coverallsについてです。お楽しみに。