OCamlのためのより良いビルドシステム、Duneになるまで
(blog.janestreet.com)- Jane StreetはOMakeへの不満から Jenga を作ったが、外部での採用は伸びず、互換性のために作ったJbuilderが予想外にOCamlコミュニティの基盤ツールへと成長した
- Jbuilderの初期の魅力は機能よりも 速度と移植性 にあり、Jane StreetのプロジェクトではOCamlbuildより約 5倍高速なコンパイル が採用を後押しした
- JbuilderはOCaml Labsと協力しながら完全なビルドシステムへと発展し、既存のBorland Java IDEとの名前衝突のため、コミュニティでの議論を経て Dune になった
- Jane StreetはしばらくJengaとDuneを並行して維持していたが、コードベースが 6,500万行のOCaml と 500万行のPython にまで拡大し、内部移行の難易度が大きく上がった
- 1年以上にわたる集中的な作業の末、Jane StreetのコードベースはDuneでビルドされるようになり、キャッシュがほぼ埋まっているビルドは 2〜3倍高速化 した
OMakeへの不満から始まったJenga
- ビルドシステムは、複数のソースファイルから実行可能なプログラムを作り、コンパイラの呼び出しやテスト実行まで担う、開発者の日常的なツールである
- Jane Streetは2012年ごろ、OCamlの標準的なビルドシステムの1つだった OMake に不満を感じ、自前のビルドシステム Jenga を作った
- 社内ではJengaがうまく機能していたため、Jane Streetはコミュニティでも有用に使えるはずだと考え、公開を決めた
- 外部ユーザーがJengaを使い、貢献してくれることを期待していた
- Jane Streetのコードをオープンソースとして公開することも容易になると見ていた
- 実際の外部採用は期待に及ばなかった
- Windowsで動作しなかった
- Jengaを採用するには、事実上OCamlをビルドする Jane Street方式 全体を受け入れる必要があった
- 外部利用が増えなかったため、Jane StreetはJengaを再び非公開に戻し、オープンソースコードのビルド問題は残ったままだった
互換レイヤーとして作られたJbuilder
- 2016年、Jane Streetは外部ユーザーがJenga全体を受け入れなくても自社コードをビルドできる、シンプルなクロスプラットフォームツール Jbuilder を作ることにした
- このツールには、当時OCamlプロジェクトのビルド新標準として台頭していた OCamlbuild 向けにビルドを書き直す負担を減らす目的もあった
- JbuilderはJengaがビルド設定に使っていた
jbuildファイルを理解し、必要なコンパイルコマンドを トポロジカルソート順 に実行した - 初期のJbuilderは、一般的な意味でのビルドシステムとはやや離れていた
- 入力が変わったコマンドだけを選んで再実行することはしなかった
- 毎回すべてのコマンドを再実行する方式だった
JbuilderがDuneに変わるまで
- Jbuilderはもともと小さな互換レイヤーとして意図されていたが、ユーザーはJane Streetのパッケージを超えて、自分たちのプロジェクトのビルドにも使い始めた
- 採用を後押しした最大の要因は 速度 だった
- Jane StreetのプロジェクトのコンパイルでOCamlbuildより約 5倍高速 だった
- 移植性が高かった
- 構造がシンプルで修正しやすかった
- Jane Streetは OCaml Labs、現在の Tarides と協力し、Jbuilderをより完全なビルドシステムへと発展させ始めた
- 名前は別の問題になった
- すでにBorlandのJava IDEである JBuilder が存在していた
- そのシステムはずっと前に事実上消滅していたが、著作権保有者に名称使用の意向を問い合わせても許可は得られなかった
- コミュニティでの議論の末、新しい名前として Dune が選ばれた
- 関連する議論は 新しいJbuilder名の提案スレッド で行われた
2つのビルドシステムを並行維持するコスト
- Duneの人気が高まるにつれ、Jane Streetは自社で作った2つの完全なビルドシステム、JengaとDune を同時に維持・サポートすることになった
- Duneは、再設計された構造、ほとんどのユーザービルドでの高速な性能、より広い採用、より良いAPIとユーザー体験を備えたシステムとして定着した
- 社内をいつDuneへ移すかが自然と課題になったが、ビルドシステムチームは拡大し続けるコードベースに追いつくだけでも手一杯だった
- 2016年にDuneが始まった当時、OCamlコードは 400万行 だった
- 現在は 6,500万行のOCaml と 500万行のPython がある
- Duneへの移行は負担が大きく、本格的に着手できず、「今後6〜12か月以内には可能かもしれない」という希望的観測だけが繰り返されていた
- 昨年、Jane Streetはビルドシステムチームを フルタイムエンジニア5人 に拡大した後、長く先送りされていた移行作業を開始した
Jane Street社内でJengaを置き換えたDune
- 最大の作業の1つは、DuneをJane Streetの巨大なコードベースに合わせて スケール するようにすることだった
- 外部でDuneが高速だった理由の1つは、ほとんどのユーザーがJane Streetの 7,000万行のリポジトリ よりはるかに小さいプロジェクトをビルドしていたからだ
- Jengaも10年間そのまま止まっていたわけではなかった
- Jane Streetはコードベースの成長に合わせてJengaの実装を継続的に改善してきた
- Jengaは大規模モノレポの要件に合わせてかなり最適化された状態だった
- この最適化作業のかなりの部分をDuneへ移す必要があった
- 日常的な統合作業も簡単ではなかった
- ビルドシステムは複数のワークフローから呼び出される
- Vim、Emacs、VSCodeの3つのエディタがそれぞれJenga向けのカスタム統合を持っていた
- 各統合をDuneへ1つずつ移行しなければならなかった
- 1年以上にわたる集中的な作業の末、Jane Streetのコードベースは現在Duneでビルドされている
- 移行時点でのDuneの性能は、全体としてJengaと同等かそれ以上だった
- 一部のケースでははるかに良い性能を示した
- ほとんどのビルド作業がすでにキャッシュにある場合、ビルドは 2〜3倍高速化 した
単一システムの上で可能になる次の改善
- Jane StreetはDuneの性能改善作業のかなりの部分をオープンソースとして公開する計画で、一部はすでに公開されている
- Jane Street向けDuneフォークと外部向けDuneという2つの系統が再び生まれないよう、可能な変更は アップストリーム に反映することを重視している
- Duneは新機能を作るための基盤としてより適したものになった
- コードベースがよりシンプルで作業しやすい
- 1つのシステムに集中できる
- 次の機能もより現実味を帯びてきた
-
分散ビルド
- 浅いビルド、すなわち “builds without the bytes”
- ビルドグラフ自体のキャッシュ読み込み
- ビルドシステムチームはニューヨーク、ロンドン、シンガポールにまたがる フルタイムエンジニア12人 に拡大し、Dune改善の速度も上がっている
-
1件のコメント
Hacker Newsのコメント
Duneのクラッシュメッセージ:
https://github.com/ocaml/dune/issues/2767
Jane Streetの技術ポッドキャストSignals and Threadsには、2020年にビルドシステムを扱ったエピソードがあり、強くおすすめする
他のエピソードも良く、特にRichard Eisenbergが出演したThe Future of Programming、Anil Madhavapeddyが出演したWhat is an Operating System?もおすすめ
¥https://signalsandthreads.com/build-systems/
°https://signalsandthreads.com/future-of-programming/
§https://signalsandthreads.com/what-is-an-operating-system/
https://signalsandthreads.com/multicast-and-the-markets/
Jane Streetが、HM型の関数型プログラミングも十分に力を入れれば本番投入可能で、非常に高速にもなり得ることを証明した点は敬意に値する
いまだに、より学術寄りのスタイルの関数型言語は本番では使えないという話を時々聞くが、OCamlは高性能要件があっても十分可能だと示している
https://mercury.com/
既存システムと幅広く相互運用しながら高品質なプログラムを作るのに優れた選択肢だ
数年前のブログ記事によるとRocも試したことがあるようだが、今も使っているかは分からない
[0] https://blog.noredink.com
Janestreetのブログ記事を見るたびに、Janeで金融業界の仕事をする方が、いわゆるテック業界の仕事の90%より面白く、報酬も良さそうだと思って内心笑ってしまう
金融系の技術職には、Jane Streetはおろか平均的なテック企業ほどにも面白くなく、報酬も良くない仕事がはるかに多い
金融業界の多くの仕事は、20年前のJavaコードを直したり、カスタムレポートのためにExcelファイルへデータを出し入れする新しい方法を探したりすることだ
それにJSに入るのはGoogle/Metaよりずっと難しいと聞いた
私も以前応募したが、面接官がかなり不快で、ビッグテックの面接ではそんなことはなかったので、良い印象ではなかった
それでも、人々に広告をクリックさせる仕事よりは高く評価する
他の会社と同じように、興味深いプロジェクトと退屈な仕事が混在している
複雑なコードベースより悪いものは、複雑なビルドシステムだけだ。CMakeは忌まわしい
「この言語をコンパイルするには、さらに別の新しい言語を学べ!」というありさまだ
ちゃんとできていることもいくつかあるし、間違っていることの一部は管理可能だ
人間が編集できる設定ファイル一式で複数プラットフォームのビルド手順が得られるなら、ある程度の苦痛は受け入れられる
ひどいスクリプト言語が足を引っ張っているが、十分な動機があれば改善できるはずだ
以前、Lispのあとで初めての関数型体験としてHaskell方面で数年を過ごしたことがある
OCamlはあまりピンと来ず、珍しいタイプのセミコロンアレルギーがあったので、Haskellのほうがずっと見やすかった
ところが最近Reasonを使ってみたらとても良くて、急にOCaml関連のあらゆるものが面白くなった
https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...
https://ocaml.org/docs/toplevel-introduction#loading-librari...
https://reasonml.github.io/は格好よく見えるし、JavaScript風のOCamlのようだ
その線が分かれば大丈夫なのだろうが、Lispのように、その構造で考える方法を学ぶ必要がある気がする。それでもHaskellコードが画面いっぱいにあると怖気づく
その中ではSML/NJがいちばん読みやすかった
Jane StreetのオープンソースのOCamlライブラリとツールを、ある程度本格的なプロジェクトで使ったことがある人がいるのか気になる
ざっと見た印象では、エコシステムを作り、コードをオープンソースとして公開することに多くの労力を注いではいるものの、Jane Street外部の人が使うには「準備ができた」状態ではないように思えた
何かを探すには関数シグネチャをかなり上手に読める必要があるが、それ以外に不満はない。たとえば、すべての基本型についてS式へ変換したり戻したりする関数は、存在を知っていて事前に計画しておけば、ものすごく時間を節約できる
ほかのライブラリも使ったことがあり、ロギングとユニットテストのppxは、OCamlの世界でそういうものが可能なら、事実上の標準に近い。コードフォーマッタ、テストフレームワークの1つ、高度なデータ構造の実装も使った
ときどき、別のコメントにあるように本当に動かないものにも出会う。別途配布された文書化されていない何かに依存していたり、秘密の設定が必要だったりする類だ。悪意があるわけではなく、issueを開いて1〜2年後に戻ってくると動くことが多い
フラストレーションがまったくないわけではないが、より少ないリリースをテストして磨くことにリソースを使うより、すべて公開するという姿勢はありがたいと思っている。コード品質は総じて非常に高く、自分で動かせなくても、厳密で検証済みの実装例になる
標準のstdlibよりAPIがずっと良いと思う
Lean 4は好きだが、AIに手伝ってもらうのは簡単ではない。今日進めている作業は、リファレンスマニュアルを200Kのコンテキストウィンドウにうまく収まるように消化することだ。役に立つか見てみるつもりだ
独自の新しいビルドシステムを開発してそこへ移行することが、buck2やbazelのような既成ツールを採用するよりもなお筋が通るという点はかなり驚きだ
こうした高度なビルドツールを導入しやすいという意味ではないが、自作するのと比べるとどうなのだろうか。duneを大きく違うものにしている特別な点があるのか気になる
Bazelの初リリースは2015年、Buckは2013年だ
JSにはNIH文化が多少あるが、ここでそれが作用したのかは分からない。当時は良いビルドツールが多くなく、特に非主流の技術スタックを使う会社にとってはなおさらだった
特に、事前にocamldepを実行できる必要があるか、二度コンパイルする必要があると理解しているが、buck2では可能で、Bazelは記憶ではハックが必要だ
両者はおおむね似ている。OCamlビルドツールを呼び出す純粋な速度はduneが速く、多くを再ビルドする必要があり分散ビルドシステムを使うときはbuck2が勝つ
大きな痛みはLSP統合だ。LSPサーバーがファイルの依存関係を知る唯一の方法がビルドであるため、ビルドシステムと密接に結びつく必要がある。duneではすべてがきれいに提供される。buck2でも何とかつなぎ込んではいるが、それほど良くはない
Duneはビルドシステムの名前としては断然最高で、近いものすらない
より良いビルドシステムを作ろうとして始めたあとで「偶然」より良いビルドシステムを作ったとは、そういう偶然の起き方は実に奇妙だ