Ingenieurbericht: Ausgabe 2025

Everett Pompeii

Everett Pompeii


Beim Entwickeln einer neuen Technologie, wie Bencher, besteht ein grundlegender Konflikt zwischen dem Wunsch, langweilige Technologie zu wählen und dem, die Durchschnitte zu übertreffen. Im Moment kann es schwierig sein, genau zu erkennen, wo man in diesem Tauziehen steht. Alle drei Jahre bringt die Programmiersprache Rust eine neue Rust-Edition heraus. Ich denke, das ist ein schönes Tempo. Es ist lange genug, um wirkliche Fortschritte zu erzielen. Doch kurz genug, um nicht zu weit abzuschweifen. Da Bencher in diesem Frühjahr 3 Jahre alt wird, dachte ich, es wäre eine großartige Zeit, innezuhalten und über alle Ingenieursentscheidungen nachzudenken, die uns hierher gebracht haben.

In diesem Beitrag werde ich darauf zurückblicken, wo Bencher seine “Innovationstokens” in den letzten drei Jahren eingesetzt hat. Bencher ist eine Open Source Suite von kontinuierlichen Benchmark-Tools. Ich beginne beim Frontend der Bencher-Architektur und bewege mich den gesamten Stack hinunter. An jedem Punkt entlang des Weges werde ich diskutieren, wie wir hierher gekommen sind und ein binäres Urteil darüber fällen, wie sich jede Ingenieursentscheidung ausgezahlt hat.

Frontend

Frontend-Bibliothek

Als sich erholender C++-Entwickler bin ich ein ziemlich großer Fan von Rust. Wenn ich die Wahl hätte, hätte ich Bencher gerne in Full-Stack Rust geschrieben. Wenn Sie in die tiefen Winkel des Bencher-Repo eintauchen, werden Sie sehen, dass ich genau das versucht habe. Ich experimentierte mit Yew, Seed und Sycamore. Während diese für einige Projekte großartig funktionieren können, gab es einen großen Haken, über den ich einfach nicht hinwegkam: JavaScript-Interoperation.

Während JS-Interop von WASM über Rust möglich ist, würde es nicht einfach werden. Ich wusste, dass ich wollte, dass Bencher hochinteraktive Diagramme besitzt. Dies bedeutete die Verwendung einer Bibliothek wie D3, was JS-Interop bedeutete.

Also, wenn ich JavaScript verwenden müsste, welche Bibliothek sollte ich wählen?

Zurück zu den Rust-Crates, mit denen ich experimentiert habe: Yew ist das Rust-Äquivalent zu React Hooks. Ich hatte in der Vergangenheit ein Frontend mit React Hooks gebaut und bereitgestellt, daher wusste ich am meisten über dieses Framework. Allerdings fand ich den React Hooks-Lebenszyklus sehr kompliziert und voller Tücken und seltsamer Randfälle.

Ich mochte die Grundprinzipien der funktionalen reaktiven Programmierung (FRP) wirklich. Dies führte dazu, dass ich sowohl Elm als auch sein Rust-Äquivalent Seed ausprobierte. Leider leidet die Verwendung von Elm unter den gleichen Problemen wie die Verwendung von Rust. Elm erfordert seine eigene JavaScript-Interop. Ich fand auch Die Elm-Architektur ein bisschen zu einschränkend für meinen Geschmack.

Von allen Rust-Frameworks, die ich ausprobierte, gefiel mir Sycamore am meisten. Sycamore wurde von Solid inspiriert. Je mehr ich über Solid lernte, desto mehr gefiel es mir. Anders als React verwendet Solid keinen virtuellen DOM. Stattdessen kompiliert es zu gutem alten JavaScript. Dies macht es viel schneller, kleiner und einfacher zu arbeiten. Solid besteht aus nur wenigen mächtigen Primitiven, die eine fein abgestufte Reaktivität ermöglichen. Wenn etwas in der UI aktualisiert wird, wird nur der Code, der davon abhängt, erneut ausgeführt. In den letzten drei Jahren habe ich es als Vergnügen empfunden, mit Solid zu arbeiten.

TechnologieUrteil
Yew
Seed
Sycamore
Elm
SolidJS

Frontend-Framework

