Xircuit Blog

Produkt-Updates, Entwickler-Logs und Neuigkeiten aus der Entwicklung von Xircuit.

Multi-Plattform-Finish — und wo wir heute stehen cover image

Multi-Plattform-Finish — und wo wir heute stehen


Multi-Plattform-Finish — und wo wir heute stehen

Mehrere Geräte als Sinnbild für Multi-Plattform Foto: Rawpixel (CC0 1.0), via Openverse

Es gibt Wochen, in denen die spannendste Arbeit unsichtbar bleibt. Kein neues Feature auf dem Bildschirm, keine neue Seite in der App — sondern ein Build, der plötzlich nicht mehr eine Dreiviertelstunde braucht, sondern ein paar Minuten. Genau so eine Woche war diese. Und weil es zugleich der letzte Beitrag dieser wöchentlichen Serie ist, will ich beides tun: den Feinschliff erklären, der Xircuit auf iOS und Mac zurückgebracht hat, und dann kurz zurücktreten und schauen, was in einem halben Jahr eigentlich entstanden ist.

Der Anlass war praktisch. Über Wochen hatte sich ein stiller Kostenpunkt in unsere Release-Pipeline geschlichen, der jedes Mal Zeit und Geld fraß, ohne dass irgendjemand ihn bewusst wahrnahm. Ihn zu beseitigen war weniger ein Feature als eine Aufräumaktion — aber eine, die genau die Art von Reibung wegnimmt, die ein Projekt langfristig ausbremst.

Der stille Kostenpunkt im iOS-Build

Ein Release-Build für iOS hatte bisher eine unangenehme Eigenschaft: Er musste jede einzelne Assembly für arm64 vorab kompilieren, also klassisch Ahead-of-Time. Das ist der Preis dafür, dass Apple auf dem Gerät keinen Just-in-Time-Compiler zulässt — der Code muss fertig übersetzt vorliegen. In der Theorie ist das sauber. In der Praxis war es ein stiller, teurer Schritt von rund 39 Minuten, jedes Mal.

Besonders weh tat das, weil dieser Schritt auf den macOS-Runnern lief, und die werden in den meisten CI-Abrechnungsmodellen mit dem Zehnfachen der Linux-Minuten berechnet. 39 Minuten AOT sind damit nicht 39 Minuten, sondern effektiv fast 400. Für einen Build, der am Ende ein IPA produziert, das sich in nichts von dem unterscheidet, was ein schnellerer Weg liefern würde. Ich habe eine Weile weggeschaut, weil AOT eben der Standardweg ist — bis klar wurde, dass es einen anderen Weg gibt, den Apple ausdrücklich erlaubt.

Der Mono-Interpreter als Ausweg

Die Lösung heißt Mono-Interpreter, und die Idee dahinter ist elegant. Statt jede Assembly vorab zu übersetzen, hält der Interpreter nur einen minimalen Kern AOT-kompiliert und interpretiert den Rest zur Laufzeit. Das ist App-Store-konform, weil kein Code zur Laufzeit erzeugt wird — er wird nur interpretiert, nicht kompiliert. Und der Build wird dadurch drastisch billiger: aus rund 39 Minuten werden wenige Minuten.

Der Kompromiss ist ehrlich zu benennen: Interpretierter Code läuft langsamer als vollständig AOT-übersetzter. Für eine App wie Xircuit, deren Hotpaths im Netzwerk, in der Datenbank und in der Blazor-Hybrid-Renderschicht liegen und nicht in engen Rechenschleifen, ist das ein Kompromiss, den man kaum spürt. Wir tauschen ein bisschen Laufzeit-Performance gegen eine Größenordnung schnellere und günstigere Builds — und gewinnen damit vor allem die Freiheit, öfter und ohne schlechtes Gewissen zu releasen.

Eine Lektion aus einem echten Release

Bei Mac Catalyst wurde es dann kurz unangenehm, und die Lektion war lehrreich genug, dass ich sie hier festhalten will. Ein Catalyst-Build produziert ein Universal-Bundle, das zwei Architektur-Slices vereint: x64 für Intel-Macs und arm64 für Apple Silicon. Beide werden separat gebaut und am Ende zu einem einzigen Binary zusammengeführt.

