Disposer d’une chaîne d’intégration continue (CI en anglais pour Continuous Integration) est absolument nécessaire pour améliorer sa qualité logicielle et optimiser sa production. L’objectif étant d’automatiser au maximum l’exécution des tests, des linters et autres opérations optimisant la productivité (compilation, paramétrage, etc.).
Si plusieurs outils existent aujourd’hui et permettent facilement la mise en place d’une chaîne d’intégration continue (Travis et Jenkins par exemple), il faut bien avoir conscience que la richesse et les gains que vous obtenez grâce à ces outils dépendent essentiellement du flux de votre code.
Cet article a donc pour objectif :
Ainsi vous pourrez sereinement songer, si besoin, à améliorer votre chaîne d’intégration continue !
L’intégration continue couvre toutes les opérations réalisées sur le code depuis l’espace de travail des développeurs jusqu’au dépôt stockant le code intégré. Dès lors que le code est intégré, on peut songer à construire une release (Continuous Delivery) et à passer en production (Continuous Deployment), mais ceci est une autre histoire.
La figure suivante présente ce flux. Elle montre plusieurs développeurs qui disposent chacun de leur propre espace de travail (dans la suite de cet article nous appellerons BENCH cet espace de travail). Chaque développeur effectue donc ses modifications dans son BENCH. Toutes les modifications de tous les développeurs sont ensuite intégrées par un intégrateur pour ne former qu’un seul code intégré. Nous appellerons le WORKSHOP l’environnement de travail de l’intégrateur. Le WORKSHOP contient le code intégré.
Le flux du code en intégration continue est donc le chemin que vont prendre les modifications du BENCH vers le WORKSHOP. Ce flux doit absolument être précisé afin que l’intégration continue soit optimale.
Pour bien comprendre le chemin que prend le code pour aller du BENCH au WORKSHOP, il faut parler de l’ANTIROOM.
L’ANTIROOM c’est le lieu où sont stockées toutes les modifications réalisées par les développeurs avant que celles-ci ne soient intégrées dans le workshop.
Autrement dit, l’ANTIROOM est le passage obligé pour que le code transite du BENCH au WORKSHOP.
La figure suivante illustre ce concept et montre bien que, grâce à ce concept d’ANTIROOM, la définition d’un flux de code nécessite de préciser deux points :
Lorsqu’il n’y a pas d’ANTIROOM, les développeurs committent directement dans le WORKSHOP. De fait, si une erreur ou un défaut est commité celui-ci ira directement en production…
Afin de bien comprendre et d’illustrer ces concepts de BENCH, ANTIROOM et WORKSHOP, voici des modèles de flux assez présents dans les projets logiciels.
Ce modèle est largement mis en avant par GitHub sur de nombreux projets OpenSource. Il considère que l’ANTIROOM contient des pull-request.
Une pull-request est proposée par un développeur. Elle contient les modifications réalisées par le développeur dans son BENCH, qu’il souhaite voir intégrées dans le WORKSHOP.
L’intégrateur peut voir les différentes Pull-Request qui lui sont proposées. Ainsi, il peut les accepter ou les refuser. Il peut même les commenter et demander aux développeurs des améliorations avant acceptation.
Notons aussi que tous les développeurs peuvent voir toutes les Pull-Request (celles des autres développeurs) et les commenter.
L’avantage de ce modèle est qu’il permet aux développeurs de bien packager les modifications qu’ils veulent soumettre. En créant une pull-request le développeur précise à l’intégrateur le bloc qu’il veut intégrer. Un autre avantage est que la pull-request est un bon support pour la revue de code. Une pull-request étant bien visible de tous les développeurs on peut alors solliciter plus facilement des revues de code.
L’inconvénient de ce modèle est qu’il laisse toute la charge de l’intégration à l’intégrateur et celui-ci peut se retrouver rapidement débordé et mettre de plus en plus de temps à accepter les Pull-Request. De plus, comme nous le verrons dans la suite, il est difficile d’intégrer des mécanismes de contrôle des pull-requests même si certains outils commencent à en proposer.
Ce modèle est souvent utilisé par les entreprises qui travaillent en feature team. Il considère que l’ANTIROOM est composé des branches contenant les modifications à intégrer. Ces branches sont appelées les feature branches.
La création des branches est souvent laissée à l’intégrateur. Pour autant, dans certaines entreprises, les développeurs peuvent créer les branches.
Les développeurs committent leurs modifications dans leur branche (en principe chaque développeur est affecté sur une feature et travaille donc principalement sur la branche de la feature). Enfin, quand la branche est suffisamment mature, le développeur demande à l’intégrateur de l’intégrer (merger la feature branch dans le WORKSHOP).
L’avantage ce modèle est qu’il soulage un peu l’intégrateur car les développeurs qui collaborent à une même feature travaillent tous sur une même branche. Ils doivent alors gérer leurs commits et les relations entre ceux-ci. L’autre avantage est qu’il est possible de réaliser des contrôles dans la feature branch et ainsi aider les déveppeurs et l’intégrateur.
L’inconvénient de ce modèle est qu’il faut faire attention à la multiplication des branches et à leur “écartement”. En effet, plus il y a de branches et plus celles-ci sont longues et différentes, plus l’intégration sera compliquée. Un autre inconvénient est que la revue de code au sein d’une même branche est un peu plus délicate à mettre en place.
Ce modèle est plébiscité par Google. Il considère que l’ANTIROOM est la branche principale du dépôt (oui, il s’agit bien de la branche master !!!).
De fait, tous les développeurs peuvent envoyer leurs modifications dans l’ANTIROOM “simplement” en commitant et en pushant sur la branche master. Enfin, ce n’est pas si simple que cela car, nous le verrons dans la suite de l’article, il y a de nombreux contrôles.
L’intégrateur, quand il le souhaite, peut intégrer certaines modifications dans le WORKSHOP en réalisant du cherry picking. Bien souvent le WORKSHOP est composé de plusieurs branches, différentes de la branche Master. L’intégrateur sélectionne donc les commits réalisés sur la branche master et les ajoute dans la branche d’intégration désirée.
Ce modèle, qui peut sembler un peu bizarre, a le principal avantage de faire en sorte que tous les développeurs aident à l’intégration. Ils sont tous responsables de la qualité du dépôt master !!! L’autre avantage c’est que tous les développements en cours sont à jour. Fini les incohérences découvertes lors de l’intégration… tardive. Enfin, avec ce modèle il est possible de réaliser dans l’ANTIROOM exactement les mêmes contrôles que l’on pourrait faire dans le WORKSHOP.
L’inconvénient réside essentiellement dans la complexité de sa mise en oeuvre et dans… la résistance au changement. En effet peu d’organisation accepteraient aujourd’hui de passer à ce modèle. Google le fait depuis de nombreuses années.
Il existe de nombreux modèles hybrides basés sur les modèles que nous venons de présenter.
Par exemple, dans plusieurs projets on couple un feature branching avec des pull-request. Les développeurs travaillent sur des feature branch et construisent des pull-request à partir de celles-ci. On peut alors considérer qu’il y a deux ANTIROOM l’une après l’autre (feature branch puis pull-request).
Pour le développement du noyau de linux, on a d’abord un modèle de pull-request vers les WORKSHOP gérés par des développeurs reconnus. Ensuite ces développeurs fonctionnent sur un modèle par feature branching avec le WORKSHOP de linux, géré par Linus Torvalds.
Ce deux exemples ilustrent un peu la diversité des organisations et de leur flux de code.
Une chaîne d’intégration continue bien définie peut intervenir aux trois niveaux de notre modèle :
Notre première préconisation est de se rapprocher d’un flux proche du push to master !!! Celui-ci réduit l’écart entre développeur et intégrateur. Il facilite grandement l’intégration et permet ainsi d’optimiser la chaîne d’intégration continue. A ProMyze nous avons vécu les limites du modèle par pull-request et du feature branching. Ces modèles, même s’ils sont intéressants, offrent moins d’avantage que le push to master.
Notre deuxième préconisation est de faire remonter au plus tôt tous les contrôles possibles. S’il vous est possible de faire remonter un contrôle dans le BENCH faites le. Sinon, faites tout pour les intégrer dans l’ANTIROOM. Avec un modèle push to master il est très facile d’effectuer tous les contrôles à ce niveau.
En allant plus loin on peut préciser où il serait préférable de faire quels contrôles :
Une autre question est de savoir si vous souhaitez effectuer des contrôles bloquants ou non-bloquants. Par bloquant on veut dire que si on ne passe pas le contrôle alors le code est bloqué dans le flux et ne peut pas aller plus loin. Par non bloquant on considère que le code avance dans le flux même s’il n’a pas passé les contrôles. Nous considérons que les tests peuvent être bloquant alors que les contrôles de dette technique ou de qualité (couverture de ligne de code) devraient être non bloquant.
Enfin, notre dernière préconisation est au coeur de l’engagement dans notre société ProMyze : faites des retours personnalisés. Les contrôles doivent uniquement porter sur les modifications réalisées par les développeurs et pas sur l’intégralité de l’application. Si un développeur modifie une ligne, il faut contrôler cette ligne et pas plus. C’est dans cet objectif que notre outil Themis a été conçu, quelque soit le modèle de flux que vous avez choisi.
Cet article vous a plu, vous a interpelé, vous voulez nous faire part de votre expérience sur un modèle de flux de code, n’hésitez pas à réagir. Nous ne prétendons pas avoir “la science infuse”, loin de là. Notre objectif est plutôt de participer à une discussion générale sur les différents environnements de développement, leurs avantages et leurs limites.
Social media