Solid selbst ist nur eine Bibliothek. Um ein modernes Frontend zu bauen, musste ich ein vollwertiges Web-App-Framework verwenden. Um die Dinge einfach zu halten, setzte ich alles auf die Solid-Karte, und ich benutzte anfänglich SolidStart. Zu der Zeit unterstützte SolidStart nur Single-Page-Apps (SPAs).

Eine SPA war in Ordnung, um loszulegen. Letztendlich musste ich jedoch anfangen, mich um Dinge wie SEO zu kümmern. Ich begann, viel mehr Bencher-Dokumentation zu schreiben. Ich plante auch den Lernbereich der Website. Das bedeutete, dass ich sowohl Client-Side Rendering (CSR) als auch eine statische Webseiten-Generierung (SSG) benötigte. SolidStart war sehr jung, und ich konnte es nicht dazu bringen, all meine Bedürfnisse zu erfüllen.

Nachdem ich von Astro erfahren und es ausprobiert hatte, entschied ich mich, das gesamte Bencher-Frontend von SolidStart zu Astro zu portieren. Dies hatte ein paar Nachteile. Der offensichtlichste war der dafür erforderliche Aufwand. Ehrlich gesagt, war es nicht zu schlimm. Astro hat seine Islands-Architektur und eine erstklassige Solid-Integration. Ich konnte auch viel von der Logik, die ich vom Solid Router benötigte, übernehmen, und es funktionierte einfach irgendwie.

Der große Kompromiss, der bis heute besteht, ist, dass Bencher von einer Single-Page-App zu einer Multi-Page-App wechselte. Die meisten Orte, auf die Sie in der Konsole klicken, verursachen ein vollständiges Seiten-Neuladen. Astro hatte das Versprechen von Ansichtstransitionen, als ich den Wechsel vornahm. Ich habe sie ausprobiert, aber sie waren fehlerhaft. Ich muss immer noch darauf zurückkommen.

In der Zwischenzeit scheint SolidStart etwas aufgeholt zu haben. Sie unterstützen jetzt sowohl CSR als auch SSG. Obwohl ich nicht überprüft habe, ob sie beide auf derselben Seite funktionieren, wie ich es brauche. Vergangene Ereignisse.

TechnologieUrteil
SolidStart
Astro

Frontend-Sprache

Astro hat eingebaute TypeScript-Unterstützung. Im Übergang von SolidStart zu Astro habe ich auch den Übergang von JavaScript zu TypeScript begonnen. Bencher’s TypeScript-Konfiguration ist auf Astro’s strengste Einstellung gesetzt. Astro führt jedoch keine Typprüfung während der Builds durch. Zum Zeitpunkt des Schreibens hat Bencher noch 604 Typfehler. Diese Typfehler werden eher als Hinweise beim Bearbeiten von Code verwendet, blockieren den Build jedoch nicht (bis jetzt).

Ich habe auch Typeshare hinzugefügt, um Bencher’s Rust-Datentypen mit dem TypeScript-Frontend zu synchronisieren. Dies war unglaublich hilfreich für die Entwicklung der Bencher-Konsole. Darüber hinaus werden alle Feldvalidierer für Dinge wie Benutzernamen, E-Mails usw. zwischen dem Rust-Code und dem TypeScript-Frontend über WASM geteilt. Es war ein bisschen mühsam, WASM sowohl in SolidStart als auch in Astro zum Laufen zu bringen. Die größte Art von Fehlern, die ich im Frontend gesehen habe, waren Orte, an denen eine WASM-Funktion aufgerufen wird, aber das WASM-Modul noch nicht geladen ist. Ich habe herausgefunden, wie man es behebt, vergesse es aber manchmal trotzdem und es tritt erneut auf.

Das automatische Generieren sowohl der gemeinsamen Typen als auch der Validierer aus dem Rust-Code hat die Schnittstellenarbeit mit dem Frontend erheblich erleichtert. Sie werden beide in CI überprüft, sodass sie nie asynchron sind. Alles, was ich tun muss, ist sicherzustellen, dass die HTTP-Anfragen gut geformt sind, und es funktioniert einfach. Das macht das Unvermögen, Full-Stack Rust zu verwenden, ein bisschen weniger schmerzhaft.

TechnologieUrteil
Rust
JavaScript
TypeScript
Typeshare
WASM

Frontend-Hosting

