Comment gagner en stabilité et en prévisibilité

adesso Blog

Trop souvent, les systèmes sont mis à mal par des bugs, ou pire, des bugs sont découverts sur le terrain et nécessitent une nouvelle série de tests et de déploiements. Cela finit par coûter du temps et de l'argent, tout en affectant négativement la réputation de l'entreprise. De plus, les délais ne sont pas respectés et tout le cycle de test/déploiement doit être recommencé. Notre modèle de branchement est conçu comme une solution à ce problème. En effet, il se concentre principalement sur la stabilité des versions actuelles et à venir. Cela est particulièrement important dans les environnements où les déploiements et les tests sont coûteux et chronophages (comme c'est souvent le cas avec les systèmes embarqués).

La stabilité d'abord : un modèle pour des versions fiables et prévisibles

J'ai souvent rejoint des groupes de développement logiciel et entendu la phrase "nous utilisons Git Flow". Bien que cela ait pu être vrai au tout début, diverses pressions et expériences peuvent amener les organisations à muter lentement vers leur propre système. Un tel système que j'ai souvent rencontré est quelque chose que j'aime appeler le "modèle de branchement basé sur les versions".

Dans ce modèle, il n'y a pas de développement continu, mais plutôt une série de version en cascade. Ces versions sont créées dès qu'une fonctionnalité est en développement et prévue pour elles. Les fonctionnalités sont ensuite fusionnées dans les versions, et les versions sont immédiatement fusionnées "vers le haut" dans les versions ultérieures. La séparation immédiate des branches permet d'isoler les fonctionnalités, le refactoring et les corrections de bugs (et donc les nouveaux bugs) les uns des autres, de sorte qu'au lieu de "fusionner dans le développement quand c'est fait", ces éléments sont repoussés dans le futur et fusionnés dans quelque chose d'autre que la prochaine version.

L'effet net de cette stratégie est l'augmentation globale de la qualité et de la stabilité du logiciel en raison de l'isolement précoce des branches de version planifiées. Cet effet a un coût léger en termes de l’effort fourni par les développeurs en raison du plus grand nombre de fusions (et éventuellement de conflits de fusion), mais généralement, l'augmentation de la stabilité compense largement.

Planifier à l'avance : créer des branches le plus tôt possible pour un meilleur contrôle

À première vue, il pourrait sembler que la principale différence entre ce modèle et Git Flow serait le fait qu'il n'y ait pas de branche de développement. En pratique, ce n'est pas vrai : il y aura toujours une "plus haute" version, c'est juste une branche de "développement" qui est continuellement renommée.

La différence clé avec ce modèle de branchement réside dans le moment où de nouvelles branches de version sont créées. Alors qu'avec Git Flow, une décision est prise pour "stabiliser le développement" en créant une branche de version, ce modèle de branchement se concentre quant à lui sur la création d'une branche de version dès qu'une fonctionnalité est prévue pour une version spécifique. Cela permet à la prochaine version de ne recevoir que des fonctionnalités, des corrections ou des refactorisations spécifiques planifiées.

Les différentes branches doivent être nommées pour indiquer la version générale (par exemple release/20.x), et les versions spécifiques doivent être étiquetées (par exemple release/20.1.0). De l'espace doit être laissé dans ce schéma pour d’éventuelles corrections, qui peuvent ensuite se brancher à partir de versions spécifiques, être étiquetés de manière appropriée, puis fusionnées dans la version active la plus basse. La dénomination des branches de correctifs peut avoir son propre désignateur (par exemple hotfix/20.1.0.1), mais en pratique, la dénomination est quelque peu moins importante car les branches de correctifs (comme toutes les autres branches) doivent être supprimées après avoir été étiquetées comme une version et fusionnées vers le haut.

Les branches "main" ou "master" ne sont alors plus nécessaires. Il est parfois utile pour un projet d'indiquer sa version actuelle, auquel cas la branche principale peut être utilisée et placée manuellement sur des versions étiquetées spécifiques au lieu d'avoir une version fusionnée. Cela maintient tous les hachages de version identiques, ce qui est important.

Description du modèle et illustration avec des exemples

Il est plus facile de comprendre ce système en utilisant des exemples concrets plutôt que des descriptions abstraites.

Dans cet exemple, la première étape serait de renommer une branche de "développement" existante pour l'aligner avec la prochaine version à venir, disons "release/4.5.x". À ce stade, le développement continue comme d'habitude, et la fonctionnalité "A" est fusionnée dans le release/4.5.x.

Dès qu'une nouvelle fonctionnalité ou correction de bug est prévue pour une version ultérieure, une nouvelle branche doit être créée, par exemple "release/4.6.x" avec les fonctionnalités prévues "B" et "C" se branchant à partir de 4.5.x.

Il est probable que le développement continue sur 4.5.x, donc il recevra deux corrections de bugs d'exemple "D" et "E". La correction de bug "D" est fusionnée d'abord dans 4.5.x puis la branche release/4.5.x est immédiatement fusionnée dans release/4.6.x.

Ensuite, la correction de bug "E" est fusionnée dans 4.5.x. Cela complète la version 4.5.x, donc cette branche reçoit l'étiquette "release/4.5.0". Dans cet exemple, il y a malheureusement un conflit entre 4.5.x (ayant juste reçu la correction de bug "E") et 4.6.x. Pour résoudre cela, une branche de fusion : "merge/4.5-4.6" est créée à partir de release/4.6.x. Ici, la branche 4.5.x est fusionnée, les conflits sont résolus, puis toute la branche est fusionnée de nouveau dans 4.6.x, où la fonctionnalité prévue ultérieure "C" est également fusionnée.

Fusion proactive : éviter que les petits problèmes ne deviennent de gros problèmes

Avec ce système de branchement, l'une des meilleures règles à suivre est de "fusionner vers le haut dès que possible". Cela empêche les petits problèmes de se transformer en plus gros. Donc, dès qu'une fusion se produit dans une branche de version inférieure, ces branches doivent être fusionnées vers le haut immédiatement. Idéalement, un système automatisé serait utilisé pour cela.

La planification est également un élément clé de ce système, mais elle se heurte souvent au désir d'avoir de nouvelles fonctionnalités plus tôt. Dans ces cas, la seule option est de sélectionner des fonctionnalités fusionnées dans des versions ultérieures pour les ramener dans de nouvelles branches, ciblant des branches antérieures. D'un point de vue Git, ce n’est pas idéal, mais cela ne devrait pas poser de problème lors de la fusion ascendante ultérieure.

Le refactoring, dans les versions plus récentes, devient un problème lors de la fusion des versions antérieures. Souvent, une extrême prudence doit être prise pour s'assurer que la fonctionnalité fusionnée vers le haut est correctement intégrée dans le nouveau code. Cet effort fait cependant partie d'un compromis: l'objectif de cette stratégie de branchement est la stabilité des versions antérieures.

Un autre problème possible survient lorsque des corrections de bugs ou des fonctionnalités "one off" sont implémentées dans des versions antérieures, mais qu’elles ne sont pas souhaitées dans les versions ultérieures. Dans ce cas, le paramètre "-sours" pour git merge est très utile, permettant de maintenir la connexion entre les branches de version. Mais la fonctionnalité antérieure n'est pas fusionnée vers le haut. Cette connexion de fusion est toujours importante à faire, plutôt que de laisser une branche de version "pendante" non fusionnée. Il est important de signifier aux développeurs que la fonctionnalité n'a pas simplement été "oubliée", ce qui risquerait de l'inclure dans toute fusion ascendante ultérieure.

Fazit

Cette approche contraste avec les stratégies de branchement modernes plus populaires, qui favorisent souvent des branches principales uniques pour une fusion et un déploiement continus. Cependant, ce modèle se présente comme une solution pratique à des contraintes spécifiques. Souvent, cette méthode est accueillie avec résistance par les développeurs, qui voient principalement le coût accru de leur effort en ce qui concerne la fusion et la résolution des conflits de fusion. Lorsqu'on la considère du point de vue organisationnel global, les gains en stabilité des versions compensent souvent cet investissement initial.

Avez-vous des questions sur les stratégies de branchement, ou souhaitez-vous optimiser vos processus de développement ? Nos experts chez adesso se feront un plaisir de vous aider.


En savoir plus

  • Business Process Automation : développez votre avantage concurrentiel

    Automatisez vos processus et améliorez votre efficacité. Avec nos solutions sur mesure, vous pouvez rationaliser vos flux de travail, réduire vos coûts et libérer de l'espace pour l'innovation. En savoir plus

  • IoT & Embedded Systems

    Exploitez tout le potentiel de l'IoT et des systèmes embarqués pour vos produits numériques. Nous vous accompagnons dans le développement de solutions intelligentes qui connectent vos systèmes et les rendent pérennes. En savoir plus

  • Testing by adesso

    Assurez la qualité de vos logiciels grâce à des services de test professionnels. Nous garantissons des résultats fiables et veillons à ce que vos applications fonctionnent parfaitement. En savoir plus

Photo Lane Westlund

Auteur Lane Westlund

Lane Westlund est ingénieur logiciel senior chez adesso Switzerland, spécialisé dans le développement embarqué.