HonoとPerl 〜 異文化を持ち込む
Honoの面白いネタがあるので書きます。
Web標準
HonoはWeb標準のAPIを使って作られています。Web標準は元々ブラウザで動くもの(JavaScriptやCSS、HTML)に対して考えられた技術仕様もしくは指針です。昨今はCloudflare Workers、Deno、BunといったJavaScriptランタイムはV8やJavaScriptCoreブラウザのエンジンを使っていて、サーバーサイドでWeb標準のAPIを動かすようになっています。Node.jsもそれに追従して使えるようになっています。例えば、HTTPのレスポンスを返したければResponseオブジェクトを使います。
return new Response('Hi')
これは多くのブラウザで動くし、上記したサーバーサイドのランタイムでも動きます。
Honoを作った動機は「Cloudflare Workers上で動くフレームワークが欲しかった」なので、初期からWeb標準のみを使って作られ、それが今でも守られています。
「僕からしてみたら」という前提ですが、Web標準のAPIはよくできてます。
- APIとして洗練されている
- (エンジンの話ですが)ブラウザでの使用実績がある
ということです。
PSGI / Plack
この話には背景があります。僕は以前「Perl」を使っていました。その最中に、Webアプリを作る際のWeb用のAPIが標準化されていなかったのが「PSGI」という仕様になりました。またそれを扱うための「Plack」というツールキットもできました。例えば以下がHello Worldのコードです。
my $app = sub {
return [200, ['Content-Type' => 'text/plain'], ["Hi\n"]];
}
僕はその当時をリアルタイムで体験していたのですね。これまではそうした標準がなかったものですから、フレームワークとWebサーバーを繋ぐのに苦労することがありました。ですので、こうした「標準」というありがたさが分かるわけです。
それがJavaScriptにすでにあって、ブラウザでの使用実績があるので動作がそのクオリティで保証されているというわけです。ですので、そのありがたさが分かります。
また、僕はその頃からPerlを使ってWebアプリを作っていたのですが、その際に独自のWebフレームワークやそれに準ずるものをよく作っていました。ですので、HonoがJavaScriptで書いた初めてのWebフレームワークだったのですが、Perlの頃の経験があるので、いわば「お手の物」だったわけです。
さらに、僕はjQueryを使っていたことがあれどサーバーサイドのNode.jsを全く触ったことがありませんでした。ですので、「JavaScript」の常識を全く持っていなかったのですね。Node.jsの代表的なフレームワークであるExpressやKoaのAPIを真似たのでそれらには近いとは言うものの、Perlっぽい要素がHonoにはあります。
Mojolicious
僕はMojolicousというPerlのフレームワークをよく使っていました。当時、Webフレームワークといえば「Ruby on Rails」だったのですが、Mojolicousはそれとは違うコンセプトでした。一番大きな差は「DB」のレイヤーを面倒見ないところです。つまりORMが付随しない。さらに、依存なしで動くところも気に入ってました。HTTPクライアントからテンプレートエンジンまで自作をしていました。
Mojoliciousの影響が強いのは$cというので分かります。つまり、Honoでは「コンテキスト」のインスタンスの変数名をcにすることを推奨、というか例でよく書きます。変数名なのでcontextでもctxでも何でもよく、KoaのWebサイトではctxを使っています。まぁ他のフレームワークではcontextかctxが多いです。ですので、cと書くのは異端でした。当初はそれが浸透していないので、ctxを使うユーザーも少なくなったです。でしたら、なぜcなのか?というとMojoliciousが$cを使ってたからです(Mojolicious公式では$cはContextのcであるとは明確には書いてないですが、その理解であってると思います)。
get '/' => sub ($c) {
$c->render(template => 'index');
};
これは僕として自然なことだったのです。ですので、知っている人からHonoは非常に「Perlっぽい」わけです。
作法を知らない
ちなみに、JavaScriptの作法を知らなかったからこそ「そうなっている」という設計がHonoにはあります。
例えば、JSONを返すにはc.json()を使います。
app.get('/', (c) => {
return c.json({ message: 'Hi' })
})
つまりContextにjsonメソッドが生えている。その場合、バンドルした時にc.json()を使ってなくてもContext内のjsonの実装が入ってしまいます。ですので、かつかつにチューニングしたい場合、それは効率が悪いので、以下のようにjsonメソッドを別のファイルに逃がすアプローチを取るかもしれません。
import { json } from 'hono/response-utils'
//...
app.get('/', (c) => {
return json({ message: 'Hi' })
})
なぜこうしなかったか?というと開発当初(恥ずかしながら)僕は「バンドル」という概念を知らなかったからです。
ですので、JavaScriptに精通してる人の中には「筋が悪い」と思われるAPIかもしれません。一方で、c.json()を使えればimport文を書かなくていいし、c.と書いただけでTypeScriptの補完が効く。それは「Easy」というか、フィーリングがいいと言うか、少なくとも僕は「開発者体験がよい」と思います。
とはいえ、やたらめったらContextに生やしてるわけでもなく、そもそもやってることが少ないので、バンドルサイズがすごい大きくなるわけじゃない。むしろ全体で比べると他のフレームワークより断然に小さい。想定しているランタイムが違うので比較しにくいですが、Expressはバンドル、ミニファイしてして「790KB」だったのが、Honoの一番小さいプリセットでは「11KB」となっています。
なんというか結果的に実装と体験のバランスが絶妙になった気がします。
タイミング
ちょうど僕がHonoを作り出した時はDenoやBunが出てきた頃で以下のタイミングがマッチしました。
- JavaScriptの「サーバーサイド」ランタイムでWeb標準のAPIを使えるようになりだした
- PerlやGoを書いてきた「サーバーサイド」が得意な自分がフレームワークを書き出した
そうすると競合が少ないかもしれません。また、もしいたとしても「サーバーサイドが得意」というアドバンテージがあるわけです。これがHonoが今の時代においてイニシアチブを取れた要因の一つかもしれません。
RegExpRouter
もうひとつPerlっぽさが色濃く分かるのは「RegExpRouter」です。これはHonoに導入された2番目のHTTPルーターで、開発初期にusualomaさんによって導入されました。
これが非常にPerlっぽい。
よくあるHTTPルーター、例えば、Expressで使っていたpath-to-regexp等では、登録されたルーティングのパスがあるとして、リクエストのパスがきたらそれを頭からマッチするかどうか?判断してく。その際に毎回正規表現が走るので、登録されたルート分正規表現が走るのです。

