Planen von Buildabhängigkeiten für Ihre Pipeline
In dieser Lerneinheit erfahren Sie, wie Sie Code verpacken, damit er leichter freigegeben werden kann. Sie erfahren, warum Sie Pakete erstellen sollten, welche Arten von Paketen Sie erstellen können, wo Sie die Pakete hosten können und wie Sie auf sie zugreifen können, wenn sie gehostet werden. Außerdem erfahren Sie mehr über die Versionsverwaltung für Pakete.
Codebasen werden immer größer und komplexer. Es ist ungewöhnlich, dass ein Team den gesamten Code schreibt, den seine App verwendet. Stattdessen schließt das Team vorhandenen Code ein, der von anderen Entwickler*innen geschrieben wurde. In einer App können viele solcher Pakete oder Abhängigkeiten vorhanden sein. Es ist wichtig, diese Abhängigkeiten aktiv zu verwalten, um sie richtig zu pflegen und sicherzustellen, dass sie den Sicherheitsanforderungen entsprechen.
Zunächst erkundigen Sie sich, wie das Team vorankommt. Andy hat das Team zusammengerufen, um über eine mögliche Änderung ihres Codes zu sprechen, die einem anderen Team helfen würde.
Teambesprechung
Andy: Hallo zusammen. Ich habe mich mit dem Team unterhalten, das am Back-End-System für Space Game arbeitet. Sie könnten die Modelle, die wir für die Website verwenden, in einer Back-End-App nutzen, die sie schreiben möchten.
Amita: Was meinen Sie mit Modellen?
Andy: Wie Sie wissen, ist die Space Game-Website eine ASP.NET Core-Anwendung. Sie verwendet das MVC-Muster (Model View Controller), um Daten von der Darstellung dieser Daten auf der Benutzeroberfläche zu trennen. Ich dachte, wir könnten ein Paket erstellen, das unsere Modellklassen enthält, sodass jede App sie verwenden kann.
Amita: Was genau ist das Ziel?
Andy: Unsere beiden Teams teilen sich dieselbe Datenbank. Das Spiel sendet die Bestenpunktzahlen an die Datenbank. Wir lesen diese Punktzahlen aus, um sie in der Bestenliste anzuzeigen.
Amita: Das ist sinnvoll. Wie werden wir dieses Paket erstellen?
Andy: Aus diesem Grund wollte ich mit Ihnen reden. Wir haben einige Optionen und ich suche nach Ideen.
Tim: Ich würde gerne helfen, aber zuerst habe ich ein paar Fragen. Ich bin neu auf diesem Gebiet und möchte verstehen, wie das Ganze funktioniert.
Was ist ein Paket?
Ein Paket enthält wiederverwendbaren Code, den andere Entwickler in ihren eigenen Projekten verwenden können, auch wenn sie ihn nicht selbst geschrieben haben.
Bei kompilierten Sprachen enthält ein Paket in der Regel den kompilierten Binärcode, z. B. DLL-Dateien in .NET oder CLASS-Dateien in Java. Bei Sprachen, die nicht kompiliert, sondern interpretiert werden, wie JavaScript oder Python, kann ein Paket auch Quellcode enthalten.
In beiden Fällen werden Pakete typischerweise im ZIP- oder einem ähnlichen Format komprimiert. Paketsysteme definieren oft eine eindeutige Dateierweiterung, z. B. .nupkg oder .jar, um die Verwendung des Pakets zu verdeutlichen. Die Komprimierung kann dazu beitragen, die Zeit zum Herunterladen zu verkürzen. Zudem erzeugt sie eine einzelne Datei, um die Verwaltung zu vereinfachen.
Pakete enthalten oft auch eine oder mehrere Dateien mit Metadaten oder Informationen zum Paket. Diese Metadaten könnten die Aufgabe des Pakets beschreiben, seine Lizenzbedingungen, die Kontaktinformationen des Autors sowie die Version des Pakets enthalten.
Warum sollte ich ein Paket erstellen?
Es hat Vorteile, ein Paket zu erstellen, anstatt den Code zu duplizieren.
Ein Grund, ein Paket zu erstellen, anstatt Code zu duplizieren, ist die Vermeidung von Datendrift (Abweichungen). Wenn Code dupliziert wird, können die einzelnen Kopien schnell davon abweichen, um die Anforderungen einer bestimmten App zu erfüllen. Es wird schwierig, Änderungen von einer Kopie zu den anderen zu migrieren. Mit anderen Worten: Sie verlieren die Möglichkeit, den Code so zu verbessern, dass alle davon profitieren.
Pakete gruppieren auch verwandte Funktionen in einer einzelnen wiederverwendbaren Komponente. Je nach Programmiersprache kann ein Paket Apps den Zugriff auf bestimmte Typen und Funktionen ermöglichen, während der Zugriff auf deren Implementierungsdetails eingeschränkt wird.
Ein weiterer Grund, ein Paket zu erstellen, ist die Bereitstellung einer konsistenten Methode zum Erstellen und Testen der Funktionalität dieses Pakets. Wenn Code dupliziert wird, kann jede App diesen Code auf unterschiedliche Weise erstellen und testen. Ein Testsatz könnte Checks enthalten, der für einen anderen Testsatz von Nutzen sein könnte.
Ein Nachteil ist, dass Sie mit einem Paket eine weitere Codebasis erhalten, die Sie testen und verwalten müssen. Sie müssen auch beim Hinzufügen von Features vorsichtig sein. Im Allgemeinen sollte ein Paket Features enthalten, von denen viele Arten von Apps profitieren. Json.NET ist z. B. ein beliebtes NuGet-Paket für .NET, in dem Sie mit JSON-Dateien arbeiten können. Json.NET ist Open Source, sodass die Community Verbesserungen vorschlagen und Probleme melden kann.
Wenn mehrere Apps von demselben Code profitieren können, überwiegen die Vorteile bei weitem die Nachteile. Sie müssen nur eine Codebasis, einen Satz von Tests und nur einen Buildprozess verwalten.
Wie kann ich Abhängigkeiten identifizieren?
Wenn das Ziel darin besteht, Ihren Code in einzelne Komponenten neu anzuordnen, müssen Sie die Teile Ihrer App identifizieren, die entfernt, zur Wiederverwendung verpackt, an einem zentralen Speicherort gespeichert und versioniert werden können. Vielleicht möchten Sie sogar Ihren eigenen Code durch Komponenten von Drittanbietern ersetzen, die entweder Open Source sind oder die Sie lizenzieren.
Es gibt viele Möglichkeiten, um die potenziellen Abhängigkeiten in Ihrer Codebasis zu identifizieren. Dazu gehören das Überprüfen Ihres Codes auf Wiederverwendungsmuster sowie das Analysieren der Architektur Ihrer Lösung. Hier folgen einige Möglichkeiten, um Abhängigkeiten zu identifizieren:
Doppelter Code.
Wenn bestimmte Codeabschnitte an mehreren Stellen verwendet werden, ist dies ein guter Hinweis darauf, dass Sie den Code wiederverwenden können. Zentralisieren Sie diese doppelten Codeabschnitte, und verpacken Sie sie entsprechend neu.
Hohe Kohäsion und geringe Kopplung.
Ein zweiter Ansatz besteht darin, nach Codeelementen zu suchen, die eine hohe Kohäsion zueinander und eine geringe Kopplung mit anderen Teilen des Codes aufweisen. Im Wesentlichen bedeutet eine hohe Kohäsion, dass Teile einer Codebasis, die miteinander in Beziehung stehen, an einem einzelnen Speicherort aufbewahrt werden. Bei geringer Kopplung geht es gleichzeitig darum, nicht zusammenhängende Teile der Codebasis so weit wie möglich zu trennen.
Individueller Lebenszyklus.
Suchen Sie nach Codebestandteilen, die denselben Lebenszyklus haben und die Sie einzeln bereitstellen und veröffentlichen können. Wenn dieser Code durch ein separates Team verwaltet werden kann, ist dies ein guter Hinweis darauf, dass Sie den Code als Komponente außerhalb der Lösung packen können.
Stabile Bestandteile.
Einige Teile Ihrer Codebasis sind möglicherweise stabil und ändern sich nur selten. Überprüfen Sie Ihr Coderepository, um Code mit einer geringen Änderungshäufigkeit zu finden.
Unabhängige Codebestandteile und Komponenten.
Immer dann, wenn Codebestandteile und Komponenten unabhängig und ohne Bezug zu anderen Teilen des Systems vorliegen, können sie potenziell in separate Abhängigkeiten isoliert werden.
Sie können verschiedene Tools verwenden, die Sie beim Überprüfen und Untersuchen Ihrer Codebasis unterstützen. Diese reichen von Tools, die nach doppeltem Code suchen und Graphen zur Lösungsabhängigkeit zeichnen, bis hin zu Tools, die Metriken für Kopplung und Kohäsion berechnen können.
Welche Arten von Paketen gibt es?
Jede Programmiersprache oder jedes Framework bietet eine eigene Methode zur Erstellung von Paketen. Gängige Paketsysteme bieten eine Dokumentation darüber, wie der Prozess funktioniert.
Vielleicht sind Sie mit diesen gängigen Paketsystemen bereits vertraut:
- NuGet: Verpackt .NET-Bibliotheken
- NPM: Packt JavaScript-Bibliotheken
- Maven: Verpackt Java-Bibliotheken
- Docker:: Packt Software in isolierten Einheiten, die als Container bezeichnet werden.
Wo werden die Pakete gehostet?
Sie können Pakete in Ihrem eigenen Netzwerk hosten, oder Sie können einen Hostingdienst nutzen. Ein Hostingdienst wird oft als Paketrepository oder Paketregistrierung bezeichnet. Viele dieser Dienste bieten kostenloses Hosting für Open-Source-Projekte.
Hier finden Sie einige beliebte Hostingdienste für die gerade beschriebenen Pakettypen:
-
NuGet-Pakete werden für .NET-Codeartefakte verwendet. Diese Artefakte umfassen .NET-Assemblys und zugehörige Dateien, Tools und manchmal auch Metadaten. NuGet definiert die Art und Weise, wie Pakete erstellt, gespeichert und genutzt werden. Ein NuGet-Paket ist im Wesentlichen eine komprimierte Ordnerstruktur mit Dateien im ZIP-Format und hat die Erweiterung NUPKG.
-
Für JavaScript wird ein NPM-Paket verwendet. Ein NPM-Paket ist eine Datei oder ein Ordner, der JavaScript-Dateien und eine package.json-Datei enthält, die die Metadaten des Pakets beschreibt. Bei node.js enthält das Paket normalerweise ein oder mehrere Module, die geladen werden können, nachdem das Paket verwendet wurde.
-
Maven wird für Java-basierte Projekte verwendet. Jedes Paket verfügt über eine Datei für das Projektobjektmodell, die die Metadaten des Projekts beschreibt und die Basiseinheit für die Definition eines Pakets und die Arbeit mit ihm darstellt.
-
Docker-Pakete werden als Images bezeichnet und enthalten vollständige, eigenständige Bereitstellungen. In der Regel stellt ein Docker-Image eine Softwarekomponente dar, die selbst gehostet und ausgeführt werden kann, ohne Abhängigkeiten von anderen Images aufzuweisen. Docker-Images sind mehrschichtig und können von anderen Images abhängig sein.
Ein Paketfeed verweist auf Ihren Paketrepositoryserver. Dieser Server kann sich im Internet oder hinter einer Firewall in Ihrem Netzwerk befinden. Sie können z. B. NuGet-Feeds selbst hosten, indem Sie Hostingprodukte wie Azure Artifacts und MyGet verwenden. Sie können Pakete auch auf einer Dateifreigabe hosten.
Wenn Sie Pakete hinter der Firewall hosten, können Sie Feeds zu Ihren eigenen Paketen einbeziehen. Sie können auch Pakete zwischenspeichern, denen Sie in Ihrem Netzwerk vertrauen, wenn Ihre Systeme keine Verbindung mit dem Internet herstellen können.
Welche Elemente gehören zu einer guten Strategie für die Abhängigkeitsverwaltung?
Eine gute Strategie für die Abhängigkeitsverwaltung hängt von diesen drei Elementen ab:
Standardisierung.
Durch die Standardisierung, wie Sie Abhängigkeiten deklarieren und auflösen, wird der automatisierte Releaseprozess immer wiederholbar und vorhersagbar bleiben.
Paketformate und Quellen.
Jede Abhängigkeit sollte unter Verwendung des entsprechenden Formats verpackt und an einem zentralen Speicherort gespeichert werden.
Versionsverwaltung.
Sie müssen die Änderungen, die im Laufe der Zeit in den Abhängigkeiten auftreten, genauso wie beim eigenen Code nachverfolgen. Dies bedeutet, dass Abhängigkeiten versioniert werden sollten.
Wer kann auf Pakete zugreifen?
Viele Paketfeeds bieten uneingeschränkten Zugriff auf Pakete. Sie können z. B. Json.NET von nuget.org herunterladen, ohne sich anmelden oder authentifizieren zu müssen.
Andere Paketfeeds erfordern eine Authentifizierung. Sie können den Zugriff auf Feeds auf verschiedene Weise authentifizieren. Für einige Arten von Feeds sind z. B. ein Benutzername und ein Kennwort erforderlich. Andere Feeds erfordern ein Zugriffstoken, das in aller Regel aus einer lange Folge von Zeichen besteht, die Sie und die Ressourcen identifizieren, auf die Sie Zugriff haben. Sie können Zugriffstoken so einrichten, dass sie nach einem bestimmten Zeitraum ablaufen.
Wie werden die Pakete versioniert?
Das Schema für die Versionsverwaltung hängt vom verwendeten System für die Paketerstellung ab.
NuGet-Pakete verwenden z. B. die semantische Versionierung.
Die semantische Versionierung ist ein beliebtes Schema für die Versionsverwaltung. Das Format sieht wie folgt aus:
Hauptversion.Nebenversion.Patch[-Suffix]
Im Folgenden wird erläutert, was jeder dieser Parameter bedeutet:
- Eine neue Hauptversion führt Breaking Changes ein. Apps müssen in der Regel aktualisieren, wie sie das Paket verwenden, um mit einer neuen Hauptversion zu arbeiten.
- Eine neue Nebenversion führt neue Features ein, ist aber abwärtskompatibel mit früheren Versionen.
- Ein neuer Patch enthält abwärtskompatible Fehlerbehebungen, aber keine neuen Features.
- Der Teil -Suffix ist optional und kennzeichnet das Paket als Vorabversion. Beispiel: „1.0.0-beta1“ könnte das Paket als ersten Beta-Vorabbuild für Version 1.0.0 identifizieren.
Wenn Sie auf ein Paket verweisen, verwenden Sie dazu die Versionsnummer.
Hier sehen Sie ein Beispiel für die Installation eines Pakets mithilfe von PowerShell und einer bestimmten Versionsnummer:
Install-Package Newtonsoft.Json -Version 13.0.1
Was geschieht, wenn das Paket geändert wird?
Wenn Sie auf ein Paket aus Ihrer App verweisen, geben Sie normalerweise die Version des Pakets an, die Sie verwenden möchten – dies wird als Anpinnen bezeichnet.
In vielen Frameworks können Sie zulässige Bereiche von Paketversionen angeben, die installiert werden können. Einige ermöglichen auch die Angabe von Platzhaltern, was wir als fließende Version bezeichnen.
In NuGet bedeutet die Version „1.0“ z. B. die erste Version, die gleich oder größer als 1.0 ist. „[1.0]“ gibt an, dass nur die Version 1.0 installiert werden soll, nicht aber eine neuere Version.
Hier folgen ein paar weitere Beispiele:
Diese Notation: | Auswahl: |
---|---|
(1.0,) | Die erste Version, die größer als 1 ist. |
[1.0,2.0] | Die erste Version, die größer als oder gleich 1.0 und kleiner als oder gleich 2.0 ist. |
(1.0,2.0) | Die erste Version, die größer als 1.0 und kleiner als 2.0 ist. |
[1.0,2.0) | Die erste Version, die größer als oder gleich 1.0 und kleiner als 2.0 ist. |
Wenn jeder Maintainer eine neue Paketversion veröffentlicht, können Sie auswerten, was sich geändert hat, und Ihre Anwendung daraufhin testen. Wenn Sie bereit sind, können Sie die Versionsnummer des Pakets in Ihrer Konfiguration aktualisieren und die Änderung an Ihre Buildpipeline übermitteln.
Im Folgenden sehen Sie ein Beispiel dafür, wie Sie das NewNewtonsoft.Json-Paket in die Projektdatei (.csproj) Ihrer C#-Anwendung einbeziehen können. Dieses Beispiel gibt Version 13.0.1 des Pakets an:
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>