Der Haken: Der Interpreter muss auf beiden Slices aktiv sein. Aktiviert man ihn nur auf einem, unterscheiden sich die Laufzeit-Konfigurationen der beiden Slices — und der Merge zum Universal-Bundle scheitert, weil er zwei inkompatible Runtime-Setups zusammenzwingen soll. Das ist keine Theorie, sondern eine Beobachtung aus einem realen Release-Durchlauf. Die Korrektur war am Ende klein — den Interpreter konsequent für x64 und arm64 setzen — aber sie zu finden hieß, den Bundle-Merge Schritt für Schritt zu verstehen. Solche Details stehen in keinem Tutorial, und genau deshalb landen sie in einem Dev-Log.

Ein Gipfel als Sinnbild für einen Meilenstein Foto: Hoach Le Dinh · StockSnap (CC0 1.0), via Openverse

Das Abschluss-Release

Mit dem schnellen Build im Rücken konnte das Abschluss-Release das tun, was ein gutes Release tun soll: alles Liegengebliebene in einem sauberen Schnitt ausliefern. iOS und macOS kamen damit zurück auf TestFlight — nach einer Phase, in der die Apple-Ziele aus Build-Kostengründen hinten runtergefallen waren, ist das ein spürbarer Schritt. Dazu ging die Marketing-Matrix live, jene Sammlung branchenspezifischer Seiten, an der wir in den Vorwochen gebaut hatten, ebenso wie die Gesundheits- und Zutritts-Funktionen, die zuvor schon fertig, aber noch nicht in aller Breite deployt waren.

Ein Release, das mehrere Wochen Arbeit bündelt, ist immer ein kleiner Nervenkitzel — viele bewegliche Teile, eine Pipeline, ein grünes oder rotes Ergebnis am Ende. Dass diesmal die Apple-Jobs in Minuten statt in einer Dreiviertelstunde durchliefen, hat den ganzen Durchlauf entspannter gemacht. Es war das erste Release, das den neuen Build-Weg unter echten Bedingungen bestätigt hat, und nicht nur in einem lokalen Testlauf.

Ein halbes Jahr, zurückgeblickt

Wenn ich von hier aus zurückschaue, wird der Bogen dieser Serie sichtbar. Am Anfang stand das Fundament: eine einzige Codebase auf Basis von .NET 10 und Blazor Hybrid, orchestriert über .NET Aspire, deployt auf Azure. Darauf kamen, Woche für Woche, die Schichten, die aus einem Gerüst ein Produkt machen.

Zuerst die echten Gesundheitsintegrationen — nicht als Demo, sondern als Anbindung an reale Datenquellen, mit allem, was Gesundheitsdaten an Sorgfalt bei Datenschutz und Sicherheit verlangen. Dann die Abrechnung, die ein Produkt erst tragfähig macht, samt der Möglichkeit, dass Organisationen ihre eigenen Mitglieder abrechnen. Danach der Support, weil eine Plattform ohne einen Weg, Menschen zu helfen, unvollständig bleibt. Und schließlich die Zutrittssteuerung, der Schritt aus der reinen Software-Welt hinaus zu echten Türen und realer Hardware. Dazu kam die Marketing-Ebene, die all das nach außen erklärt.

Nach einem halben Jahr steht damit mehr als eine App. Es steht ein Fundament: sieben Branchen, echte Gesundheitsintegrationen, Abrechnung, Support, Zutritt — getragen von einer Codebase und ausgeliefert auf sechs Plattformen. Dass Web, Windows, macOS, iOS, iPadOS und Android aus demselben Code kommen, war von Anfang an die Wette dieses Projekts. Der schnelle iOS-Build dieser Woche ist im Grunde die letzte fehlende Bestätigung, dass diese Wette aufgeht, ohne dass die Apple-Plattformen zum Sonderfall werden.

Ich schreibe das ohne Pathos und ohne den Eindruck erwecken zu wollen, alles sei fertig. Vieles läuft noch hinter Feature-Flags, manches ist auf echter Hardware noch zu verifizieren, und die Liste der Dinge, die besser werden können, ist lang. Aber ein Fundament unterscheidet sich von einem Prototyp genau darin, dass man darauf weiterbauen kann, ohne es vorher wieder einzureißen. An diesem Punkt sind wir angekommen.

Was kommt als Nächstes?

Damit endet die wöchentliche Relaunch-Serie — der Dev-Log geht weiter, wenn es das nächste große Stück zu erzählen gibt.


Kommentare

Noch keine Kommentare. Teilen Sie als Erste(r) Ihre Gedanken!

Kommentar hinterlassen