Le Build en .NET
Assembler pour construire du logiciel ne date pas d'aujourdhui, mais le besoin de processus de construction automatisés s'est largement renforcé avec la demande croissante de projets itératifs, contraints d'évoluer rapidement et sans régression. Nous présentons donc comment les principaux composants et outils de Build en .NET peuvent adresser cet enjeu majeur.
Article paru dans le magazine "Programmez !", dossier Build, janvier 2008.
Le " build " versus le " pipeline de Build "
Loin de se limiter à la simple compilation de l'application sur le poste développeur, le build s'est étendu : il est maintenant automatisé et inclut a minima l'exécution des tests unitaires [1]. Afin de le distinguer de son ancêtre, nous utilisons les termes de Build, avec un B majuscule, ou encore de " pipeline de Build ".
Représentons provisoirement et très schématiquement les étapes du pipeline :
Les grandes étapes du pipeline de Build (cliquez sur l'image pour l'agrandir)
Travailler suivant ces étapes appelle à plusieurs questions :
- Quel est / quel peut être le déclencheur de ce pipeline ?
- Chaque étape du pipeline peut retourner une erreur et mettre en échec le pipeline tout entier : Comment identifier l'erreur ? Comment notifier l'équipe ? Que faire en cas d'échec ?
- Que produit-il en sortie : un logiciel ? un rapport ? sous quel format ? pour qui ? pour quoi faire ?
- Quel est l'outillage associé à chacune de ces étapes ?
Le pipeline de Build en détail
Le processus de Build met en oeuvre les composants suivants.
Les composants détaillés du Build (cliquez sur l'image pour l'agrandir)
Le gestionnaire de sources est chargé de centraliser et d'historiser le code source. Celui-ci doit pouvoir :
Marquer une version des sources, en l'occurrence celle qui est Buildée, via un tag, ou une étiquette ;
Isoler différentes versions du logiciel : les branches sont le mécanisme le plus fréquent pour cela
Effectuer des opérations transactionnelles sur le code source : l'ensemble des fichiers soumis au gestionnaire est rollbacké en cas de conflit sur l'un d'eux ;
Travailler de manière collaborative : l'édition sans verrouillage, les outils de visualisation des différences et de fusion sont particulièrement utiles dans le cadre de la pratique d'intégration continue ;
Etre intégré confortablement à l'IDE: le gestionnaire de sources est manipulé de manière fréquente par les développeurs, il faut donc qu'ils l'aient " sous la main ".
Team Source, le module de gestion de source de Team System, et Subversion répondent par exemple à ces critères.
L'ordonnanceur lance le Build sur la plateforme d'intégration. Le déclenchement peut intervenir :
Sur événement (triggering) : l'ordonnanceur observe le gestionnaire de sources afin de détecter les mises à jour. Un délai avant le démarrage de la construction est généralement paramétré afin de ne pas effectuer deux compilations lors de mises à jour rapprochées. Ce mode est utilisé dans le cadre de l'intégration continue ;
A échéance fixe : c'est le cas de la construction nocturne (nighty Build) par exemple ;
Sur demande : un membre de l'équipe peut demander explicitement l'exécution d'un Build.
C'est l'ordonnanceur qui effectue la première étape du Build. Elle consiste à récupérer la version la plus à jour des sources auprès du gestionnaire de sources (checkout ou update).
L'ordonnanceur offre généralement un tableau de bord des constructions en cours et de l'historique des constructions, la possibilité de consulter les journaux d'événements des constructions. Il est chargé d'avertir par mail (ou par autre moyen) les développeurs et personnes intéressées par le résultat du Build à l'issue du processus.
A titre d'exemple, CruiseControl .NET (CC.NET) est l'ordonnanceur .NET Open Source le plus répandu.
Le moteur de Build réalise la construction étendue de l'application :
Il lance la compilation du code source, en utilisant éventuellement des dépendances externes (issues d'un éditeur, de la communauté open source ou d'une autre équipe projet) ;
Il exécute ensuite les tests unitaires. C'est généralement à l'issue de cette étape que le Build est qualifié (" réussi " ou " cassé ") ;
Il calcule alors des métriques sur l'application (couverture des tests unitaires, respect des règles de développements, analyse des similitudes,...). Elles sont destinées à estimer la qualité du code compilé ;
Le déroulement du Build, les métriques calculées dans l'étape précédente, et le résultat du Build (" réussi " ou " cassé ") sont consignés dans des rapports ;
En cas de Build réussi, l'application est packagée afin de fournir un livrable (Release).
En l'occurrence, quelques standards du marché sont à signaler :
MSBuild, moteur de Build gratuit, inclus dans le framework .NET et extensible ;
FXCOP, outil de vérification des normes de développements et des bonnes pratiques, fourni gratuitement par Microsoft ;
NUnit, framework Open Source de tests unitaires.
Le site projet agrège et publie les rapports et métriques issus des différentes étapes du processus de Build :
La documentation du code ;
La couverture des tests unitaires ;
Les infractions aux règles de développement (codage / nommage) ;
Les différentes métriques de qualité (complexité et taille du code, copier/coller, ...).
Ce site permet aux différents acteurs de l'équipe de connaître l'état du projet. Dans le cas de Team System, c'est un portail SharePoint qui tiendra ce rôle. Il expose les documents projet.
Deux portails Build .NET : CC.NET et Team Plain (cliquez sur les images pour les agrandir)
Qu'est ce qu'un Build cassé ?
Un Build est considéré comme " cassé " lorsque l'une des étapes du Build retourne une erreur. Les cas de Build cassé les plus courants sont :
- Le code source ne compile pas. Cette erreur est généralement due au fait que les développeurs n'ont pas mis à jour leur version locale des sources et résolu les conflits sur leur poste avant de soumettre leurs modifications. La version actuelle du code dans le référentiel n'est donc pas cohérente (fichiers en conflits, différences d'API,...) ;
- Les tests unitaires ne passent pas. Ce cas se produit lorsqu'un développeur n'a pas exécuté tout ou partie des tests unitaires avant de mettre ses sources à disposition.
Quelles que soient les règles définies, il convient de s'assurer des points suivants :
- Les développeurs doivent avoir les moyens de s'assurer qu'ils ne casseront pas le Build avant de mettre à disposition leurs modifications dans le gestionnaire de sources ;
- Le Build ne doit pas casser " pour un rien " (nom d'attribut mal formé par exemple), sous peine que l'équipe se désintéresse du résultat du Build ;
- La durée du Build doit rester courte si l'on pratique l'intégration continue. On envisagera le cas échéant d'avoir plusieurs Build :
- Un Build rapide vérifiant la compilation et les tests unitaires. Ce Build sera exécuté à chaque commit ;
- Un Build plus long, effectuant des vérifications complémentaires et générant le site projet, qui sera effectué la nuit.
Quelles actions entreprendre à l'issue du Build ?
Lorsque le Build est cassé, l'ordonnanceur doit notifier les membres de l'équipe de ce statut anormal (par mail généralement). La résolution de ce problème devient alors la priorité de l'équipe.
En cas de succès, l'ordonnanceur est généralement chargé de marquer la version des sources (et des fichiers de configuration) utilisée. L'étiquette utilisée est généralement le numéro du Build. Elle permet à tout moment de reproduire un Build donné.
Une livraison est une étape supplémentaire du Build. Après le marquage des sources, elle construit le livrable (MSI, ZIP,...), puis le dépose ou le déploie sur une plateforme de test.
Patterns d'intégration et outils de Build
Nous venons de présenter les étapes et composants du Build. Concrètement, quels sont les outils de Build en .NET ? Comment fonctionnent-ils ?
A la lueur de ce tour du propriétaire des composants du Build, il apparaît qu'un outil de Build procédera lui-même à l'intégration des différents composants du Build, qui sont : le gestionnaire de source, l'ordonnanceur de Build, le moteur de build, et les sites projet.
En la matière, il existe deux grandes familles d'outils .NET, qui participent de deux patterns de l'intégration.
- Dans le premier pattern, l'outil de Build est conçu comme un intégrateur de composants du Build : il est relativement léger, et agrège différents composants du Build qui lui sont externes, il les ordonnance et les orchestre dans le pipeline de Build. L'intégration de ces composants externes est souvent effectuée à l'aide du pattern plugins.
- Dans le second pattern, l'outil de Build est conçu comme un outil intégré (de composants internes de Build) : il est plus lourd et implémente en interne les composants du Build.
" Intégrateur d'outils " et " outil intégré "
Microsoft Team System repose entièrement sur le pattern " outil intégré " : l'outil contient un référentiel centralisé de données (une base SQL 2005 avec des cubes OLAP), et un serveur Team Foundation Server. Le serveur TFS implémente les différents composants du pipeline de Build, et présente l'exécution des Builds dans un portail SharePoint.
Le pattern " outil intégré " dans Team System (cliquez sur l'image pour l'agrandir)
Ce pattern est aussi mis en oeuvre dans la suite Rational Build Forge d'IBM, ainsi que dans Borland Gauntlet.
Le pattern " intégrateur d'outils ", lui, est très utilisé dans le monde Open Source, à l'instar de CruiseControl.NET (CC.NET), ou de Draco.NET [2] . Il est aussi présent dans des outils commerciaux tels que : Automated Build System, Final Builder, ParaBuild, Visual Build Professional, ou encore Visual Make.
Prenons l'exemple de CC.NET : dans son principe, CC.NET est un intégrateur de composants de Build, suivant un pattern plugins :
- Il est compatible avec la plupart des gestionnaires de code source : Clear Case, CVS, Perforce, PVCS, Subversion, Synergy, Team Source, Visual Source Safe, ... [3] ;
- Il s'appuie sur NAnt, MSBuild pour la compilation ;
- Il intègre NUnit ou csUnit et NCover pour les tests unitaires instrumentés, ainsi que Fitnesse pour les tests de recette ;
- Il sait lancer VIL ou FXCop pour les contrôles qualité .NET ;
- Il notifie le résultat du Build par email.
CC.NET affiche également le résultat de chaque Build au sein d'un site portail.
Conclusion
Aujourd'hui, on constate que le Build s'est standardisé autour des composants et des pratiques que nous avons présentés, et que l'on retrouve dans l'intégration continue et les usines de développement .NET.
Les outils de Build modernes implémentent les composants du pipeline de Build suivant deux patterns d'intégration différents : pattern " outil intégré " et pattern " intégration d'outils ".
De ce point de vue, le pattern " outil intégré ", qui connaît toutes les données du Build, permet d'offrir facilement des rapports plus complets et de présenter l'évolution des métriques : évolution du nombre de tests unitaires OK/KO, évolution du taux de couverture, évolution des infractions aux règles de développement... Mieux, lorsque l'outil intègre un gestionnaire de demandes, les rapports peuvent relier les évolutions de code, les métriques qualité avec les demandes de développement, voire le planning projet.
Les outils intégrés nécessitent souvent moins d'effort d'intégration de la part de l'équipe. Ceci n'est pas négligeable car cela induit un délai et des compétences spécifiques dans la mise en oeuvre et la mise à jour d'une usine logicielle .NET.
En revanche, les outils intégrés souffrent souvent d'un manque d'ouverture à des composants techniques tiers, ce qui est loin d'être anodin lorsque l'on possède des outils existants.
Messaoud OUBECHOU (meo@octo.com) et Frédéric SCHÄFER (fch@octo.com)
Responsables du Centre de Compétences .NET
[1] On se référera à l'article de référence sur l'intégration continue rédigé par Martin Fowler.
[2] Voir : ccnet et http://draconet.sourceforge.net
[3] La liste complète est accessible ici
Le tableau suivant présente succinctement quelques outils intégrés ou intégrateurs de composants de Build et le pattern d'intégration qu'ils implémentent.
Pattern d'intégration | Licence Commercial / OSS | Gestionnaire de source supporté | Ordonnanceur | Moteur de Build / Test / Qualité | Site Projet / Notification | |
Automated Build Studio 1.4 de Automated QA | Intégrateur d'outils | Commercial | StarTeam, CVS, PVCS, VSS, Team Source, Perforce, ClearCase, SourceGear, SVN | Programmé<br><br>Sur événement déclencheur (checkin, mise à jour de fichier)<br><br>A la demande par interface web | Compilateurs .NET, C++ (Intel, Borland, GNU), ASP.NET,<br><br>NAnt, MSBuild, / A. QA Test,<br><br>JUnit, NUnit, MSTest | Web, technique et orienté Build unitaire (pas de rapportd'évolution en standard) /<br><br>Net send, MSN, ICQ, mail |
CruiseControl.NET 1.3 | Intégrateur d'outils | OSS | CVS, SVN, VSS, Perforce, ClearCase, PVCS, StarTeam, Telelogic, Seapine | Intervalle, programmé, intégration continue | NAnt, MSBuild, Visual Studio, Final Builder /<br><br>Fitnesse, NUnit, NCover / VIL, FxCop | Web, orienté Build unitaire (pas de rapportd'évolution en standard) / icon tray |
Draco.NET 1.6.4 | Intégrateur d'outils | OSS | CVS, VSS, SVN, PVCS, Vault | Service Windows en mode poll et intégration continue | MSBuild, NAnt, VS2005 | Site web orienté Build / Notification par email |
Final Builder Server de VSoft Technologies | Intégrateur d'outils | Commercial | ClearCase, Source Force, CVS, MKS, PVCS, QVCS, StarTeam, SourceGear, Seapine, SVN, Vault | A la demande, intervalle, intégration continue | C++, .NET, Borland C#, Delphi.NET / Nant, MSBuild / NUnit, MSTest, TestComplete, AQTest | Web site / email, RSS |
ParaBuild 3.1 de ViewTier Systems | Intégrateur d'outils | Commercial | Perforce, Subversion, CVS, ClearCase, Serena, StarTeam, Vault, MKS, VSS | A la demande, intervalle, intégration continue | NAnt, MSBuild, VB, MSDEV, make, nmake | Site Web orientés build / email, rss, system tray, IM |
Team City2.1.1 de JetBrains | Intégrateur d'outils | Commercial | ClearCase, CVS, Perforce, SVN, Team Source, VSS | A la demande, intervalle, intégration continue | MSBuild, NAnt | Site web orienté build / |
Team System / Team Foundation Server 1.0 de Microsoft | Outil intégré | Commercial | Team Source | A la demande, interval, intégration continue | Team Build / MSBuild | Site SharePoint liant Work Items, MS Project lors du Build / email, rss |
Rational Build Forge d'IBM | Outil intégré | Commercial | ClearCase + ClearQuest<br><br>+ CVS, Perforce, StarTeam, VSS, Subversion | Programmé, à la demande, intégration continue | JAVA/.NET, intégration avec Eclipse et VS2005 | Web / RSS, mail, tray |
Gauntlet de Borland | Outil intégré | Commercial | Borland Star Team | Programmé, à la demande, intégration continue | Intégration native avec Perfect Build<br><br>Borland Silk Performer<br><br>Borland Silk Test Manager<br><br>NUnit | Site et rapports Web, orientés build |