感想: Node.js: The Documentary | An origin story

llll
·

Ryan Dahl 氏をはじめとする初期の開発者へのインタビューを中心に Node.js の誕生と発展を取り上げたドキュメンタリーを観たので、要約と感想と自分のメモを書き残しておく。このシリーズは ReactRuby on Rails など他の回も面白かったので、まだ視聴していない方はお勧め。

Ryan は博士課程で数学の研究をしていたが未来の理論物理学者ではなく今を生きる人間に使われるものを作りたかったので大学院をドロップアウトした。

南米を旅しながら Craigslist でプログラミングの仕事をする過程で Ruby on Rails を使い始め、Web アプリのパフォーマンスを高めるにはより下位のレベル(例えば Nginx など)に取り組む必要があることに気がついた。

その後、交換留学でアメリカに来ていたガールフレンドの帰国に付き合ってドイツのケルンに移住した。2008年に Google が V8 を発表したこともあって、Ryan はこの新しい JavaScript runtime を使って高性能なサーバーを作れないか考えていた。

Node.js は 非同期 I/O のみを提供することで non-blocking なサーバーを簡単に構築できるプラットフォームとして開発された。データベースの読み書きや外部 API の呼び出しなど時間のかかる処理をしている間に処理をブロックしていると他のリクエストを処理できない。Node.js は非同期 I/O を処理するためのイベントループを抽象化するので、利用者はその詳細を知らなくてもよい。

もともと Ryan は実装にあたり Python や Lua, Haskell などを試していたが、最終的には JavaScript を使うことに決定した。背景としては直感的に分かりやすい高級言語で、数多くの開発者がおり、V8 のような良い runtime があり、既存の I/O パラダイムが無い(Ruby や Python や Perl では同期的な I/O を使って書かれたコードがたくさんある)という事情があったらしい。その後 JSConf EU で発表するまで9ヶ月ほどフルタイムで Node.js の開発を続けた。

Node.js 以前は JavaScript はクライアントの実装に使われる言語という認識が一般的だった。しかし、Web アプリケーションを開発するにあたりサーバの PHP や Ruby とクライアントの JavaScript の間を行ったり来たりするコンテキストスイッチが面倒で「サーバー側も JavaScript で書けるのではないか?」と考えていた人は Ryan 以外にもいた(ServerJS, のちに CommonJS と呼ばれるプロジェクト等)。そのため、 JavaScript でサーバを書けることを示した Node.js には注目が集まった。

Node.js のユーザーが増えると、さまざまな人が自分でライブラリを書いて公開するようになった。この頃からあり今も使われている有名なのは Express や Socket.io など...(ちなみに Socket.io の作者は Vercel の創業者らしい)

しかし、さまざまなライブラリを GitHub 等からダウンロードして特定のディレクトリに配置し make を実行して云々...という作業をライブラリを入れるたびに実行するのは大変だった。

npm の作者 Isaac Schlueter は当時勤務していた Yahoo の内製パッケージマネージャ Yinst からアイデアを拝借して npm を提案、実装した。npm は Node.js から呼び出される小さな bash script として始まったそうだ。

Ryan は2009年にベルリンで開催された JSConf EU で Node.js を発表した。

この発表には大きな反響があり、Node.js を事業で使いたい企業がいくつか現れた。その中で Joyent というホスティングプロバイダに資金を提供してもらえることになり Ryan もその会社で働くようになったが、次第に Node.js の人気が高まり Joyent の本業ではなく Node.js に集中するようになった。

当時の Node.js は各バージョンで破壊的変更を続けており、いつ stable なリリースに到達するかは不明確だった。ユーザーは増え続けていたが Ryan 本人は至る所で誤りを犯したと考えており、成熟していない今なら直せると思って反発を気にせずカジュアルに壊していたらしい。

Ryan が Joyent で働き始めて1年後、同社は Ryan から Node.js を「購入」した。これには Node.js の Web サイトと商標、プロジェクトの管理者としての地位が含まれていたようだ。

Node.js 自体は MIT ライセンスで提供される OSS なので、開発者にとっては contributor agreement の相手が変わるだけで大きな変更はない...はずだった。当時の主要な開発者も「OSS だし Joyent が evil になったら fork すればいいや」くらいの感覚を持っていた。

なお、その後いろいろ(後述)あって2022年に Node.js の商標は OpenJS Foundation (旧 Node.js Foundation)に移行された。

Node.js は当初 macOS と Linux でしか動かなかった。macOS / Linux は Windows とは非同期 I/O を実現する方法が異なっていた。Node.js 0.4 以前は libev というライブラリを使っていたがこれには幾つかの問題があり、何より Windows で動かなかった。一方で、Windows で Node.js を動かしたいという需要はあった。

macOS / Linux で動いている既存のコードをそのままに Windows だけ異なる実装にすることもできたが、Ryan は複雑さを嫌い libev を模したライブラリで I/O を抽象化することを提案した。そして、クロスプラットフォームな非同期 I/O を実現するためのライブラリとして libuv が誕生した。

Ryan は「Node.js を建物に喩えると、フォークリフトで基礎ごと持ち上げて50m移動させたあと着地させるようなもの」と表現している。Windows でも Node.js が使えるようになったことで Windows のバックエンドで .NET より Node.js が注目され、さらにユーザーが増えた。

この後 Ryan は燃え尽きて Node.js から離れ、Isaac が責任者の立場を引き継ぐことになった。

しかしすぐに Isaac も自分が作った npm を何とかするため npm, Inc を設立し Node.js を離れ、 TJ Fontaine が引き継ぐことになる(その後、Isaac は npm の買収後に GitHub で働き、最近 vlt technologies という会社に参画した)。

