- Das .NET Unified Build-Projekt ist ein neues Build-System, das das gesamte Produkt in Form eines „Virtual Monolithic Repository“ (VMR) zusammenführt, um die Komplexität und Ineffizienz der bisherigen Build-Struktur auf Basis verteilter Repositories zu reduzieren
- Die bisherige verteilte Produktstruktur bietet zwar hohe Unabhängigkeit und Flexibilität, verursacht aber erhebliche Belastungen bei Abhängigkeitsmanagement, Build-Konsistenz und Geschwindigkeit
- Unified Build erweitert die Prinzipien von Source Build für Linux-Distributionen und führt ein einheitliches Source-Layout sowie eine „Vertical Build“-Struktur ein, um Build-Zeiten zu verkürzen und Vorhersehbarkeit zu schaffen
- Durch bidirektionalen Code-Flow (two-way code flow), Szenario-Tests sowie Verbesserungen bei automatischer Validierung und Signatur-Infrastruktur werden sowohl die Effizienz der Entwickler als auch die Produktqualität gesteigert
- Das mit .NET 10 offiziell eingeführte System hat konkrete Ergebnisse erzielt, darunter verkürzte Build-Zeiten (24 Stunden → unter 7 Stunden), geringere Wartungskosten und höhere Zuverlässigkeit bei der Auslieferung
Hintergrund des Wandels in der .NET-Build-Struktur
- Im Zuge der Open-Source-Umstellung von .NET in den Jahren 2015–2016 wurde die Entwicklung auf zahlreiche Repositories wie CoreCLR, CoreFX, ASP.NET Core und SDK aufgeteilt
- Jedes Repository wurde unabhängig gebaut und ausgeliefert, während das Gesamtprodukt über einen Abhängigkeitsgraphen zusammengesetzt wurde
- Dieser Ansatz ähnelt dem OSS-Ökosystem, führt aber bei Sicherheits-Patches oder dringenden Fixes dazu, dass mehrere Teams gleichzeitig koordiniert werden müssen, wodurch der Zeitaufwand unvorhersehbar wird
- Trotz der Vorteile verteilter Entwicklung (Layering, Aufspaltung der Community, asynchrone Entwicklung usw.) ist sie bei der Sicherstellung von Produktkohärenz ineffizient
Komplexität der Produktzusammensetzung und Overhead
- Komplexität (Complexity): definiert als die Anzahl der Schritte, die nötig sind, bis eine Änderung beim Kunden ankommt
- Je mehr Repositories und Abhängigkeitsknoten es gibt, desto mehr Zeit und personelle Abstimmung sind nötig, um Konsistenz sicherzustellen
- Overhead: Zeit, die nicht direkt für die Erstellung von Ergebnissen aufgewendet wird, die an Kunden ausgeliefert werden können
- Beispiele: Erstellen von PRs, Warten auf Genehmigungen, Queueing, Umgebungssetup
- Die Analyse des Runtime-Builds von .NET 8 zeigte, dass rund 38,5 % der gesamten Build-Zeit auf Overhead entfielen
- Wenn Komplexität und Overhead zusammenkommen, sinkt die Build-Effizienz stark, und der gesamte Release-Zyklus verlängert sich
Ursprung von Source Build und Unified Build
- Source Build ist ein System, das dafür entwickelt wurde, dass Linux-Distributionen .NET offline aus einer einzigen Quelle bauen können
- Prinzipien: eine Implementierung, eine Plattform, eine Build-Umgebung
- Ein Build-Orchestrator verwaltet die Abhängigkeiten und die Build-Reihenfolge der einzelnen Komponenten
- Source Build kann aufgrund geringer Komplexität und geringen Overheads in unter 50 Minuten gebaut werden
- Microsoft wollte dieses Konzept auch auf interne Builds anwenden, stieß jedoch auf Schwierigkeiten durch Closed Source, Legacy-Abhängigkeiten und plattformübergreifende Joins
- Um diese Probleme zu lösen, wurden Ansätze wie reference-only packages (
source-build-reference-packages), das Prinzip einer einzigen Implementierung und die Eliminierung von Joins eingeführt
Ziele und Design von Unified Build
- Das gesamte .NET-Produkt soll mit einem einzigen Commit gebaut werden können
- Alle plattformspezifischen Distributionen sollen in einer einzigen Umgebung erzeugt werden
- Unabhängiger Build und unabhängige Validierung sollen auch außerhalb von Microsoft möglich sein
- Bidirektionaler Code-Flow sorgt für die automatische Synchronisierung von Änderungen zwischen VMR und einzelnen Repositories
- Über Szenario-Tests wird die Funktionalität auf Ebene des Gesamtprodukts validiert
- Die Vertical Build-Struktur parallelisiert plattformspezifische Builds
- Sie besteht aus etwa 35–40 Build-Vertikalen (short/tall stack)
Umsetzungsphasen von Unified Build
- .NET 7: Konzeption und Freigabe
- .NET 8: Verbesserung der Source-Build-Infrastruktur und Aufbau der Grundlagen
- .NET 9: Experimente mit Vertical Build und Code-Flow
- .NET 10: Offizielle Produktivsetzung und Übernahme in RTM
- In Preview 4 wurde der neue Build-Prozess eingeführt, ab Preview 5 erfolgte die vollständige Umstellung
Zentrale Komponenten
Virtual Monolithic Repository (VMR)
- Das Repository dotnet/dotnet dient als einheitliches Source-Layout für alle Komponenten
- Entwickler können entweder in einzelnen Repositories oder im VMR arbeiten und erhalten so die Flexibilität verteilter Entwicklung und die Konsistenz eines Monorepos zugleich
Vertical Build
- Für jede Plattform und jede Runtime wird ein unabhängiger Build ausgeführt
- Nach parallelen Builds werden die Ergebnisse zusammengeführt; einige Joins werden in zusätzlichen Build-Pässen verarbeitet
Code Flow
- Bidirektionale Code-Synchronisierung: Komponenten-Repository → VMR, VMR → Komponenten-Repository
- Der letzte Status des Code-Flows wird in
eng/Version.Details.xml festgehalten
- Änderungen werden als Patch-Dateien erzeugt, um automatisch PRs zu erstellen
- Logik zur Behandlung von Konflikten und zur Fehlerbehebung ist integriert
Scenario Test Validation
- Zusätzlich zu bestehenden Unit-Tests werden Szenario-Tests hinzugefügt, die die Gesamtfunktionalität des Produkts validieren
- Sie laufen auf Basis der Build-Artefakte und stärken so Regressionsschutz und Qualitätssicherung
Ergebnisse und Auswirkungen
- Verkürzte Build-Zeiten: mehr als 24 Stunden → unter 7 Stunden (einschließlich Signierung)
- Höhere Flexibilität: kürzere Build- und Auslieferungszyklen, einfachere Umsetzung dringender Fixes
- Mehr Vorhersehbarkeit: klarer Zeitpunkt, wann der Build nach einer Änderung abgeschlossen ist
- Verbesserte Infrastruktur: Signierungs-Tools, Logs, parallele Builds, Automatisierung des Abhängigkeitsflusses usw.
- Auch Source Build für Linux-Distributionen bleibt jederzeit in einem sauberen Zustand vor dem Build
Ausblick
- Mit .NET 11 ist die Einführung von automatisiertem Code-Flow und AI-basierten Monitoring-Agenten geplant
- Die Verfolgung von Fehlern im Prozess von PR bis zur Produktübernahme soll automatisiert werden
- Langfristig soll durch die Beseitigung von Join-Punkten der Build weiter vereinfacht und beschleunigt werden
- Ziel: vollständiger Build in unter 4 Stunden
Fazit
- Das Unified Build, das die Grenzen des verteilten Build-Modells überwindet, verbessert die Effizienz von Build und Auslieferung bei .NET grundlegend
- Es wurden konkrete Fortschritte in drei Bereichen erzielt: weniger Komplexität und Overhead, mehr Konsistenz, Geschwindigkeit und Qualität
- Seit .NET 10 RTM wird dieses System vollständig eingesetzt und soll in künftigen Versionen kontinuierlich weiter verbessert werden
1 Kommentare
Hacker-News-Kommentare
Ich habe wirklich großen Respekt vor dem .NET-Team
Sie veröffentlichen regelmäßig tiefgehende technische Artikel, und ihre Besessenheit von Performance-Optimierung ist beeindruckend (z. B. Kestrel, die Entwicklung von Entity Framework)
ASP.NET ist eines der wenigen großen Projekte, das selbst einen Umbruch in der Größenordnung von Python 2→3 überlebt hat
Früher war man für die Sitzungssynchronisierung auf magisch wirkende Funktionen angewiesen, heute funktioniert das auf eine völlig andere Weise
Es fühlt sich gut an, dass ein 3-Billionen-Dollar-Unternehmen den von mir genutzten Stack ernsthaft verbessern will
Also habe ich es durch Dapper und ein selbst gebautes Migrationssystem ersetzt, und dadurch sank die Zeit für DB-Validierung und Seeding beim Start von 10 Sekunden auf unter 2 Sekunden (auf schwacher Hardware + mit SQLite)
Die von Entity erzeugten Queries enthielten viele unnötige mehrfache Joins
In letzter Zeit steige ich auf ein einfaches Go-Backend um und nutze .NET nur noch für andere Lösungen
Frameworks wie WPF hatten so viele Probleme, dass man Win32-Hacks brauchte
Zum Beispiel liefert erst .NET 9 endlich alle Netzwerkschnittstellen korrekt zurück. Frühere Runtimes zeigten nur aktive NICs an
Es gibt immer noch Projekte, die Windows-7-Unterstützung beibehalten müssen
Selbst bei neuen Projekten muss man manchmal noch .NET 4.8 verwenden. Zum Beispiel tritt beim Erstellen von Excel-Formeln ein async/await-Deadlock-Problem auf
Außerdem ist die Windows-Integration kaputt, sodass derselbe Netzwerkaufruf unter 4.8 authentifiziert wird, unter Core aber fehlschlägt
Wegen des Zusammenbruchs der Abwärtskompatibilität in zahllosen Bibliotheken ist eine Migration nicht einfach
Die Performance wurde besser, aber funktional wirkt .NET Framework wie ein Fossil
Es hat 15 Jahre gedauert, bis ein JSON-Serializer in die Standardbibliothek aufgenommen wurde, und Unterstützung für moderne Bildformate wie webp oder heic gibt es ebenfalls nicht
Visual Studio zeigt praktisch jeden Tag Absturzmeldungen an
Früher war ich ein glühender .NET-Fan, aber ich vermisse Anders' Führung
In einem Side-Project habe ich vor Kurzem ein C#-REST-API-Backend in VSCode auf macOS entwickelt und deploye es nun seit drei Jahren unter Linux
Ich nutze SQLite, EFCore und Minimal API, und es ist deutlich angenehmer als das Frontend (NextJS/React/MaterialUI, mehr als 50 npm-Pakete)
Das ist persönlich mein Lieblings-API-Framework
Die zweitbeste Wahl wäre für mich die Kombination aus TS + Hono + Zod-OpenApi + SwaggerUI, aber das Einrichten des Typkontexts ist etwas umständlich
Beeindruckend fand ich, dass die Grundlage für die Open-Source- und Cross-Platform-Ausrichtung von .NET das Build-System von Linux-Distributionen war
Deshalb brauchten wir ein Build-System, das ihre Anforderungen erfüllt, und am Ende war die Integration in das Modell der Linux-Distributionen der einzige gangbare Weg
Dieses Modell ist simpel, aber in der Performance schwächer. Ein verteiltes Build-System mit Caching wäre schneller, passt aber nicht zum Workflow der Maintainer
Wir kamen zu dem Schluss, dass die Optimierung auf Einfachheit besser geeignet ist, um Beiträge aus der Community zu fördern
Ziel ist es, dass die Community selbst Builds und Auslieferung für verschiedene Plattformen wie BSD, S390x usw. übernehmen kann
Die Menge an Pull Requests und positiven Ergebnissen der letzten zehn Jahre ist wirklich erstaunlich
Ich hätte nicht gedacht, dass der beeindruckendste Software-Engineering-Artikel dieses Jahres von Microsoft kommen würde
Ich mag die neueren Versionen von .NET, hatte ihre Robustheit aber eher für ein Zufallsprodukt gehalten
Dieser Artikel zeigt jedoch systematische Bemühungen zur Qualitätsverbesserung (einschließlich Diagrammen und Beispielen für den Einsatz von LLMs)
Selbst wenn solche Investitionen künftig zurückgehen sollten, ist das ein gutes Beispiel dafür, „wie man es machen sollte“
Die Leute, die an diesem Projekt beteiligt waren, müssen wirklich eine großartige Erfahrung gemacht haben
Der Artikel war gut, aber ich finde, das .NET-Team sollte Azure DevOps aufgeben
Wartezeiten in der Queue sind der größte Engpass. Sie sollten Bare-Metal-Build-Server betreiben
Mac-Hardware wird schnell verbunden und gestartet
Wir starten für jeden Job eine neue saubere VM, um Compliance und Stabilität sicherzustellen
Man könnte vorbereitete Hot-Machines vorhalten, um Wartezeiten zu beseitigen, aber die Kosten wären zu hoch
Da es praktisch kaum möglich ist, verschiedene SKUs ständig in Bereitschaft zu halten, gehen wir diesen Kompromiss ein
Ich frage mich, warum Microsofts Developer Division zur absoluten Spitze der Branche gehört, während der Rest des Unternehmens zum Symbol für Inkompetenz und Bürokratie geworden ist
Seit Bill weg ist, gibt es keine Kultur der Selbstreflexion mehr
Ich denke, die abstraktionszentrierte Denkweise, die komplexe Systeme vereinfachen will, ist die Wurzel des Problems
Statt alles auf höherer Ebene lösen zu wollen, kann ein Ansatz, der von den unteren Ebenen aus aufgebaut wird, viel mehr Probleme grundlegend beseitigen
Als ich den Satz las „Wir bauen pro Monat 3 bis 4 Major-Versionen und Dutzende SDK-Bänder“, fragte ich mich, warum es so viele Varianten gibt
Außerdem werden für jede Version SDK/aspnet/runtime für verschiedene Plattformen wie x64/arm32/arm64 und Linux/macOS/Windows gebaut
Bevor Node populär wurde, war .NET eine solide Wahl für Backend-Builds (auch performanter als Node)
Nach den jüngsten Supply-Chain-Angriffen im Node-Ökosystem hoffe ich, dass viele Entwickler wieder auf stabile Plattformen zurückkommen
Der große Umbruch war der Wechsel zu .NET Core, aber das ist fast zehn Jahre her
Updates des Frameworks und der Abhängigkeiten sind etwas lästig, aber im Vergleich zu React-Projekt-Updates deutlich einfacher
Dank des kurzen LTS-Zyklus ist es nicht schwer, auf dem neuesten Stand zu bleiben. In schnellen Entwicklungszyklen ist solche Wartung ganz normal
In der Realität dreht sich aber vieles um Node.js, Java und Low-Code (iPaaS)
Trotzdem bietet sich dank Performance-Problemen gelegentlich die Chance, C++-Add-ons vorzuschlagen