Je länger man an einem Anwendung arbeitet desto eher steigt auch die Projektanzahl in der Solution an – Solutions mit 80 Projekten sind keine Seltenheit. Allerdings merkt man das selbst Visual Studio zum Teil damit kämpft und die Performance nicht ideal ist.
Was macht man mit den ganzen Projekten?
Man erstellt natürlich nicht sinnlos irgendwelche Projekte, sondern der Kerngedanke ist das man bestimmte Komponten einfach kapseln und wiederverwenden kann. Der Grundgedanke ist daher nicht verkehrt.
Aber man arbeitet selten an allen Komponenten gleichzeitig, oder?
Hier kommt der Punkt der mich am meisten stört: Natürlich arbeitet man meist nicht an allen Komponenten/Projekten gleichzeitig – zum Teil können Projekte nur Schnittstellendefinitionen enthalten, welche in der Regel nicht ständig verändert werden.
Und trotzdem sind sie die ganze Zeit in der Solution drin…
Da man die einzelnen Komponenten einfach in der Solution untereinander referenziert werden oftmals völlig unnötige Build-Schritte gemacht.
Was könnte man dagegen machen?
Idee: NuGet – Packages als Ersatz für Projekt Referenzen
NuGet gibt es schon eine ganze Weile – allerdings nutzt man es zumeist nur für 3rd Party Libraries (jedenfalls geht es mir so) . Aber natürlich könnte man NuGet – Packages auch für die eigenen Komponenten nehmen. Schauen wir uns das Konzept mal in einer Demo-Anwendung an:
Wir haben eine “Haupt-Anwendung” und eine Assembly die irgendwelche Business-Logik enthält. Nun möchten wir hier aber nicht direkt das “Business”-Projekt referenzieren.
Wie erzeugt man ein NuGet Package?
Ich selber habe auch noch nicht selbst viele NuGet Packages erstellt – meist habe ich es einfach nur als normaler Anwender genutzt, daher ist dies als “prototypische Implementierung” zu verstehen ;) Erster Einstiegspunkt wäre die NuGet Doku.
Wichtigstes Tool ist NuGet.exe (die aktuelle Version ist in der Doku verlinkt). Über das Tool kann man NuGet Packages erstellen, updaten und eine ganze Liste weitere Dinge machen:
Die NuGet.exe kann man auch nach belieben kopieren und ausführen wo man möchte.
Ein Package erzeugen geht über den Aufruf “pack” mit der Angabe der Projektdatei (csproj):
NuGet.exe pack Business\Business.csproj -build -Outputdirectory ..\NugetShare\ –Version 1.2.3.4
Kurze Erläuterung:
Wir geben hier den Pfad zur csproj Datei an und über –build wird das Projekt nochmal explizit gebaut. Danach folgt der Ausgabeort des NuGet Packages und am Ende ein Versionsnummer, welche für NuGet wichtig ist.
Als Ergebnis bekommen wir dies in der Kommandozeile zu sehen:
Da wir als Basis eine Projektdatei und kein NuGet Spec File nutzen fehlen ein paar Meta-Daten – daher auch die Warnungen. Über das Spec File könnte man wesentlich interessantere Szenarien abdecken – hier ging es aber erst einmal nur um das referienzieren von einer Assembly.
Der NuGet.exe Output
Das Tool erzeugt am Ende ein .nupkg, welche alles enthält:
Wer genauer in ein .nupkg reinschauen will benötigt den NuGet Package Explorer:
Eigenen NuGet Feed in Visual Studio einbinden
Damit Visual Studio unsere NuGet Packages auch kennt muss dieser in den Optionen hinterlegt werden:
Das NuGet Package nutzen
Ähnlich wie ich auch von NuGet.org die Packages lade, kann ich jetzt einfach von dem Verzeichnis aus die Komponente in das Haupt-Projekt importieren (und damit referenzieren).
In diesem Fall wird mir ein Update angeboten, da ich bereits eine ältes Package installiert habe.
Kann man das Package debuggen?
In meinem Demo konnte der Debugger die Assembly, welche aus dem NuGet Package kam zu dem entsprechenden Projekt zuordnen:
Ob dies in jedem Fall geht muss man allerdings überprüfen. Bislang sieht es aber recht vielversprechend aus.
Was haben wir jetzt als Ergebnis?
Wir haben eine Haupt-Anwendung und eine Komponente, welche nur durch das NuGet Package miteinander verbunden sind. Natürlich ist die Assembly (von dem NuGet Package) in den Referenzen drin, aber es gibt keine direkte Build-Dependency:
Bei einem “Rebuild” der MainApp wird auch nur das Projekt gebaut – hier vermeidet man das man die Business-Schicht immer mit baut.
Welche Nachteile ergeben sich?
Die Denkweise von “Referenzen” zu “Packages” ist eine Umstellung und es lohnt sich vermutlich erst wirklich bei großen Solutions. Wenn man ohnehin wirklich ständig an allen Assemblies Veränderungen durchführt ist das natürlich ungünstig.
Auch muss man sich ein Konzept für die NuGet Version überlegen. SemVer.org ist hier ein gutes Stichwort.
Man benötigt im Team irgendwo ein Share auf dem das gesamte Team zugreifen kann und dieser Share sollte auch stabil zur Verfügung stehen. Es gibt noch andere Wege einen NuGet Feed zu hosten – aber ein File-Share ist die einfache Möglichkeit. Wer einen direkten Dienst benutzen möchte (also ein privates NuGet.org) der auch ein Blick auf MyGet.org werfen (NuGet as a Service).
Damit das ganze Spass macht, sollte man vermutlich auch ein Build-System haben und sich ein vollständigen Workflow überlegen. Hier ein paar Fragen die mir spontan einfallen:
- Wann baut man die Komponente mit welcher Version?
- Wer startet diesen Prozess?
- Wie sieht das Testing aus? Gibt es hier eine Art Freigabe-Prozess?
- Version der Assembly = NuGet Package Version?
- Assemblies signieren – geht danach das Debugging noch?
NuGet einzuführen bringt Komplexität mit sich – aber ein +100 Projekte umfassende Solution ist auch nicht gerade wartbar ;)
Gute Idee? Schlechte Idee?
Vermutlich haben schon einige ein ähnliches System auf Basis von NuGet im Einsatz. Falls jemand aus der Community Erfahrungen mit “Inhouse-NuGet-Packages” hat, kann er dies gern über einen Kommentar weitergeben.