この間、Joyent 社自体もいろいろあって多くの人が離れた。Node.js のリリースは次第に遅くなり、何を含めるかについても多くの衝突があった。

背景としては、Joyent が自社のホスティングプラットフォームを Node.js で構築していたことがあるようだ。V8 のアップグレードやインターフェイスの変更等で大きな破壊的変更があるとそのシステムを破壊するかもしれないので、仮にコミュニティがそれを必要としていたとしても企業の立場からはアップデートに慎重になることは理解できる。

本当にそういう理由だったかは分からないが、実際に Joyent は次第にコミュニティの貢献を受け入れることに消極的になっていった。多くの開発者は ES6 の構文など新しい機能を使えるようになる V8 のアップグレードを望んでいたが、Joyent が管理していた時代の Node.js では結局行われなかった。

やがてコミュニティは Joyent に失望するようになった。例えば JSON の作者である Douglas Crockford は Node.js に bet するが Joyent には bet しないと宣言した。

Joyent に代わって Node.js にコミュニティが望む改善を加えるために、Mikeal Rogers を中心に TJ 以外のプロジェクトのコアコントリビュータが集まって node-forward というプライベートリポジトリが作られた(TJ の不参加が彼自身の意思なのか会社の意思だったのかは不明)。

Mikeal の意図としては、当時 Joyent に腹を立てている開発者がたくさんおり互いのコミュニケーションも減っていて複数の fork が発生する可能性があったので、fork するとしても1つにまとめておきたいという意図があったらしい。また、node-forward はコミュニティから Node のガバナンスについて Joyent と合意するための提案を作る場所でもあったようだ。Joyent 側はこの動きを無視して以下のブログを公開した。

node-forward の経緯は以下のブログにまとまっている。

同じ頃 Joyent の CEO が交代し、新 CEO である Scott Hammond の協力でコミュニティと Joyent の利害を調整したりプロジェクトのロードマップを示すために Node.js Advisory Board という諮問機関が作られたが、状況は大きく変化しなかった。

node-forward ではコミュニティの開発者が patch を取り込んでもらえるが Joyent Node はそうではない。プライベートリポジトリで取り込まれた変更を(Joyent で働くメンバーが)Node.js 本体に取り込むような無駄な作業も行われており、フラストレーションを感じる開発者もいた。

しかし node-forward をそのままパブリックにすると、商標権侵害の問題がある。Scott は Joyent の顧客や Node.js のユーザーが単一のコミュニティを望んでいたので fork に反対しており、パブリックにする場合は商標権を追求して訴訟を定期する可能性がある旨を Mikeal に伝えていた。

node-forward のメンバーだった Fedor Indutny は、Joyent に反発し io.js としてフォークした。io.js の開発者は Node.js のコアコントリビュータしかいなかったしコードベースは実質的にほとんど同じだったが、コミュニティからは歓迎された。io.js の最初のリリースでは開発者の望んだ V8 の upgrade などが含まれていた。

この辺の経緯は以下のブログにまとまっている。

io.js の登場によりコミュニティが分断される危機が顕在化した。Joyent はこれ以上の分断を防ぐため「プロジェクトとしての Node.js は必要だが同社の利益のために管理者になる必要はない」という結論に至り、 Node.js の管理は Node.js Foundation (現 OpenJS Foundation)に移行することになった。Foundation のガバナンスの仕組みについては io.js や node-forward から引き継がれたものが多いようだ。

Joyent の Node.js と io.js は全て Node.js Foundation が管理する Node に統合され、Node.js v4.0.0 がリリースされた。これが現在の Node.js に繋がっている。


私は2020年からプログラミングを始めたので最近の Node.js しか知らない。初めて使った Node.js は v12 だったので当然 libuv があって Windows でも使えたし、非同期処理はコールバックではなく async / await で書いていたし、io.js は使ったことが無いし、Node.js のガバナンスに不安を感じた経験は特にない。

完全に余談だが、私は nvm で Node のバージョン管理をしている。"nvm ls-remote" で Node のバージョンをリストアップして古いものを眺めていると "v0.12.18" と "v4.0.0" の間に "iojs-v..." というバージョンがあって「なんだこれ?」と思っていたのだが、このドキュメンタリーを見てその疑問が解けた。

Node.js の物語は、以下の点でとても興味深い。

  • 一人の暇な人間が「非同期 I/O でパフォーマンスの高いサーバーを書けるのではないか」という動機で始めたことが、たった数年で多くの人を巻き込んで世界最大規模の OSS に成長したこと

  • JavaScript の採用や npm の登場、libuv の開発、フォークと再統合など一つ一つの積み重ねによってより多くの人が Node.js に魅力を感じ、参加していったこと

  • プロジェクトが巨大になるとさまざまな利害関係者が生まれ、その中でプロジェクトの方向性について合意したり当事者間の利害を調整するガバナンスを構築することは難しくなっていくこと

  • さまざまな利害の対立やそれに伴うフォークを経て、より強いコミュニティになったこと(雨降って地固まる)

さまざまな課題や衝突があっても Node.js は日々より多くの開発者に使われ続けている。実際、世の中の大部分の Web サイトはなんらかの形で Node.js を使っているだろう。それだけ大きな付加価値があり、多くの人が愛しているプロジェクトと言うことができる。

作者の Ryan Dahl 氏は現在 Deno を作っているわけだが、十数年後は Deno も今日の Node のような存在になっているかもしれない...

@llll
経理 → プログラマー