Meine anfängliche Entscheidung, “voll auf Solid zu setzen”, wurde stark von der Tatsache beeinflusst, dass Netlify den Ersteller von Solid eingestellt hat, um Vollzeit daran zu arbeiten. Netlifys größter Konkurrent ist Vercel. Vercel hat Next.js erstellt und pflegt es. Und ich dachte, Netlify wollte, dass Solid ihr Next.js wird. Daher dachte ich, es gäbe keinen besseren Ort, um eine SolidStart-Site zu hosten, als Netlify.

Standardmäßig versucht Netlify, Sie dazu zu bringen, ihr Build-System zu verwenden. Die Nutzung von Netlifys Build-System macht es sehr schwierig, atomare Deployments durchzuführen. Netlify würde das Frontend trotzdem veröffentlichen, selbst wenn die Backend-Pipeline fehlschlug. Sehr schlecht! Das führte dazu, dass ich das Frontend in derselben CI/CD-Umgebung wie das Backend erstellte und dann einfach die neueste Version mit ihrer CLI zu Netlify hochlud. Als ich den Übergang von SolidStart zu Astro machte, konnte ich das gleiche CI/CD-Setup beibehalten. Astro hat eine native Netlify-Integration.

Bencher konnte für einige Zeit unter dem kostenlosen Netlify-Tarif bleiben. Mit der zunehmenden Popularität von Bencher begannen wir jedoch, einige der kostenlosen Tarife zu überschreiten. Ich habe darüber nachgedacht, die Astro-Site zu sst auf AWS zu verlagern. Die Kosteneinsparungen scheinen jedoch bisher den Aufwand nicht wert zu sein.

TechnologieUrteil
Netlify-Builds
Netlify-Deploys

Backend

Backend-Sprache

Rust.

TechnologieUrteil
Rust

HTTP-Server-Framework

Einer meiner wichtigsten Überlegungen bei der Auswahl eines Rust-HTTP-Server-Frameworks war die eingebaute OpenAPI-Spezifikationsunterstützung. Aus den gleichen Gründen, aus denen ich in die Einrichtung von Typeshare und WASM im Frontend investiert habe, wollte ich die Möglichkeit haben, sowohl API-Dokumentationen als auch Clients automatisch aus dieser Spezifikation zu generieren. Es war mir wichtig, dass diese Funktionalität integriert und kein Drittanbieter-Add-on war. Damit die Automatisierung tatsächlich von Nutzen ist, muss sie fast 100% der Zeit funktionieren. Das bedeutet, dass die Wartungs- und Kompatibilitätslast bei den Kern-Framework-Ingenieuren selbst liegen muss. Andernfalls wird man unweigerlich in Problembereichen mit Randfällen stecken bleiben.

Ein weiterer wichtiger Gesichtspunkt war das Risiko der Aufgabe. Es gibt mehrere einst vielversprechende Rust-HTTP-Frameworks, die jetzt so gut wie aufgegeben sind. Das einzige Framework, das ich fand, das eingebaute OpenAPI-Spezifikationsunterstützung hatte und auf das ich setzen wollte, war Dropshot. Dropshot wurde erstellt und wird weiterhin von Oxide Computer gepflegt.

Bisher hatte ich nur ein größeres Problem mit Dropshot. Wenn ein Fehler vom API-Server generiert wird, führt dies zu einem CORS-Fehler auf dem Frontend aufgrund fehlender Antwort-Header. Das bedeutet, dass das Web-Frontend keine hilfreichen Fehlermeldungen an die Benutzer anzeigen kann. Anstatt an einer Lösung zu arbeiten, konzentrierte ich meine Bemühungen darauf, Bencher einfacher und intuitiver zu gestalten. Es stellt sich jedoch heraus, dass die Lösung weniger als 100 Codezeilen war. Reingefallen!

Nebenbei bemerkt: Das axum-Framework war noch nicht veröffentlicht, als ich anfing, an Bencher zu arbeiten. Wenn es zu der Zeit verfügbar gewesen wäre, hätte ich vielleicht versucht, es mit einem der vielen Drittanbieter-OpenAPI-Add-ons zu kombinieren, trotz besserer Urteilsfähigkeit. Zum Glück war axum noch nicht da, um mich zu versuchen. Dropshot war eine großartige Wahl. Siehe den Abschnitt API-Client für mehr zu diesem Punkt.

TechnologieUrteil
Dropshot

Datenbank

