Framework Bun: "Schneller als mir irgendwer glaubt" – Jarred Sumner im Interview
Jarred Sumner ist der Kopf hinter der Node.js-Alternative Bun. Ein Gespräch über seine Motivation, sein Unternehmen und warum er die Schule abgebrochen hat.
- Timo Zander
- Silke Hahn
(This article is also available in English.)
Seit 2021 entwickelt der kalifornische Softwareentwickler Jarred Sumner federführend die JavaScript-Runtime Bun. Das Community-getriebene Projekt soll ein All-in-One-Werkzeug sein zum Bundlen, Transpilieren, Installieren und Ausführen von JavaScript- sowie TypeScript-Code. 2022 gründete Sumner das Unternehmen Oven, das die Entwicklung der neuen Laufzeitumgebung vorantreibt – zuvor war er Frontend Engineer bei Stripe.
Bun ist an Deno und Node.js angelehnt. Anders als Deno soll Bun besonders kompatibel sein mit Node.js. Es ist Open Source, in der Programmiersprache Zig geschrieben und die erste öffentliche Version ist seit Juli 2022 verfügbar (heise Developer hatte berichtet). Der Heise-Autor und JavaScript-Entwickler Timo Zander hat die Runtime ausprobiert und für die heise-Developer-Redaktion im Rahmen unserer Young-Professionals-Reihe mit Jarred Sumner über die Hintergründe gesprochen. Das Gespräch fand im Original auf Englisch statt.
heise Developer: Bun erlebt derzeit einen Hype. Was ist dein 5-Minuten-Pitch für das Tool?
Jarred Sumner: Bun ist alles in einem: JavaScript-Runtime, Bundler, Transpiler und npm-Paketmanager. Also nimmt es eine ganze Menge an Tools aus dem bestehenden Ökosystem, vereinigt sie in einem Tool und macht es richtig schnell. Der Weg, diese Geschwindigkeit zu erreichen, ist mithilfe von nativem Code und der Wahl schnellerer Systemaufrufe. Leute denken oft, dass Software I/O-gebunden sei, obwohl in Wahrheit die Systemaufrufe das Bottleneck sind. Also denkt man, dass das Lesen von der Festplatte bremst – was I/O-gebunden bedeutet. Doch in Wahrheit braucht das Einlesen und Verarbeiten oft deutlich mehr Zeit. Die Leute unterschätzen das oft, daher konzentriert Bun sich auf Performancegewinn durch das Reduzieren der Dauer von Systemaufrufen.
Also geht es hauptsächlich um das Parsen und Auswerten von Code und weniger um Lesen und Schreiben?
Nicht ganz. Bun ist zwanzig- bis hundertmal so schnell wie bestehende npm-Klienten auf Linux. Festplatten sind heutzutage sehr schnell, solange man keine rotierenden Platten benutzt – und das tun die wenigsten. Das Bottleneck ist daher nicht mehr "Zeit zum Schreiben". Aber wenn man zum Beispiel tausend npm-Pakete installiert, von denen die meisten schon heruntergeladen wurden, benötigt die Masse an Dingen, die dem Computer mitzuteilen sind, die meiste Zeit. Verkleinert man den Overhead dieser Systemaufrufe, erzielt man eine deutliche Beschleunigung.
Bun erreicht das mit einer Mischung aus nativem Code – statt JavaScript – und durch eine genaue Auswahl der Algorithmen. Das ist häufig ganz banal. Ich habe eine Woche damit verbracht, herauszufinden, was der schnellste Weg ist, Dateien zu kopieren. Erst auf Linux, dann auf macOS, denn die Lösungen sind ziemlich unterschiedlich.
So viel mal zu macOS and Linux. Was für Pläne gibt es für Windows?
Die Windows-Unterstützung soll binnen eines halben Jahres kommen. Windows Subsystem for Linux 2 lässt sich verwenden. Das funktioniert bereits heute, sofern man den neuesten Kernel hat.
Wieso liegt der Fokus so stark auf Performance?
Aus persönlichem Frust. Jahrelang war ich schwer frustriert, wie langsam JavaScript ist. Ich erinnere mich gut, wie ich zum ersten Mal Objective C nutzte und sah, wie viel schneller etwa NSLog gegenüber console.log ist. Mein Gedanke war, dass es keinen Grund gibt, wieso JavaScript nicht so schnell wie nativer Code sein kann bei solchen Aufgaben. Wenn alles von Systemaufrufen gebremst wird, dann geht es ausschließlich um den Overhead zwischen einer Nachricht an die Hardware und ihrer Verarbeitung.
Hattest du bereits Erfahrung mit systemnaher Programmierung?
Ehrlich gesagt, nicht wirklich. Wobei, das stimmt nicht ganz. Ich hatte ein Jahr lang ein performancesensibles Voxel-Multiplayer-Spiel mit JavaScript programmiert – Minecraft im Browser. Dort habe ich viel Erfahrung gesammelt, denn es war ziemlich schwierig, das umzusetzen. Irgendwann war der Code dann so groß, dass die Build-Zeiten und die Iterationszeit – also die Zeitspanne, bis eine gespeicherte Änderung sichtbar wird – wirklich extrem schlecht wurden. Ich habe alles probiert: esbuild, meine Tools upgraden, aber es war immer noch nicht schnell. Es war sogar so langsam, dass ich in der Wartezeit angefangen habe, Hacker News zu lesen, und das ist einfach der Tod der Kreativität. Blöd, wenn man den Fokus verliert, nur weil man auf den Build wartet.
Was hast du daraufhin versucht?
Zuerst dachte ich: Okay, ich migriere esbuild in die Low-Level-Sprache Zig. Das habe ich getan, habe gebenchmarkt und es war tatsächlich rund dreimal schneller für Dinge wie JSX-Transpilation. Irgendwann habe ich Next.js zum Laufen gebracht. Dann kamen mehr und mehr Dinge, in denen ich mich verlor: Den Transpiler zum Laufen bringen, serverseitiges Rendern. Dafür brauchte ich eine JavaScript-Runtime. Also habe ich mich gefragt: Node startet nicht allzu schnell, wie kann ich das verbessern?
Was machtest du dann?
Ich habe begonnen, mit V8-Isolaten zu arbeiten, das war deutlich schneller. Aber ich wollte sehen, wo die Grenze nach oben ist. Daher begann ich, mit JavaScriptCore zu experimentieren – das ist die JavaScript-Engine, die Safari nutzt. In allen Benchmarks, die ich fand, startete JavaScriptCore am schnellsten. Allerdings muss man hier einen Kompromiss eingehen: Hermes von Facebook startet etwas schneller, hat aber keine JIT-Funktion. Da müsste man den Just-in-Time-Compiler separat laufen lassen, was der Laufzeitperformance aber schaden würde.
Ich habe mich also für JavaScriptCore entschieden und rund einen Monat gebraucht, um es einzubinden. WebKit ist ein ziemlicher Monolith. Es gibt zwar Dokumentationen, wie die C-API sich nutzen lässt, allerdings sind die eher für einfache Anwendungsfälle gedacht. Etwa für ein Spiel, das JavaScript für einen Teil einbettet, nicht für eine ganze Runtime. Daher habe ich WebKit-Quellcode gelesen. Währenddessen war ich zunehmend frustriert über die langsamen Installationszeiten von npm und habe angefangen, bun install
zu schreiben.
Wieso hast du Zig als Programmiersprache gewählt?
Zuerst wollte ich Rust verwenden, hatte aber Probleme, produktiv damit zu arbeiten. Sehr cool ist, dass Zig eine so einfache Sprache ist. Man versteht alles, was passiert. Und das ist sehr wichtig für die Performance: In C++ gibt es zum Beispiel Destruktoren, die automatisch aufgerufen werden beim Zerstören eines Objekts. Oder man hat Funktionen, die aufgerufen werden, wenn sie den Scope verlassen. Das sind klassische Quellen von verstecktem Verhalten. Wenn man alles versteht, was in einem Programm vor sich geht, ist es einfach zu optimieren. Und Zig hat außerdem noch ein cooles Feature namens "Comptime", mit dem man beliebigen Quellcode – in normalem Zig – während des Kompilierens ausführen kann.
Andere Sprachen habe Makros oder Templates, meistens stark eingeschränkte Versionen der eigentlichen Sprache. In Zig hingegen ist alles ziemlich simpel, etwa wie es Generics implementiert: Statt einer speziellen Syntax übergibt man einen Typ. Dieser Typ ist dann ein comp-time
-Parameter, sodass man einen neuen Typ zurückgeben kann. Ich fand das wirklich cool und war binnen zwei Wochen produktiv im Umgang mit Zig. Die Lernkurve ist wahrscheinlich ähnlich wie bei Go, denn beide haben nicht viel Syntax und sind sparsam mit Abstraktionen. Zig ist nicht schwer zu erlernen.
Müssen alle Entwickler, die du einstellst, Zig schon beherrschen – oder lernen sie es während der Arbeit?
Letzteres! Die Leute lernen einfach Zig, immerhin ist es eine sehr einfache Sprache. Wer Erfahrung mit C oder C++ hat, kann Zig rasch meistern.
Was brachte dich dazu, Bun zu beginnen, statt zu bestehenden Projekten wie Deno beizutragen?
Ehrlich gesagt hatte ich Deno nicht in Erwägung gezogen. Ich finde es wichtig, dass der Fokus auf Kompatibilität liegt, damit Leute mit bestehendem Quellcode Bun nutzen können und direkt einen Performancezugewinn haben. Entweder durch Bun build – zum Beispiel durch TypeScript, das out-of-the-box funktioniert – oder durch die Runtime.
Versuchte Bun von Anfang an, ein vollumfängliches Tool zu sein?
So hat es nicht angefangen. Es ging zunächst nur darum, die Iterationszeit zu verringern, doch dann ist der Scope kontinuierlich gewachsen und wächst immer noch. Ich habe unlängst erst eine Loader API hinzugefügt. Alles in JavaScript kann deutlich schneller sein. Modernes JavaScript ist einfach so komplex mit seiner Vielzahl an Tools. Wenn man alles in ein Tool packt und es deutlich schneller macht, wird das Leben als Entwickler deutlich einfacher.
Hattest du in Erwägung gezogen, bestehende schnelle Tools wie pnpm einzubinden, statt Bun install zu schreiben?
Es ist schwierig, Bun install auf einem bestehenden Tool aufzubauen. Damit es schnell ist, muss es in den Rest von Bun integriert sein. Zum Beispiel ist der JSON-Parser ein eigener, der sowohl zum Lesen von package.json in Bun install genutzt wird, aber auch vom Transpiler. Durch das gemeinsame Nutzen des Codes ist es deutlich einfacher, ihn zu optimieren. Außerdem ist im Fall von Bun install nichts in JavaScript geschrieben, sondern alles in Zig.
Was ist der Plan für Buns erstes Stable Release – wann soll es erscheinen?
In rund fünf Monaten. Es gibt eine Menge zu tun!
Worüber hast du bislang noch nicht gesprochen?
Etwas, worüber ich bislang erst wenig gesprochen habe, ist Bun test. Das ist ein sehr schneller Testrunner für kleine Alltagstests. Er ist Jest-kompatibel, sodass Unternehmen ihn einfach für ihre bestehenden Tests nutzen können. Ich muss klar sagen, dass er ist noch nicht fertig ist und zurzeit gibt es noch keine Dokumentation dazu, aber das wird kommen. Er ist für kleine Jest-Tests rund vierzigmal schneller und bei einer größeren Menge Code etwa viermal schneller.
Benutzen die Tests allerdings TypeScript, habe ich auch schon Fälle gesehen, in denen Bun zweihundertmal schneller war. Das ist schneller, als irgendjemand je glauben würde – mich eingeschlossen. Ziemlich verrückt. Die Geschwindigkeit kommt erneut überwiegend aus der Architektur. Jest zum Beispiel hat ein eigenes Loader-System für TypeScript. Das muss eine Menge Laufzeit-Prototyp-Änderungen vornehmen. Mit Low-Level-Zugriff auf die Runtime kann man allerlei so ändern, dass es besser funktioniert. Damit kann man einiges an Performance rausholen. Daher denke ich, dass Bun test wirklich cool wird.
Doch auch Bun install wird wirklich cool, sobald es Workspaces unterstützt und stabiler ist. Dann kann es von größeren Unternehmen eingesetzt werden. Buns Laufzeit wird aufregend. Eine der spannendsten Sachen, die es geben wird, ist ein Bundler mit clientseitigem Fokus. Also wird es Bun build haben und es wird komplett unabhängig von der Laufzeit nutzbar sein, als Alternative zu esbuild. Und es gibt noch viel mehr, was Leute spannend finden werden: Es gibt zum Beispiel eine vollständige AST-Plugin-API, die direkt in der Laufzeit integriert ist. Das funktioniert ähnlich wie Makros, indem man kleine Funktionen zur Build-Zeit ausführen kann, die dann ASTs (abstrakte Syntaxbäume) anstelle von Strings zurückgeben. Doch in Bun kann man einfach ein Objekt zurückgeben, etwa ein Response-Objekt aus der Web-API. Und wenn dieses Objekt JSON enthält, wird es automatisch in das AST-Format konvertiert.
Man kann auch Kontext an diese Makros übergeben. Zum Beispiel kann man eine HTTP-Anfrage haben, die dynamisch generiertes JavaScript zurückgibt, was sich gut eignet zum Erkennen von totem Code. Bislang waren API-Antworten nie statisch analysierbar, denn sie wurden in einer Art abgerufen, die für Minifier und Transpiler undurchsichtig war. Indem man das in ein Makro verschiebt, kann man deutlich kleinere Builds generieren. Man hat ein besseres Bild davon, welcher Code tatsächlich genutzt wird. Also wird Bun auch einen Minifier haben. Doch das wird noch über sechs Monate brauchen, denn es gibt so viel zu tun.
Wie stehst du zu TypeScript? Wird Bun es unterstützen?
Ich persönlich mag TypeScript sehr, aber Buns Integration wird hauptsächlich aus einem Transpiler bestehen. Also wie auch esbuild und swc entfernt Bun alle Typen, bevor der Quellcode ausgeführt wird. Das Ganze funktioniert out-of-the-box, nichts muss extra installiert werden. Zudem liest Bun die tsconfig.json aus: Wenn ein bestehendes Projekt also etwa Paths nutzt, dann funktioniert das einfach in Bun. Kein zusätzliches Einrichten nötig. Bun prüft allerdings auch keine Typen, das ist hier der Kompromiss. Ich denke aber, dass es langfristig realistisch ist, den TypeScript-Compiler direkt einzubinden für das Szenario. Derzeit ist das nicht geplant, wir müssen den Scope realistisch begrenzen.
Bleibt noch etwas außen vor zurzeit?
Eine interessante Alternative, die Bun nicht verfolgt, ist, eine Light-Version von TypeScript zu erstellen. Sobald das TypeScript Type Annotation Proposal implementiert ist, wäre es deutlich einfacher, so eine schnelle Version zu implementieren. Aber das macht ein ganz anderes Fass auf, denn dann muss man ein eigenes LSP bauen und es entsteht plötzlich eine Inkompatibilität mit bestehenden Tools. Es wird sehr schnell sehr kompliziert. Also ja, das werde ich aktuell nicht machen.
Du sprichst in der Ich-Form, hast aber mit Oven auch ein Start-up gegründet, das hinter Buns Entwicklung steht. Welche Teamgröße strebst du an?
Wir stellen ein! Die Teamgröße wird zwischen drei und fünf Entwicklern liegen in den nächsten sechs Monaten, die meisten sollen dann Zig-Entwickler sein.
Jarred, in einem Tweet hattest du gesagt, dass Oven "ein Grind" sein werde, also eine Plackerei. Auf Twitter sorgte das für ziemliche Empörung. Was ist deine Sicht hierzu?
Das hatte ich nicht erwartet. Einige Leute sind heute noch sauer auf mich. Wenn ich das noch mal kommunizieren müsste, dann würde ich sagen, dass Oven ein Start-up in einem frühen Stadium ist. Und es wird eine Menge harter Arbeit brauchen. Es gibt viel zu tun und ich denke, dass Leute, die Interesse an Mitarbeit haben, das vorher wissen sollten. Ich finde es wichtig, vorab ehrlich zu sein. Das Wort "Grind" zu nutzen war aber ein Fehler.
Zudem gehen Menschen auf Twitter immer vom Schlechtesten aus und nehmen böse Absichten an. Ich hätte sagen sollen, dass die ersten Mitarbeiter auch eine große Menge an Unternehmensanteilen bekommen werden. Als junges Start-up ist das ein wichtiger Teil der Vergütung. Entwickler bekommen einen extrem bedeutsamen Anteil am Unternehmen zusätzlich zu dem Gehalt – wir haben sieben Millionen US-Dollar gesichert, um Beschäftigten gutes Gehalt zu zahlen. Das hätte ich sagen sollen. Denn die Leute haben wohl angenommen, dass man bei uns ohne Bezahlung hart arbeiten soll. Das wäre Unsinn.
Warum hast du das Start-up Oven gegründet statt Bun als reines Open-Source-Projekt aufzuziehen?
Es war von Anfang an mein Plan, ein Unternehmen aufzubauen und Start-ups zu gründen.
Hat deine Zeit bei Stripe deine Entscheidung zur Gründung Ovens beeinflusst?
Früher habe ich Apps für Endkunden gemacht. Das war vor Stripe. Zum Beispiel erstellte ich eine Pokémon-Go-Karte, die 4,9 Millionen Leute genutzt haben. Oder eine Chrome-Erweiterung, mit der man anderen Zugriff zu einer Webseite geben konnte, ohne das eigene Passwort zu teilen – auch das haben ein paar Millionen Leute genutzt. Also habe ich viele verschiedene Sachen gemacht, die aber noch keine Start-ups waren. Und ich habe eine Menge dabei gelernt. Stripe hatte allerdings keinen Einfluss auf meinen Wunsch, ein eigenes Start-up zu gründen. Mit 14 habe ich eine Menge Hacker News gelesen, das war der größte Einfluss.
In deiner Twitter-Biografie steht, dass du die High School abgebrochen hast. Was ist denn die Geschichte dahinter?
In der Bay Area aufzuwachsen war mein Glück. Als Kind habe ich meine gesamte Zeit am Computer verbracht. Irgendwann habe ich angefangen, Ruby on Rails zu lernen – das ist nun gut zehn Jahre her – und habe damit eine Anwendung gebaut und sie meinen Lehrern gezeigt. Und ich dachte, wenn ich diese Anwendung ganz alleine bauen kann, dann kann ich vielleicht auch einen Job finden. Denn ich hasste die Schule und war auch nicht gut darin. Also habe ich eine Menge "Cold E-Mails" an Unternehmen in der Nähe verschickt, eines davon hat mich als Praktikant eingestellt. Meine Sicht auf die Dinge war, dass ich entweder sechs Jahre in der Schule verbringe, um einen Job zu finden – oder mir direkt eine Stelle suche. Für mich hat das gut funktioniert.
Wie hat dein Umfeld darauf reagiert?
Meinen Eltern hat es nicht gefallen, dass ich die High School abgebrochen habe. Sie waren besorgt. Noch vor zwei oder drei Jahren haben sie mich regelmäßig gefragt, wann ich aufs College gehe. Allerdings war das für mich nie ein Problem durch das Silicon Valley und die Start-ups hier. In anderen Sektoren wäre das deutlich schwerer. Aber ich denke, eine Sache, die ich wirklich gut gemacht habe – die andere Leute sich abschauen sollten – sind meine Cold E-Mails. Viele Leute, besonders Entwickler, unterschätzen den Einfluss einer guten Initiativbewerbung. So habe ich nicht nur meinen ersten Job gefunden, sondern auch später noch weitere. Daher würde ich sagen, dass es für mich gut geklappt hat, die High School abzubrechen. Zum einen, weil ich wirklich Glück hatte, aber auch weil ich hart gearbeitet habe. Ich habe dadurch viel Zeit mit Programmieren verbracht.
Eine Cold E-Mail ist eine durch den Versender initiierte E-Mail, die beabsichtigt einen Kunden zu gewinnen, ein Job-Angebot zu erhalten oder sich einen anderweitigen Vorteil zu verschaffen. Verglichen mit Spam ist die Mail sehr personalisiert und wird innerhalb eines beruflichen Kontexts versendet. Im Deutschen würde man am ehesten "Initiativbewerbung" dazu sagen, doch der amerikanische Ausdruck ist etwas breiter gespannt. Im Sales-Bereich wäre auch "Kaltakquise" ein Begriff, der in die Richtung geht.
Kannst du ein paar Tipps für erfolgreiche Initiativbewerbungen geben?
Am besten einfach darüber sprechen, wieso man Interesse an dem Unternehmen hat, in normaler Alltagssprache. Auch finde ich es gut, dem CEO direkt zu mailen, die meisten Leute machen das nicht. Man kann auch dem Hiring Manager schreiben, je nach Unternehmen. Und dann spricht man über seine bisherigen Projekte oder relevante Erfahrungen mit möglichst vielen Details. Vielleicht kann man ja sogar ein Projekt vorzeigen, das eine besondere Schnittmenge mit dem Unternehmen zeigt. Ein Freund von mir hat zum Beispiel für ein Praktikum in einem T-Shirt-Start-up deren T-Shirt-Designer nachgebaut als Beleg, dass er Code schreiben kann und interessiert ist. Den hat er dem Unternehmen gezeigt und sie damit beeindruckt. Für Oven erwarte ich allerdings nicht, dass jemand so etwas tut.
Na ja, in einer früheren Stellenausschreibung hattest du aber Bewerber gebeten, Projekte zu zeigen, die sie mit Bun gebaut hatten...
Das war keine so gute Idee. Es lagen gerade einmal zwei Stunden zwischen meinem Tweet über Ovens Fundraising und der Banküberweisung auf mein Konto. Über all diese Tweets hatte ich nicht genug nachgedacht im Eifer des Gefechts. Grundsätzlich denke ich, dass es interessanter ist, relevante Projekte zu haben, die Erfahrung mit Low-Level-Softwaresystemen zeigen. Oven sucht aktuell keine Fullstack-Entwickler. Und das finde ich komisch, denn die Leute, die sich am meisten auf Bun freuen und es nutzen werden, sind nicht diejenigen, die es bauen werden. Es ist schlicht ein anderes Skillset aufgrund der Low-Level-Systeme. Jegliche Erfahrung mit C, Rust, C++ oder Zig ist von Vorteil. Besonders im Kontext von JavaScript-Interpretern oder interpretierten Sprachen im Allgemeinen.
Was genau wird Ovens Beitrag zu Bun sein?
Bun ist eine Runtime und bindet daher die Engine nur ein. Trotzdem denke ich, dass wir an der Engine mitarbeiten werden. Es ist spannend, all die Performanceverbesserungen in JavaScriptCore zu sehen. Eine Verbesserung, über die ich getwittert habe, war, dass Proxies vier- bis fünfmal schneller geworden sind beim Aufruf von Gettern. Eine andere, über die ich nicht getwittert habe, ist String.replace, das nun doppelt so schnell ist. Oven wird dabei mithelfen, denn für uns ist es wichtig, dass die Runtime-API schnell ist, genauso wie die tatsächlichen Implementierungen von verschiedenen JavaScript-Features.
Wieso sollten Leute sich auf Bun freuen?
Alles in JavaScript kann deutlich schneller und viel einfacher werden. Entwicklerinnen und Entwickler beschweren sich oft über die Komplexität in JavaScript. Und ein Hauptgrund hierfür ist, dass es so viele verschiedene Tools gibt, die alle eine einzelne Sache tun. Das macht es schwer zu verstehen, wie alles zusammenpasst. Auch sind diese Tools häufig sehr langsam. Bun packt alles in ein Tool, macht es deutlich schneller und ist zudem kompatibel zum restlichen Ökosystem.
Danke für deine Zeit, Jarred!
Das Interview führte Timo Zander, externer Autor für Heise in der Reihe Young Professionals. Zander hat Angewandte Mathematik und Informatik studiert. Als Entwickler interessiert er sich für Open Source und das JavaScript-Universum.
(sih)