Comment Dune est devenu un meilleur système de build pour OCaml
(blog.janestreet.com)- Insatisfait d’OMake, Jane Street a créé Jenga, mais son adoption externe est restée faible ; Jbuilder, conçu comme couche de compatibilité, a contre toute attente grandi jusqu’à devenir un outil de base de la communauté OCaml
- L’attrait initial de Jbuilder tenait moins à ses fonctionnalités qu’à sa vitesse et sa portabilité ; dans les projets Jane Street, une compilation environ 5 fois plus rapide qu’avec OCamlbuild a favorisé son adoption
- En collaboration avec OCaml Labs, Jbuilder est devenu un système de build complet et, en raison d’un conflit de nom avec un ancien IDE Java de Borland, il a été renommé Dune après discussion avec la communauté
- Jane Street a maintenu Jenga et Dune en parallèle pendant un temps, mais à mesure que sa base de code atteignait 65 M de lignes d’OCaml et 5 M de lignes de Python, la migration interne est devenue beaucoup plus difficile
- Après plus d’un an de travail intensif, la base de code de Jane Street se construit avec Dune ; quand la majeure partie du cache est déjà remplie, les builds sont 2 à 3 fois plus rapides
Jenga, né de l’insatisfaction envers OMake
- Un système de build est un outil quotidien des développeurs : il produit des programmes exécutables à partir de plusieurs fichiers source, lance le compilateur et exécute les tests
- Vers 2012, Jane Street, insatisfaite de OMake, alors l’un des systèmes de build standard d’OCaml, a créé son propre système de build, Jenga
- Comme Jenga fonctionnait bien en interne, Jane Street a décidé de le publier, pensant que la communauté pourrait aussi l’utiliser utilement
- L’entreprise espérait que des utilisateurs externes essaieraient Jenga et y contribueraient
- Elle pensait aussi que cela faciliterait la publication open source du code de Jane Street
- En pratique, l’adoption externe n’a pas été à la hauteur des attentes
- Il ne fonctionnait pas sous Windows
- Adopter Jenga revenait, dans les faits, à accepter toute la méthode Jane Street de build d’OCaml
- Comme l’usage externe ne progressait pas, Jane Street a de nouveau rendu Jenga privé, tandis que le problème du build de son code open source demeurait
Jbuilder, créé comme couche de compatibilité
- En 2016, Jane Street a décidé de créer Jbuilder, un outil simple et multiplateforme permettant aux utilisateurs externes de construire son code sans adopter tout Jenga
- L’objectif était aussi de réduire la charge liée à la réécriture des builds pour les adapter à OCamlbuild, qui émergeait alors comme le nouveau standard de build des projets OCaml
- Jbuilder comprenait les fichiers
jbuildque Jenga utilisait pour la configuration de build, et exécutait les commandes de compilation nécessaires dans un ordre topologique - Les premières versions de Jbuilder étaient loin d’un système de build au sens habituel
- Elles ne sélectionnaient pas uniquement les commandes dont les entrées avaient changé pour les relancer
- Elles relançaient toutes les commandes à chaque fois
Comment Jbuilder est devenu Dune
- Jbuilder était à l’origine pensé comme une petite couche de compatibilité, mais les utilisateurs ont commencé à l’employer au-delà des paquets Jane Street, pour construire leurs propres projets
- Le principal facteur d’adoption a été sa vitesse
- Environ 5 fois plus rapide qu’OCamlbuild pour compiler les projets Jane Street
- Une bonne portabilité
- Une structure simple, facile à modifier
- Jane Street a commencé à travailler avec OCaml Labs, aujourd’hui Tarides, pour faire évoluer Jbuilder vers un système de build plus complet
- Le nom est devenu un problème à part entière
- Il existait déjà JBuilder, un IDE Java de Borland
- Même si ce système avait en pratique disparu depuis longtemps, la demande d’autorisation d’utiliser le nom auprès du détenteur des droits n’a pas abouti
- Après discussion avec la communauté, le nouveau nom Dune a été choisi
- La discussion correspondante s’est déroulée dans le fil de proposition d’un nouveau nom pour Jbuilder
Le coût du maintien de deux systèmes de build
- Avec la popularité croissante de Dune, Jane Street s’est retrouvée à maintenir et prendre en charge simultanément deux systèmes de build complets qu’elle avait elle-même créés, Jenga et Dune
- Dune s’est imposé comme un système doté d’une architecture repensée, de bonnes performances sur la plupart des builds utilisateurs, d’une adoption plus large, ainsi que de meilleures API et d’une meilleure expérience utilisateur
- La question de savoir quand migrer l’interne vers Dune est naturellement devenue un chantier, mais l’équipe build system était déjà occupée à suivre la croissance de la base de code
- Au lancement de Dune en 2016, le code OCaml comptait 4 M de lignes
- Aujourd’hui, il y a 65 M de lignes d’OCaml et 5 M de lignes de Python
- La migration vers Dune représentait une charge importante et n’a pas pu être réellement lancée ; on répétait surtout l’estimation optimiste selon laquelle « cela pourrait être possible dans les 6 à 12 prochains mois »
- L’an dernier, après avoir porté l’équipe build system à 5 ingénieurs à temps plein, Jane Street a lancé cette migration longtemps repoussée
Dune remplace Jenga en interne chez Jane Street
- L’un des plus gros chantiers a été de faire en sorte que Dune puisse passer à l’échelle de l’énorme base de code de Jane Street
- Si Dune était rapide à l’extérieur, c’était notamment parce que la plupart des utilisateurs construisaient des projets bien plus petits que le dépôt de 70 M de lignes de Jane Street
- Jenga n’était pas non plus resté figé pendant 10 ans
- Jane Street avait continué à améliorer l’implémentation de Jenga pour accompagner la croissance de sa base de code
- Jenga était devenu fortement optimisé pour les besoins d’un grand monorepo
- Une grande partie de ce travail d’optimisation devait être portée vers Dune
- Le travail d’intégration au quotidien était également conséquent
- Le système de build est appelé depuis de nombreux workflows
- Les trois éditeurs Vim, Emacs et VSCode disposaient chacun d’intégrations personnalisées pour Jenga
- Chaque intégration a dû être migrée une à une vers Dune
- Après plus d’un an de travail intensif, la base de code de Jane Street se construit désormais avec Dune
- Au moment de la transition, les performances de Dune étaient globalement équivalentes ou supérieures à celles de Jenga
- Dans certains cas, elles étaient nettement meilleures
- Quand la plupart des tâches de build sont déjà dans le cache, les builds sont 2 à 3 fois plus rapides
Les prochaines améliorations possibles avec un système unique
- Jane Street prévoit de publier en open source une grande partie du travail d’amélioration des performances de Dune, et une partie l’est déjà
- Pour éviter de recréer deux systèmes, un fork Dune pour Jane Street et un Dune externe, l’entreprise veille à intégrer autant que possible les changements upstream
- Dune est devenu une meilleure base pour créer de nouvelles fonctionnalités
- La base de code est plus simple et plus facile à travailler
- L’équipe peut se concentrer sur un seul système
- Les fonctionnalités suivantes se rapprochent également
-
Builds distribués
- Builds superficiels, c’est-à-dire « builds without the bytes »
- Chargement depuis le cache du graphe de build lui-même
- L’équipe build system est passée à 12 ingénieurs à temps plein à New York, Londres et Singapour, et le rythme d’amélioration de Dune s’accélère
-
1 commentaires
Avis sur Hacker News
Message de crash de Dune :
https://github.com/ocaml/dune/issues/2767
Le podcast technique de Jane Street, Signals and Threads, a consacré un épisode aux systèmes de build en 2020, et je le recommande vivement
Les autres épisodes sont aussi bons, notamment The Future of Programming avec Richard Eisenberg, et What is an Operating System? avec Anil Madhavapeddy
¥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/
Le fait que Jane Street ait prouvé qu’avec suffisamment d’efforts, la programmation fonctionnelle typée HM pouvait être prête pour la production et très rapide mérite le respect
J’entends encore parfois dire que les langages fonctionnels de style plus académique ne sont pas utilisables en production, mais OCaml montre que c’est tout à fait possible, même avec des exigences de hautes performances
https://mercury.com/
C’est un excellent choix pour créer des programmes de qualité tout en interopérant largement avec des systèmes existants
D’après un billet de blog d’il y a quelques années, ils ont aussi expérimenté Roc, mais je ne sais pas s’ils l’utilisent encore aujourd’hui
[0] https://blog.noredink.com
Chaque fois que je lis un billet du blog de Janestreet, je souris intérieurement en me disant que travailler chez Jane dans la finance a l’air plus intéressant et mieux rémunéré que 90 % des emplois de ce qu’on appelle la tech
Il y a énormément de postes tech dans la finance qui ne sont ni aussi intéressants ni aussi bien payés que ceux d’une entreprise tech moyenne, sans même parler de Jane Street
Dans la finance, beaucoup de jobs consistent à corriger du code Java vieux de 20 ans, ou à trouver de nouvelles façons d’entrer et de sortir des données de fichiers Excel pour des rapports sur mesure
J’ai aussi entendu dire qu’il était beaucoup plus difficile d’entrer chez JS que chez Google/Meta
J’y ai moi-même postulé autrefois, et l’intervieweur était assez désagréable ; ça ne m’avait pas laissé une bonne impression, surtout que je n’ai jamais eu ce genre d’expérience en entretien dans la big tech
Cela dit, je place quand même ça au-dessus du fait de pousser les gens à cliquer sur des pubs
Comme ailleurs, il y a un mélange de projets intéressants et de tâches ennuyeuses
La seule chose pire qu’une base de code complexe, c’est un système de build complexe. CMake est abominable
C’est du genre : « Pour compiler ce langage, apprenez encore un nouveau langage ! »
Il fait aussi correctement certaines choses, et une partie de ce qu’il fait mal reste gérable
Si un ensemble de fichiers de configuration éditables par des humains permet d’obtenir des procédures de build multiplateformes, je peux accepter une certaine dose de douleur
Son affreux langage de script le plombe, mais avec assez de motivation, cela pourrait s’améliorer
Il y a longtemps, après Lisp, j’ai passé quelques années du côté de Haskell pour ma première expérience fonctionnelle
OCaml ne me parlait pas vraiment, et comme je souffrais d’une forme rare d’allergie aux points-virgules, Haskell me semblait bien plus agréable à lire
Mais récemment, j’ai essayé Reason, j’ai beaucoup aimé, et soudain tout ce qui touche à OCaml est devenu intéressant
https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...
https://ocaml.org/docs/toplevel-introduction#loading-librari...
https://reasonml.github.io/ a l’air chouette, comme un OCaml avec une touche JavaScript
Une fois qu’on a saisi la logique, ça doit aller, mais on dirait qu’il faut apprendre à penser avec cette structure, comme avec Lisp. Malgré tout, un écran rempli de code Haskell continue de m’intimider
Dans le lot, SML/NJ était le plus lisible pour moi
Je me demande si quelqu’un a déjà utilisé les bibliothèques et outils OCaml open source de Jane Street dans un projet un tant soit peu sérieux
À première vue, j’ai eu l’impression qu’ils avaient fait beaucoup d’efforts pour créer un écosystème et publier leur code en open source, mais que ce n’était pas vraiment « prêt » pour des utilisateurs extérieurs à Jane Street
Pour trouver quelque chose, il faut savoir lire assez efficacement les signatures de fonctions, mais à part ça je n’ai pas de reproche. Par exemple, les fonctions qui convertissent tous les types de base vers et depuis des s-expressions font gagner énormément de temps si l’on sait qu’elles existent et qu’on les prévoit à l’avance
J’ai aussi utilisé d’autres bibliothèques, et les ppx de logging et de tests unitaires sont quasiment des standards de fait dans le monde OCaml, si tant est que ce genre de chose y soit possible. J’ai aussi utilisé le formateur de code, un framework de test, et des implémentations de structures de données avancées
Parfois, comme dans d’autres commentaires, on tombe sur des choses qui ne fonctionnent vraiment pas. Elles dépendent d’un élément distribué séparément et non documenté, ou nécessitent une configuration secrète, ce genre de chose. Ce n’est pas malveillant, et si l’on ouvre une issue puis qu’on revient un ou deux ans plus tard, ça fonctionne souvent
Ce n’est pas sans frustrations, mais j’apprécie leur approche consistant à tout publier plutôt qu’à consacrer les ressources à tester et peaufiner moins de releases. La qualité du code est généralement très élevée et, même quand je n’arrive pas à le faire fonctionner directement, cela reste une implémentation d’exemple rigoureuse et éprouvée
Je trouve son API nettement meilleure que celle de la stdlib standard
J’aime Lean 4, mais il n’est pas facile de se faire aider par l’IA. Mon travail du jour consiste à digérer le manuel de référence pour qu’il tienne bien dans une fenêtre de contexte de 200K. On verra si ça aide
C’est assez étonnant qu’il soit encore logique de développer son propre nouveau système de build et de migrer vers celui-ci, plutôt que d’adopter un outil existant comme buck2 ou bazel
Je ne dis pas que ces outils de build avancés soient faciles à adopter, mais comparé au fait de tout construire soi-même ? Je me demande ce qui rend dune si particulier
La première release de Bazel date de 2015, Buck de 2013
Il y a bien une certaine culture NIH chez JS, mais je ne sais pas si elle a joué ici. À l’époque, il n’y avait pas beaucoup de bons outils de build, surtout pour une entreprise utilisant une pile technologique peu conventionnelle
En particulier, il me semble qu’il faut pouvoir lancer ocamldep à l’avance ou compiler deux fois ; buck2 le permet, tandis que Bazel nécessite des hacks, si je me souviens bien
Les deux sont à peu près comparables. Pour la vitesse brute d’appel des outils de build OCaml, dune est plus rapide ; lorsqu’il faut reconstruire beaucoup de choses et qu’on utilise un système de build distribué, buck2 l’emporte
Le gros point douloureux, c’est l’intégration LSP. Comme la seule façon pour le serveur LSP de connaître les dépendances d’un fichier est de passer par le build, il doit être étroitement couplé au système de build. Avec dune, tout est fourni proprement. Nous avons aussi bricolé quelque chose avec buck2, mais ce n’est pas aussi bon
Dune est de loin le meilleur nom pour un système de build, rien ne s’en approche
Commencer avec l’idée de créer un meilleur système de build puis créer « par hasard » un meilleur système de build : c’est étrange, la manière dont ce genre de hasard se produit