Ich habe versucht, Bencher so einfach wie möglich zu halten. Die erste Version von Bencher nahm alles, einschließlich der Benchmark-Ergebnisse, über URL-Abfrageparameter auf. Ich habe schnell gelernt, dass alle Browser ein Limit für die URL-Länge haben. Das ergibt Sinn.

Dann habe ich in Betracht gezogen, die Benchmark-Ergebnisse in git zu speichern und einfach eine statische HTML-Datei mit den Diagrammen und Ergebnissen zu generieren. Diese Vorgehensweise hat jedoch zwei große Nachteile. Erstens würden die git clone-Zeiten für Intensivnutzer irgendwann untragbar werden. Zweitens müssten alle historischen Daten in der HTML-Datei vorhanden sein, was zu sehr langen initialen Ladezeiten für Intensivnutzer führt. Ein Entwicklerwerkzeug sollte seine Intensivnutzer schätzen, nicht bestrafen.

Es stellt sich heraus, dass es eine Lösung für mein Problem gibt. Sie heißt Datenbank.

Warum also nicht einfach Postgres verwenden und fertig? Nun, ich wollte wirklich, dass die Leute in der Lage sind, Bencher selbst zu hosten. Je einfacher ich die Architektur gestalten konnte, desto einfacher (und günstiger) wäre es für andere, es selbst zu hosten. Ich wollte ohnehin schon zwei Container erfordern, aufgrund des getrennten Frontends und Backends. Könnte ich einen dritten vermeiden? Ja!

Vor Bencher hatte ich SQLite nur als Testdatenbank verwendet. Das Entwicklererlebnis war fantastisch, aber ich hatte nie in Betracht gezogen, es in der Produktion einzusetzen. Dann stieß ich auf Litestream. Litestream ist ein Desaster-Wiederherstellungstool für SQLite. Es läuft im Hintergrund und repliziert kontinuierlich Änderungen zu S3 oder jedem anderen Datenspeicher Ihrer Wahl. Dies macht es einfach zu verwenden und unglaublich kosteneffizient, da S3 keine Gebühren für Schreibvorgänge erhebt. Denken Sie an Pfennigbeträge pro Tag für eine kleine Instanz.

Als ich zum ersten Mal auf Litestream gestoßen bin, gab es auch das Versprechen, dass bald Live-Lese-Replikationen verfügbar sein würden. Dies hat sich jedoch nie verwirklicht. Die vorgeschlagene Alternative war ein Nachfolgeprojekt desselben Entwicklers namens LiteFS. Allerdings gibt es große Nachteile bei LiteFS. Es bietet keine eingebaute Desaster-Wiederherstellung, wenn alle Replikate ausfallen. Um mehrere Replikate zu haben, müssen Sie Ihre Anwendungslogik mit dem Konzept infizieren, ob sie Leser oder Schreiber sind. Und der absolute Showstopper war, dass eine Consul-Instanz ständig laufen muss, um die Replikate zu verwalten. Der gesamte Punkt der Verwendung von SQLite war, einen weiteren Dienst zu vermeiden. Glücklicherweise habe ich nicht versucht, LiteFS mit Bencher Cloud zu verwenden, da LiteFS Cloud ein Jahr nach dem Start eingestellt wurde und LiteFS nun so gut wie tot ist.

Derzeit wird die kurze Ausfallzeit zwischen den Bereitstellungen vom Bencher CLI gehandhabt. In der Zukunft plane ich, auf Bereitstellungen ohne Ausfallzeiten mit Kamal umzustellen. Mit Rails 8.0, das standardmäßig Kamal und SQLite verwendet, fühle ich mich ziemlich zuversichtlich, dass Kamal und Litestream gut zusammenpassen werden.

TechnologieUrteil
URL-Abfrageparameter
git + HTML
SQLite
Litestream
LiteFS

Datenbank-Treiber

Je näher ich an die Datenbank komme, desto stärker typisiert möchte ich die Dinge haben. Es ist in Ordnung, es im Frontend ein wenig locker anzugehen. Wenn ich einen Fehler mache, wird alles mit dem nächsten Push in die Produktion wieder in Ordnung sein. Wenn ich jedoch die Datenbank beschädige, ist es viel schwieriger, das wieder in Ordnung zu bringen. Mit diesem Gedanken im Hinterkopf habe ich mich entschieden, Diesel zu verwenden.

