Planifier les dépendances de build pour votre pipeline

Effectué

Dans cette unité, vous allez découvrir comment empaqueter du code pour faciliter son partage. Vous allez découvrir pourquoi vous devriez créer des packages, le type de packages que vous pouvez créer, où les héberger et comment y accéder une fois qu’ils sont hébergés. Vous découvrez également le versioning de package.

Les codes base sont toujours de plus en plus grands et complexes. Il est rare pour une équipe d’écrire tout le code que son application utilise. L’équipe inclut plutôt du code existant écrit par d’autres développeurs. Dans une application, il peut y avoir un grand nombre de ces packages, ou dépendances. Il est important de gérer activement ces dépendances pour être en mesure d’en assurer une maintenance correcte et de veiller à ce qu’elles répondent aux exigences de sécurité.

Voyons où en est l’équipe. Andy a convoqué les membres de l’équipe car il souhaite discuter d’une modification potentielle de leur code qui aiderait une autre équipe.

Réunion d’équipe

Andy : Bonjour tout le monde. Je viens de discuter avec l’équipe qui travaille sur le système back-end pour Space Game. Elle pourrait utiliser les modèles que nous utilisons pour le site web dans une application back-end qu’elle prévoit d’écrire.

Amita : Qu’entendez-vous par modèles ?

Andy : Comme vous le savez, le site web Space Game est une application ASP.NET Core. Il utilise le modèle Model-View-Controller, ou MVC, pour séparer les données de la façon dont ces données sont affichées dans l’interface utilisateur. Je me disais que nous pourrions créer un package qui contient nos classes de modèle afin que n’importe quelle application puisse les utiliser.

Amita : Dans quel but, exactement ?

Andy : Nos deux équipes partageront la même base de données. Le jeu envoie les scores élevés à la base de données ; nous lisons ces scores pour les afficher dans le classement.

Amita : Cela paraît logique. Comment allons-nous créer ce package ?

Andy : C’est justement à ce sujet que je voulais discuter avec vous. Nous avons quelques options, et je me demandais si vous auriez quelques idées.

Tim : Je serais ravi de contribuer, mais j’ai d’abord quelques questions. Tout ceci est nouveau pour moi, et je souhaiterais comprendre comment tout cela fonctionne.

Qu’est-ce qu’un package ?

Un package contient du code réutilisable que d’autres développeurs peuvent utiliser dans leurs propres projets, bien qu’ils n’en soient pas les auteurs.

Pour les langages compilés, un package contient généralement le code binaire compilé, comme des fichiers .dll en .NET ou .class en Java. Pour les langages qui sont interprétés plutôt que compilés, tels que JavaScript ou Python, un package peut inclure du code source.

Dans les deux cas, les packages sont généralement compressés au format ZIP ou dans un format similaire. Les systèmes de packages définissent souvent une extension de fichier unique comme .nupkg ou .jar pour clarifier l’utilisation du package. La compression peut aider à réduire les temps de téléchargement et génère également un fichier unique pour simplifier la gestion.

Les packages contiennent aussi souvent un ou plusieurs fichiers qui fournissent des métadonnées ou des informations sur le package. Ces métadonnées peuvent décrire ce que fait le package, spécifier les termes du contrat de licence, les coordonnées de l’auteur et la version du package.

Pourquoi générer un package ?

La génération d’un package offre plusieurs avantages par rapport à la duplication du code.

L’un d’entre eux est d’empêcher la dérive. Quand du code est dupliqué, chaque copie peut rapidement dériver afin de répondre aux exigences d’une application particulière. Il devient difficile de migrer les modifications d’une copie vers les autres. En d’autres termes, vous perdez la capacité à améliorer le code d’une manière bénéfique à tout le monde.

Les packages regroupent également des fonctionnalités connexes dans un même composant réutilisable. En fonction du langage de programmation, un package peut fournir aux applications l’accès à certains types et fonctions tout en limitant l’accès à leurs détails d’implémentation.

Une autre raison de générer un package est que cela fournit un moyen cohérent de générer et de tester les fonctionnalités de ce package. Quand du code est dupliqué, chaque application est susceptible de générer et de tester ce code de différentes façons. Une série de tests pourrait inclure des vérifications susceptibles d’être bénéfiques à une autre série.

L’un des inconvénients est que vous avez un autre codebase à tester et à tenir à jour avec un package. Vous devez également être prudent lors de l’ajout de fonctionnalités. En règle générale, un package doit contenir des fonctionnalités qui sont bénéfiques à de nombreux types d’applications. Par exemple, Json.NET est un package NuGet connu pour .NET, qui vous permet de travailler avec des fichiers JSON. Json.NET étant open source, la communauté peut proposer des améliorations et signaler des problèmes.