RegExpRouterのすごいところは複数のパス情報を一つの大きな正規表現にして、リクエストに対して一発でマッチさせる(現在の実装はもうちょっとだけ複雑な動きをします)。

これも分かる人には分かります。かなりPerlっぽいのです。というのもPerlにはいくつかの正規表現を一つの正規表現にアセンブルするRegexp::Assembleという有名なライブラリがあるのです。
use Regexp::Assemble;
my $ra = Regexp::Assemble->new;
$ra->add( 'ab+c' );
$ra->add( 'ab+-' );
$ra->add( 'a\w\d+' );
$ra->add( 'a\d+' );
print $ra->re; # prints a(?:\w?\d+|b+[-c])
また、そのアイデアを元にしたRooter::BoomというHTTPルーターもあります。こうしたものに強くインスパイアされている。
これには理由があって、RegExpRouterの作者であるusualomaさんも実はPerlを書くからです。これはすごく面白い現象ですね。つまりHonoはAPIも実装も「Perlっぽい」わけです。
異文化を持ち込む
簡単に行ってしまえば、JavaScriptにPerlの概念と実装、いわば「文化」を持ち込んだわけです。ですので、HonoはPerlっぽく、それゆえ伝統的なバックエンドのフィーリングで使えるし、ノスタルジーすら感じることもあるでしょう。
それもあってか、Honoのユーザーは新しい「界隈」と呼べるかもしれない。先日10月に開催したHono Conferenceでのアンケートで、あなたは「フロントエンドエンジニアですか?バックエンドエンジニアですか?」の答えが同数でした。つまりフロントエンド、バックエンドから平等に使われている。これは非常に面白い。まさに通りで、Honoをやっていると新しくフロントエンドサイドの友達が増える一方、昔からのPerl界隈の知り合いも使っています。
フロントエンドの技術を使って、Perlの経験を活かす。だからこそHonoは古くて新しいのかもしれません。
Discussion