Diesel ist ein stark typisierter objekt-relationaler Mapper (ORM) und Query-Builder für Rust. Es überprüft alle Datenbankinteraktionen zur Kompilierzeit und verhindert Laufzeitfehler. Diese Überprüfung zur Kompilierzeit macht Diesel auch zu einer abstraktionsfreien Lösung über SQL. Abgesehen von einem kleinen Fehler meinerseits, als ich die Dinge 1200x schneller durch Performance-Tuning gemacht habe, hatte ich keine Laufzeit-SQL-Fehler, als ich mit Diesel gearbeitet habe.

🐰 Fun Fact: Diesel verwendet Bencher für kontinuierliches Benchmarking!

TechnologieUrteil
Diesel

Backend-Hosting

Genauso wie ich Netlify für mein Frontend-Hosting gewählt habe, weil ich Solid eingesetzt habe, habe ich Fly.io für mein Backend-Hosting ausgewählt, weil ich Litestream nutzte. Fly.io hatte gerade den Schöpfer von Litestream eingestellt, um Vollzeit daran zu arbeiten. Wie oben erwähnt, wurde diese Arbeit an Litestream schließlich von LiteFS übernommen, und LiteFS ist nun eingestellt. Das hat sich also nicht so entwickelt, wie ich es mir erhofft hatte.

In Zukunft, wenn ich zu Kamal wechsle, werde ich auch Fly.io verlassen. Fly.io hatte ein paar größere Ausfälle, die Bencher jedes Mal für einen halben Tag lahmgelegt haben. Aber das größte Problem ist das Missverhältnis, das durch die Nutzung von Litestream entsteht.

Jedes Mal, wenn ich mich in das Fly.io-Dashboard einlogge, sehe ich diese Warnung:

ℹ Ihre App läuft auf einer einzigen Maschine

Skalieren Sie und führen Sie Ihre App auf mehr Maschinen aus, um hohe Verfügbarkeit mit einem einzigen Befehl sicherzustellen:

fly scale count 2

Sehen Sie sich die Dokumentation für weitere Details zur Skalierung an.

Aber mit Litestream können Sie immer noch nicht mehr als eine Maschine haben! Ihr habt nie die versprochene Lese-Replikation geliefert!

Das ist also alles ein wenig ironisch und frustrierend. Zu einem Zeitpunkt habe ich mich mit libSQL und Turso beschäftigt. Allerdings erfordert libSQL einen speziellen Backend-Server für die Replikation, was bedeutet, dass es nicht mit Diesel funktioniert. So oder so scheint es, als ob ich einem weiteren End-of-Life-Shutdown dort entkommen bin. Ich bin sehr interessiert daran zu sehen, was Turso mit Limbo macht, ihrem Rust-Rewrite von SQLite. Aber ich werde diesen Wechsel nicht so bald vollziehen. Der nächste Halt ist eine nette, langweilige und stabile VM, die Kamal laufen lässt.

Der AWS S3 Backend für die Litestream-Replikation hat einwandfrei funktioniert. Selbst mit dem plötzlichen Kurswechsel rund um Litestream und Fly.io glaube ich immer noch, dass ich die richtige Entscheidung getroffen habe, Litestream mit Bencher zu verwenden. Ich stoße auf einige Skalierungsprobleme mit Bencher Cloud, aber das ist ein gutes Problem zu haben.

TechnologieEntscheidung
Fly.io
AWS S3

Befehlszeilenoberfläche

CLI-Bibliothek

Beim Erstellen einer Rust-CLI ist Clap ein wenig der de facto Standard. Stellen Sie sich also meinen Schock vor, als ich Bencher zum ersten Mal öffentlich vorführte und der Schöpfer selbst, Ed Page, dort war! 🤩

Im Laufe der Zeit entdecke ich immer mehr nützliche Dinge, die Clap tun kann. Es ist ein wenig peinlich, aber ich habe erst kürzlich die default_value-Option entdeckt. All diese Fähigkeiten helfen wirklich, die Menge des Codes zu reduzieren, den ich in der bencher-CLI pflegen muss.

🐰 Fun Fact: Clap verwendet Bencher, um die Binärgröße zu verfolgen!

TechnologieUrteil
Clap

API-Client

Ein entscheidender Faktor bei der Auswahl von Dropshot als Benchers HTTP-Server-Framework war seine eingebaute Möglichkeit, eine OpenAPI-Spezifikation zu generieren. Ich hoffte, eines Tages einen API-Client automatisch aus dieser Spezifikation generieren zu können. Ein Jahr oder so später lieferten die Ersteller von Dropshot: Progenitor.