Quand plusieurs applications peuvent tirer profit du même code, les avantages compensent largement les inconvénients. Vous n’avez qu’une seule base de code, une seule série de tests et un seul processus de build à gérer.

Comment identifier les dépendances ?

Si l’objectif est de réorganiser votre code dans des composants distincts, vous avez besoin d’identifier les parties de votre application qui peuvent être supprimées, empaquetées pour les rendre réutilisables, stockées dans un emplacement central et versionnées. Vous pouvez même remplacer votre propre code par des composants tiers open source ou sous licence.

Il existe de nombreuses façons d’identifier les dépendances potentielles dans votre codebase. Vous pouvez notamment analyser votre code pour identifier des modèles de réutilisation, ainsi que l’architecture de votre solution. Voici quelques méthodes pour identifier des dépendances :

  • Code dupliqué.

    Si certaines parties de code apparaissent à plusieurs endroits, cela indique que vous pouvez réutiliser ce code. Centralisez ces éléments de code en double pour les réempaqueter de manière appropriée.

  • Cohésion élevée et couplage faible.

    Une deuxième approche consiste à rechercher les éléments de code dont la cohésion est élevée entre eux et dont le couplage est faible avec d’autres parties du code. En bref, une cohésion élevée implique de conserver les parties d’un code base liés entre eux à un seul endroit. Un couplage faible, en même temps, consiste à séparer autant que possible les parties non liées d’un code base.

  • Cycle de vie individuel.

    Recherchez les parties du code qui présentent un cycle de vie pouvant être déployées et mises en production individuellement. Si ce code peut être géré par une équipe distincte, cela indique que vous pouvez l’empaqueter sous forme de composant en dehors de la solution.

  • Parties stables.

    Certaines parties de votre code base peuvent être stables et rarement modifiées. Vérifiez votre dépôt de code pour y trouver du code dont la fréquence de modification est faible.

  • Code et composants indépendants.

    Chaque fois que le code et les composants sont indépendants et non liés à d’autres parties du système, ils peuvent potentiellement être isolés dans des dépendances distinctes.

Vous pouvez utiliser divers outils qui vous aideront à analyser et examiner votre codebase. Ces outils permettent notamment d’analyser du code dupliqué afin de tracer des graphes de dépendance de solution, ou de calculer des métriques de couplage et de cohésion.

Quels genres de packages existe-t-il ?

Chaque langage de programmation ou framework fournit sa propre méthode pour générer des packages. Les systèmes de packages les plus populaires fournissent une documentation sur le fonctionnement de ce processus.

Vous connaissez peut-être déjà ces systèmes de packages populaires :

  • NuGet : packages de bibliothèques .NET
  • npm : bibliothèques JavaScript des packages
  • Maven : packages de bibliothèques Java
  • Docker : logiciel de packages dans des unités isolées appelées conteneurs

Où les packages sont-ils hébergés ?

Vous pouvez héberger des packages sur votre propre réseau ou utiliser un service d’hébergement. Un service d’hébergement est souvent appelé dépôt de package ou registre de package. Un grand nombre de ces services fournissent un hébergement gratuit pour les projets open source.

Voici quelques services d’hébergement populaires pour les types de packages que nous venons de décrire :

  • Galerie NuGet

    Les packages NuGet sont utilisés pour les artefacts de code .NET. Ces artefacts incluent les assemblys .NET et les fichiers, les outils et, parfois, les métadonnées associés. NuGet définit la manière dont les packages sont créés, stockés et consommés. Un package NuGet est essentiellement une structure de dossiers compressés, dont les fichiers sont au format ZIP, qui porte l’extension .nupkg.

  • NPM

    Un package NPM est utilisé pour JavaScript. Un package NPM est un fichier ou dossier qui contient des fichiers JavaScript et un fichier package.json qui décrit les métadonnées du package. Pour node.js, le package contient généralement un ou plusieurs modules pouvant être chargés une fois que le package est consommé.

  • Dépôt central Maven

    Maven est utilisé pour les projets basés sur Java. Chaque package possède un fichier POM (Project Object Model) qui décrit les métadonnées du projet et constitue l’unité de base pour la définition d’un package et son utilisation.

  • Docker Hub

    Les packages Docker sont appelés images. Ils contiennent des déploiements complets et autonomes. En règle générale, une image Docker représente un composant logiciel qui peut s’héberger et s’exécuter tout seul, sans aucune dépendance vis-à-vis d’autres images. Les images Docker sont superposées et peuvent dépendre d’autres images.

Un flux de package fait référence à votre serveur de dépôt de package. Ce serveur peut être sur Internet ou derrière votre pare-feu sur votre réseau. Par exemple, vous pouvez héberger vos propres flux NuGet à l’aide de produits d’hébergement comme Azure Artifacts et MyGet. Vous pouvez également héberger des packages sur un partage de fichiers.

