今回話を伺ったエキスパート
フォローしよう!
2022年7月初旬に登場した高速JavaScriptライブラリ「Bun」の実力をエキスパートの古川陽介氏が語るインタビューの後編をお届けします。後編ではBunが構成要素として選択した技術についての深堀り、さらにBunそしてサーバサイドJavaScript界隈の未来についても展望していただきました。インタビュー前編もあわせてお読みください。
Zig、パッケージ管理、エンジン - Bunの技術選択の理由
白石: いま出てきたZigという言語ですが(前編参照)、私も実は今回始めて聞いたレベルに近いんですが、えっとNode.jsはたしかC++で書かれていていますよね。(マイクロベンチの結果からいうと)ZigそのものはC++より速いという話になるんでしょうか。
古川: 正直言うとわかってないです。ただ1点、Zigの特徴としていうと、C言語から呼び出したとき、とくにインタフェースから呼び出したときの差がなく、ほとんど直接Cで呼び出したのと変わらないぐらい高速に呼び出せる、ZigはそういうふうにCのネイティブコードとの互換性をかなり強くもっている言語と聞いています。
Node.jsがC++を使っている理由は単純にV8がC++だからなんですが、Bunはそういうのを全部Zigでラップしていて、そこから使うということをしているから、メモリ効率も良いし、C言語のコードを直接呼び出すみたいなことをやったときでもかなり速くなる設計になっているんじゃないかなと思います。ただ、(Zigの言語仕様の)細かいところまではすみません、わかっていないです。
白石: わかりました、ありがとうございます。あと互換性というところでいうと、パッケージ管理、たとえばnpmといったところが非常に重要だと思うんですが、Bunのパッケージ管理についてはどう見ていますか。
古川: これ、さっき言った(Bunの)戦略でいうところの「Node.jsをまるっと吸収しようとしている」とも関連していて。Node.jsのパッケージ管理のやり方なんですが、Node.jsは内部的にはNodeモジュール(node_modules)と呼ばれているフォルダの下に自分たちのフォルダを作って、そのフォルダの下にpackage.jsonと呼ばれるエントリポイントがあって…みたいなモジュール解決の仕方をするんですけど、(Bunは)そのモジュール解決の仕方をそのまま採用しています。だからNode.jsのパッケージをそのまま使えるようにしているところは側面としてあります。要はCommonJSと呼ばれているrequireやimport/exporrtでモジュールを解決できる仕組み、プラス、それがnpmで呼び出したときに解決するアルゴリズム、それも全部、Bunは同じものを使っています。
ここはDenoとの違いがやっぱり明確になります。DenoはどちらかというとES Modulesと呼ばれている新しいモジュール解決の仕組みを重視しています。Node.js互換モードは提供されていて、それが Node.jsのモジュール解決の仕組みと共通化できるようになっているのですが、後から追加されたモードです。このあたり、だいぶBun-Deno-Node.jsの戦略の違いが大きく出てきますね。Bunはどちらかというと開発初期段階からNode.jsに寄っている印象です。
白石: なるほど、理解しました。じゃあBunはなんでV8じゃなくてJavaScriptCoreを採用したんだと思いますか? 推測でもかまわないのでぜひ聞きたいです。
古川: ここは自分で言うのも何なんですけど、わりとおもしろい解説ができるかと思っていて。V8は車のギアに例えると、2速、ローギアとハイギアしかないみたいに考えてもらっていいかと。要はローギアはとにかく最初はぐんぐんと速度を出していけるけど最高速度は出ない。で、ハイギアはめちゃくちゃ速くて、最高速度は出るけど、そのかわり減速/加速には弱いという特徴があります。この例えでいうとV8は2速、つまりローギアかハイギアしかない。一方でJavaScriptCoreは1から4まで4段階のギアがある。これ、ギアがたくさんあればあるほど良いという話ではなくて、ギアがたくさんあるということは、どんな路面環境であっても対応しやすいということです。あと、エンジンの戦略の差でいうなら、どういうふうにスタートしたいのか - たとえば最初ぐぐっと加速して徐々に速くしていきたいのか、それともある程度加速したらもういきなり最高速にしたいのか - JavaScriptCoreはどちらかというと徐々に徐々に加速していくという特徴をもったエンジンなので4速あるんです。そのことは、もしかしたらさっき僕が最初に言っていた「エッジでも動かしたい、ローカルでも動かしたい、サーバでも動かしたい」といういろんな環境に対応させるには、実はこれ(JavaScriptCore)がいちばん良いという実験というか戦略なのかもしれないですね。
V8はどちらかというと、もう速いか遅いか - 最高速が速くて加速が遅いか、加速が速くて最高速が遅いか、この2つのギアしかないので、それを使い分けるしかできないんですが、(JavaScriptCoreは)もうちょっと細かくレンジを取れるので、Bunは「だから俺たちのほうが優れているぜ!」と言いたいのかな、という気がします。
正確には最近V8は3段階のギアを使うようになっています。 Ignition、Sparkplug、Turbofan の3段階になりました。JSCは4段階 - LLInt、BaseLine JIT、DFG JIT、 FTL JITです。ギアの例えで言うと、V8の3速目のTurbofanがJSCの4速目のFTL JITと同じ位置づけになります。
白石: なるほど、わかりました。それって起動オプションみたいなものでその”ギア”を切り替えられるような感じなんでしょうか?
古川: V8だとたとえば1速しかなくて2速めは使わないというモード(jitless mode)はあります。そのかわりめちゃくちゃ速く起動するけど、最高速に到達するまでに遅くなるというのがある。サーバサイドで使う場合は基本的に立ち上げっぱなしにするので、最高速のほうが重要視されるケースは多いです。ただよくあるサーバサイドの使われ方がずっと立ち上げっぱなしにするというモデルだからで、たとえばTypeScriptをビルドしたいとかコンパイルしたいとか、クライアントサイドで動かしたい場合はちょっと違ってきて、最初に起動をとにかく速くしてほしいとなります。
こういうところを考えるとケースバイケースなんですね。サーバサイドでHTTPサーバとして振る舞うなら最高速をずっと維持してほしいけど、クライアントでTypeScriptコンパイルしたりいろんなことをバンドルしたりしたいんだったら、1速でとりあえず始めて、徐々に徐々に速くなってほしいというニーズはあるかと。このへんが戦略としてはおもしろいところなんですが。ただ、どっちが良いかといわれると、いまはわからないですね。あと、それを最初から4速で出発するモードがあるかどうかはわからないですね。たぶんないと思います。
白石: それっていうのは、ギアという例えじゃなくていうとインタプリタのモードだったり、Just-in-Timeだったりとか、そういう感じなんですかね。
古川: そうですね、おっしゃるとおりです。
Bunが選んだJavaScriptCoreは1から4まで4段階のギアがある。ギアがたくさんあるということは、どんな路面環境であっても対応しやすいということ
Bunのこれから、JSランタイムのこれから
白石: ではそろそろ最後のトピックで、Bunの今後について、そしてJSランタイム界隈はどうなるかについて、古川さん個人のご意見でかまわないので、ぜひお聞かせいただければと思います。
古川: はい。まずBunに関しては、今、ものすごく勢いがついている状態なので、ここからいろんなフレームワークを動かすという段階に入っていくかと。今はNext.jsを動かすことがひとつのキーポイントになっていますね。あとNuxt.jsやSvelteKitとか、その手のよく使われているフレームワークも全部Bun上で動かせるようにするぜ!という話もあるので、その辺はやっぱり「Node.js周りを全部吸収して大きくしていく」という戦略に沿っていくのかなと。
あとNode.js APIとの互換性については、さっき言ったとおり、まだまだだったところをもうちょっと良くしていこうという話が出てくるようになるかと。速さのところに関して言えば、まだだいぶ懐疑的な結果でもあるので、そこの部分が本当なのみたいなところとかを踏まえておきたい。
実際、パフォーマンスの勝負って、エンジニアはかなり気になるところだと思うので、ここを懐疑的ではなく、ちゃんとした結果として出せるようになると、ちょっと変わってくるだろうなって気はしています。でもそれはたぶん、DenoやNode.jsにとっても良い影響を与えるはずです。パフォーマンスが速いというだけで「そっちを使いたい!」という人は多いので、なるべく「そっちに行かせたくない!」という人たちはどうにかして速くしたいと努力するはずなので。そうすると界隈がどんどん進化していくので、それはすごく良いことだと思います。ここまでがBunの今後についての展望です。
で、今後のJSランタイム界隈の話については、もうひとつ別の角度からのニュースがあって。最近、Cloudflare Workersのメインコミッターをやっているジェームス(James M Snell 氏)さんという方と、あとDenoの中の人たち、Node,jsの中にいた人たちがいろいろ持ち寄ってWinterCGという仕様化団体(コミュニティグループ)を作ったんですよ。この人たちが何をしたいかというと、今までJavaScriptのランタイムって基本的にはブラウザをベースにする人たち、たとえばWHATWGとか、WICGとか、W3Cとかそういう団体全部、ブラウザのための団体だと思うんですけど、そこでJavaScriptのAPIを決めているんですが、そうではなくてサーバサイドのためのJavaScriptのAPIを決める団体 ができたんです。これがWinterCGです。
この団体の人たちが「いまJavaScriptのランタイムっていうのはこれがあればいったん、サーバサイドとして動くよね」というスモールセットのAPIを定義して、それを規定した上で「これらをちゃんと動かしていきましょう、コミュニティとして仕様を育てていきましょう」という話になっています。そうなると相互運用で動かせられるんですよ、Node.js、Deno、Bun、この3つだけじゃなくて、Cloudflare Workersや別のCDN業者が作っているなにか新しいWorkerとか、そういういろんなWorkerなどがランタイム環境間でポータブルに動かせるようになると、そうなるとあとはパフォーマンスだったりセキュリティだったり、いろいろな側面でそれに従って書いておけば、いろんな選択肢が増える - そこはすごく期待しています。
やっぱりどうしてもサーバサイドのJavaScriptって、今までもこれからもなんというか”お客様感”があったと思うんですよ。なんというか、全然こう、メインストリームにない感じがあったかなと。ブラウザのAPIがメイン、サービスワーカーとかそういうのがメインで、”サーバサイドのAPIなんておまけでしょ”感があったと思うんです。なので、できたらそこからちょっと良い意味の圧力をかけられるような、「WinterCGでこういうAPIが提供されているから、ブラウザ側もこういうのを考えてもらえませんか」みたいに、これまでとは逆向きの方向に仕様がうまく回るようになるといいな、と。
白石: なるほど、相互運用性が高まって、JS界隈ももっと盛り上がっていって…という流れを期待したいですね。
古川: そうです。本当にこの界隈がもっと盛り上がっていってほしいですね。
★Bunは現在すごく勢いがある状態、互換性やパフォーマンスが改善すればNode.jsやDenoにも良い影響があるはず
★サーバサイドJavaScript APIのための新コミュニティグループ「WinterCG」に期待!