Progenitor ist das Yin zu Dropshots Yang. Mit der OpenAPI-Spezifikation von Dropshot kann Progenitor einen Rust-API-Client entweder in einem positionsbasierten Muster generieren:

client.instance_create("bencher", "api", None)

oder in einem Builder-Muster:

client.instance_create().organization("bencher").project("api").send()

Persönlich bevorzuge ich Letzteres, und daher verwendet Bencher dieses Muster. Progenitor kann auch ein komplettes Clap-CLI zur Interaktion mit der API generieren. Allerdings habe ich es nicht benutzt. Ich musste die Dinge enger kontrollieren, besonders bei Befehlen wie bencher run.

Der einzige bemerkenswerte Nachteil, den ich bei den generierten Typen festgestellt habe, ist, dass es aufgrund von Einschränkungen im JSON-Schema nicht möglich ist, einfach ein Option<Option<Item>> zu verwenden, wenn man zwischen einem fehlenden item-Schlüssel und einem item-Schlüssel mit dem Wert null unterscheiden muss. Dies ist mit etwas wie double_option möglich, sieht aber auf der Ebene des JSON-Schemas alles gleich aus. Die Verwendung eines abgeflachten oder nicht getaggten inneren Struktur-Enums funktioniert mit Dropshot nicht gut. Die einzige Lösung, die ich gefunden habe, war die Verwendung eines Top-Level nicht getaggten Enums. Es gibt jedoch nur zwei solcher Felder in der gesamten API zu diesem Zeitpunkt, also kein großes Problem.

TechnologieUrteil
Progenitor

Entwicklung

Entwicklerumgebung

Als ich anfing, an Bencher zu arbeiten, forderten die Leute das Ende von localhost. Ich war bereits weit über das Bedürfnis hinaus, einen neuen Entwicklungs-Laptop zu benötigen, also beschloss ich, eine Cloud-Entwicklungsumgebung auszuprobieren. Zu dieser Zeit war GitHub Workspaces für meinen Anwendungsfall noch nicht allgemein verfügbar (GA), also entschied ich mich für Gitpod.

Dieses Experiment dauerte etwa sechs Monate. Mein Fazit: Cloud-Entwicklungsumgebungen funktionieren nicht gut für Nebenprojekte. Möchten Sie schnell fünf Minuten Arbeit erledigen? Nein! Sie werden dabeisitzen und warten, bis Ihre Entwicklungsumgebung sich zum tausendsten Mal neu initialisiert. Oh, Sie haben einen ganzen Nachmittag am Wochenende, um wirklich viel Arbeit zu leisten? Nein! Ihre Entwicklungsumgebung wird einfach zufällig nicht mehr funktionieren, während Sie sie benutzen. Immer wieder und wieder.

Ich stieß auf diese Probleme als zahlender Nutzer. Für 25 $/Monat könnte ich mir alle fünf Jahre ein brandneues M1 MacBook Pro mit viel besseren Spezifikationen leisten. Als Gitpod ankündigte, dass sie ihre Preisgestaltung von einem Festpreis auf eine nutzungsbasierte umstellen würden, ließ ich einfach meinen Plan kündigen und wechselte zu apple.com.

Vielleicht war das alles ein Problem mit Gitpods nun aufgegebener Entscheidung, Kubernetes zu nutzen. Aber ich habe es nicht eilig, mit Bencher erneut eine andere Cloud-Entwicklungsumgebung auszuprobieren. Letztendlich habe ich die Gitpod-Konfiguration in einen Dev-Container portiert, um es Mitwirkenden zu erleichtern, loszulegen. Für mich bleibt es jedoch bei localhost.

TechnologieUrteil
Gitpod
M1 MacBook Pro

Kontinuierliche Integration

Bencher ist Open Source. Als modernes Open-Source-Projekt muss man irgendwie auf GitHub sein. Das bedeutet, dass der Weg des geringsten Widerstands für die kontinuierliche Integration (CI) GitHub Actions ist. Im Laufe der Jahre habe ich begonnen, YAML-basierte CI-DSLs zu verabscheuen. Jede hat ihre eigenen Eigenheiten, und bei einem so großen Unternehmen wie GitHub kann es Jahre dauern, bis ein ⚠️-Symbol anstelle eines ❌-Symbols behoben wird.