Quand vous hébergez des packages derrière le pare-feu, vous pouvez inclure des flux pour vos propres packages. Vous pouvez également mettre en cache les packages auxquels vous faites confiance sur votre réseau quand vos systèmes ne peuvent pas se connecter à Internet.

Quels éléments constituent une bonne stratégie de gestion des dépendances ?

Une bonne stratégie de gestion des dépendances s’articule autour de ces trois éléments :

  • Standardisation.

    La standardisation de la façon dont vous déclarez et résolvez les dépendances va permettre à votre processus de version automatisé de rester reproductible et prévisible.

  • Formats et sources des packages.

    Chaque dépendance doit être empaquetée au format applicable et stockée dans un emplacement central.

  • Gestion des versions :

    Vous devez effectuer le suivi des modifications qui se produisent au fur et à mesure dans les dépendances, comme vous le feriez avec votre propre code. Cela signifie que les dépendances doivent être versionnées.

Qui peut accéder aux packages ?

De nombreux flux de packages fournissent un accès illimité aux packages. Par exemple, vous pouvez télécharger Json.NET à partir de nuget.org sans avoir à vous connecter ou à vous authentifier.

D’autres flux de packages nécessitent une authentification. Vous pouvez authentifier l’accès aux flux de plusieurs façons. Par exemple, certains types de flux nécessitent un nom d’utilisateur et un mot de passe. D’autres flux nécessitent un jeton d’accès, généralement une longue série de caractères qui identifie votre identité et les ressources auxquelles vous avez accès. Vous pouvez définir les jetons d’accès afin qu’ils expirent après une période donnée.

Comment les versions des packages sont-elles gérées ?

Le schéma de gestion de versions varie en fonction du système d’empaquetage que vous utilisez.

Par exemple, les packages NuGet utilisent la gestion sémantique de version.

La gestion sémantique de version est un schéma de gestion de versions populaire. Voici le format :

Principale.Mineure.Correctif[-Suffixe]

La signification de chacun de ces paramètres est la suivante :

  • Une nouvelle version Principale introduit des changements cassants. Les applications doivent généralement mettre à jour la façon dont elles utilisent le package pour fonctionner avec une nouvelle version principale.
  • Une nouvelle version Mineure introduit de nouvelles fonctionnalités, mais elle offre une compatibilité descendante avec les versions antérieures.
  • Un nouveau Correctif introduit des corrections de bogues à compatibilité descendante, mais pas de nouvelles fonctionnalités.
  • La partie -Suffixe est facultative ; elle identifie le package en tant que préversion. Par exemple, 1.0.0-beta1 peut identifier le package comme étant la première préversion bêta pour la version 1.0.0.

Quand vous référencez un package, vous le faites par numéro de version.

Voici un exemple d’installation de package avec PowerShell et un numéro de version spécifique :

Install-Package Newtonsoft.Json -Version 13.0.1

Que se passe-t-il quand le package change ?

Quand vous référencez un package à partir de votre application, il est d’usage d’épingler, ou de spécifier, la version du package que vous souhaitez utiliser.

De nombreux frameworks permettent de spécifier les plages de versions de package autorisées pour l’installation. Certains permettent également de spécifier des caractères génériques. Nous employons alors le terme de version flottante.

Par exemple, dans NuGet, version « 1.0 » signifie la première version supérieure ou égale à 1.0. « [1.0] » indique qu’il faut installer uniquement la version 1.0, et pas une version plus récente.

Voici quelques autres exemples :

Cette notation : Sélectionne :
(1.0,) La première version supérieure à 1.
[1.0,2.0] La première version supérieure ou égale à 1.0 et inférieure ou égale à 2.0
(1.0,2.0) La première version supérieure à 1.0 et inférieure à 2.0
[1.0,2.0) La première version supérieure ou égale à 1.0 et inférieure à 2.0

À mesure que chaque chargé de maintenance publie une nouvelle version de package, vous pouvez évaluer ce qui a changé et tester votre application par rapport à elle. Quand vous êtes prêt, vous pouvez mettre à jour le numéro de version du package dans votre configuration et soumettre le changement à votre pipeline de build.

Voici un exemple de la façon dont vous pouvez ajouter le package Newtonsoft.Jsdu dans le fichier projet (.csproj) de votre application C#. Cet exemple spécifie la version 13.0.1 de ce package :

<ItemGroup>
  <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

Vérifiez vos connaissances

1.

Qu’est-ce qu’un package ?

2.

Supposez que vous avez créé un package que vous souhaitez partager publiquement. Quel est le moyen le plus simple de procéder ?