Dies motivierte mich dazu, Dagger auszuprobieren. Damals konnte man Dagger nur über diese esoterische Sprache namens CUE verwenden. Ich habe es versucht. Wirklich. Ein ganzes Wochenende lang. Vielleicht hätte ich es geschafft, wenn es damals ChatGPT gegeben hätte. Aber es lag nicht nur an mir. Dagger hat letztendlich CUE aufgegeben zugunsten sinnvollerer SDKs. Zu diesem Zeitpunkt war es für mich jedoch zu spät.

Von Dagger geschlagen, akzeptierte ich mein YAML CI DSL Schicksal, und Bencher nutzt jetzt GitHub Actions. Verdammt, ich habe sogar eine Bencher CLI GitHub Action gebaut. Sei das Change-Problem, das du in der Welt sehen möchtest.

TechnologieUrteil
Dagger
GitHub Actions⚠️

Fazit

Der Aufbau von Bencher hat mir viel über die Kompromisse gelehrt, die mit jeder ingenieurtechnischen Entscheidung einhergehen. Es gibt einige Entscheidungen, die ich heute anders treffen würde, aber das ist gut so. Es bedeutet, dass ich auf dem Weg eine oder zwei Dinge gelernt habe. Insgesamt bin ich sehr zufrieden mit dem aktuellen Stand von Bencher. Bencher hat sich von einer Skizze in meinem Notizbuch zu einem ausgereiften Produkt mit einer wachsenden Benutzerbasis, einer lebendigen Community und zahlenden Kunden entwickelt. Ich bin gespannt, wohin uns die nächsten drei Jahre führen werden!

StapelKomponenteTechnologieUrteil
FrontendFrontend-BibliothekYew
Seed
Sycamore
Elm
SolidJS
Programmiersprache für FrontendRust
JavaScript
TypeScript
Typeshare
WASM
Frontend-HostingNetlify Builds
Netlify Deploys
BackendBackend ProgrammierspracheRust
HTTP Server FrameworkDropshot
DatenbankURL Query Params
git + HTML
SQLite
Litestream
LiteFS
DatenbanktreiberDiesel
Backend-HostingFly.io
AWS S3
CLICLI-BibliothekClap
API-ClientProgenitor
EntwicklungEntwicklungsumgebungGitpod
M1 MacBook Pro
Kontinuierliche IntegrationDagger
GitHub Actions⚠️

Bencher: Kontinuierliches Benchmarking

🐰 Bencher

Bencher ist eine Suite von kontinuierlichen Benchmarking-Tools. Hatten Sie jemals eine Performance Regression, die Ihre Nutzer beeinflusste? Bencher hätte das verhindern können. Bencher ermöglicht es Ihnen, Leistungsregressionen vorher zu erkennen und zu verhindern, bevor sie in die Produktion gelangen.

  • Ausführen: Führen Sie Ihre Benchmarks lokal oder in CI mit Ihren bevorzugten Benchmarking-Tools aus. Das bencher CLI umfasst einfach Ihr vorhandenes Benchmark-Harness und speichert die Ergebnisse.
  • Verfolgen: Verfolgen Sie die Ergebnisse Ihrer Benchmarks im Laufe der Zeit. Überwachen, abfragen und grafisch darstellen der Ergebnisse mit der Bencher Web Konsole auf Basis des Quellzweigs, Testbetts und Maßnahme.
  • Auffangen: Fangen Sie Leistungsregressionen in CI ab. Bencher verwendet modernste, anpassbare Analysen, um Leistungsregressionen zu erkennen, bevor sie in die Produktion gelangen.

Aus denselben Gründen, warum Unit Tests in CI laufen, um Feature Regressionen zu verhindern, sollten Benchmarks in CI mit Bencher ausgeführt werden, um Leistungsregressionen zu verhindern. Performance-Bugs sind Fehler!

Beginnen Sie damit, Leistungsregressionen in CI aufzufangen - probieren Sie Bencher Cloud kostenlos aus.

🤖 Dieses Dokument wurde automatisch von OpenAI GPT-4 generiert. Es ist möglicherweise nicht korrekt und kann Fehler enthalten. Wenn Sie Fehler finden, öffnen Sie bitte ein Problem auf GitHub.