Comment gérez-vous l'intégration de code provenant de plusieurs branches / développeurs à chaque sprint?

42

Je viens de recevoir un appel rétro où les développeurs ont exprimé leur préoccupation quant à l'intégration de leurs histoires dans la branche principale à chaque sprint. Les développeurs codent tous dans leur propre branche et vers la fin du sprint, ils fusionnent tous en une seule branche principale.

Ensuite, il reste un développeur (généralement le même) chargé de s’assurer que tout s’intègre bien avec le code des autres développeurs (la plupart des modifications se trouvent sur la même page. Par exemple, une histoire d’affichage des données, une histoire de filtrage des données, et un indicateur SLA).

Comment pouvons-nous réduire ce fardeau et faciliter la fusion de notre code? De mon point de vue, le fait que le bon de commande ou le gestionnaire de priorités hiérarchise les histoires de manière plus efficace, de sorte que nous n'ayons pas ce type de dépendances dans le même sprint, pourrait résoudre certains problèmes. Comment chacun aborde-t-il cela? Ou est-ce juste une partie du processus?

cuisinier
la source
18
N'avez-vous pas une branche de développement où l'intégration continue est faite?
Kayaman
13
Je suis avec Kayaman ici, la meilleure pratique consiste à implémenter une intégration continue.
RandomUs1r
27
Bonne journée de fusion! Chaque fois que votre problème ressemble trop à quelque chose du Daily WTF, vous savez que vous avez des problèmes.
user3067860
Fusionnez tôt, fusionnez souvent: {écrivez le plus petit code de test qui échouera (en rouge), écrivez le plus petit code de production qui passera (en vert), refactor, retester, fusionner} sans avoir fini.
ctrl-alt-delor
1
Premier enregistrement gagne! Ne sois jamais le dernier! :-)
ChuckCottrill

Réponses:

88

Si vous utilisez Git, chaque développeur tire de la developbranche dans sa propre branche de fonctionnalité afin de s’assurer qu’il ne s’éloigne pas trop de la base actuelle. Ils peuvent le faire quotidiennement, de sorte que les tâches qui durent plus de deux jours restent synchronisées et que les problèmes de fusion soient résolus tant qu'ils sont encore petits.

Lorsque le développeur a terminé son travail, il crée une demande d'extraction . Une fois approuvé, cela est fusionné dans la developbranche.

La developbranche devrait toujours avoir du code de travail et être prête pour la publication à tout moment. Lorsque vous effectuez en fait une version, vous fusionnez developdans masteret taguez.

Si vous disposez d'un bon serveur Continuous Integration Server, chaque branche sera créée lors de l'enregistrement des modifications, en particulier pour les demandes d'extraction. Certains serveurs de génération s'intègrent à votre serveur Git pour approuver ou refuser automatiquement une demande d'extraction si la construction échoue ou si les tests automatisés échouent. C'est une autre façon de trouver des bogues d'intégration potentiels.

Berin Loritsch
la source
73
La partie importante (qui n’est implicite que dans votre réponse) est que les branches doivent être fusionnées dès qu’elles sont prêtes, généralement avec seulement 1 à 5 validations, et pas seulement à la fin du sprint. Une branche par article / histoire, pas une branche par développeur. Cela nécessite que les histoires soient vraiment minuscules, c'est-à-dire prennent au plus deux jours.
amon
@amon, d'accord. Ajout des mots "branche de fonctionnalité", mais en essayant de garder cette réponse assez petite. Il y a beaucoup de bons articles qui approfondissent ce processus.
Berin Loritsch
5
Ne restez pas isolé sur votre propre branche. C'est comme ça que l'enfer commence. Utilisez le développement sur ligne principale, isolez les travaux en cours derrière les basculements de fonctions ou toute autre configuration d'exécution.
Rob Crawford
3
@Zibbobz Mon équipe utilise des "branches de fonctionnalités" explicites pour celles qui sont fondamentalement traitées de la même manière que la branche de développement, mais uniquement pour les demandes d'extraction et les validations liées à ce changement. Généralement, selon la durée pendant laquelle il doit rester séparé, tous les quelques jours, une personne fusionne les modifications apportées à la fonctionnalité et résout les problèmes éventuels. De cette façon, les branches sont aussi similaires que possible au moment de la fusion. A noter que ce n’est que pour les très grands changements
reffu
9
"isoler les travaux en cours derrière les basculements de fonctions ou toute autre configuration au moment de l'exécution" Vous venez d'éviter de fusionner l'enfer en entrant dans l'enfer de la configuration. "Merge hell" n’est un problème que pour un développeur à la fois et il est facilement évité par une synchronisation régulière: disposer de tonnes de configuration éphémère est un enfer pour tous les futurs développeurs.
Cubique
23

J'ai travaillé dans une équipe où nous avons lutté avec le même problème. Nous avons constaté que moins nous avions de temps avant l'intégration, moins cela devenait difficile. Je sais que la plupart des enseignants en intégration continue parlent d'engagement toutes les quelques minutes - nous nous sommes probablement engagés toutes les heures environ.

Nous avons également constaté que la construction ne suffisait pas. Nous avions besoin d'un bon niveau de couverture de test afin de nous assurer que nous ne casserions pas accidentellement le code de chacun.

Daniel
la source
2
C'est aussi mon expérience. Peu importe la fréquence à laquelle vous vous engagez, une fois que vous l'engagez rapidement, l'intégration / la fusion de la validation économise beaucoup d'effort sur toute la ligne. Une fois, j’étais sur un projet dans lequel nous avions trois branches de développement divergentes qui avaient chacune des mois de travail. Les fusionner n'était pas amusant. J'ai beaucoup appris de cette erreur :)
amon
4
Oui, c'est ce que signifie "intégration continue"! Vous intégrez en permanence vos modifications aux modifications des autres développeurs!
Rob Crawford
@Rob, d'accord. Ma déclaration ne visait pas à suggérer que l'intégration continue n'est pas, bien, continue. Juste que nous n’avions pas fait l’idéal et que nous en avions encore beaucoup.
Daniel
12
  • Gardez vos branches éphémères (on dirait que vous le faites déjà).
  • Laissez les résultats de vos tests parler d'eux-mêmes.
  • N'attendez pas la fin du sprint.

Vous n'avez même pas besoin de vous abonner à TDD pour celui-ci. Tout ce dont vous avez besoin sont quelques tests qui prouvent que les fonctionnalités de vos développeurs fonctionnent correctement. Ceux-ci pourraient inclure des tests unitaires et des tests d'intégration, mais constitueraient idéalement deux tests automatisés de bout en bout des fonctionnalités critiques. Trucs de pack de régression standard.

Ensuite, une fois votre fusion terminée, vous pouvez vérifier le rapport de test d'automatisation ensemble et vérifier que tout a été intégré avec succès.

Je suis d’accord avec l’une des autres réponses dans lesquelles l’auteur a déclaré que les relations publiques de Git permettraient de résoudre ce problème en amenant chaque développeur à fusionner son propre travail.

Un autre point qui, à mon avis, est suffisamment important pour rester jusqu'au dernier paragraphe. Je suggère que vous exécutiez des tests manuels sur vos versions nocturnes, plutôt que d’attendre la fin du sprint. Les développeurs doivent fusionner dès que la fonctionnalité est terminée afin de pouvoir l'intégrer, la déployer et la tester le plus rapidement possible.

Liath
la source
6

Ne pas

En fonction de votre langue et des fichiers que vous modifiez, il peut ne pas être judicieux que chaque développeur les modifie sur sa propre branche. Par exemple, en C #, il est préférable qu'une seule personne puisse éditer des fichiers de concepteur d'interface utilisateur à la fois. Il s’agit de fichiers générés automatiquement. Par conséquent, le code est parfois déplacé sans raison apparente - ce qui cause des ravages sur la plupart des outils de fusion.

Cela signifie que certaines histoires peuvent en bloquer d'autres jusqu'à ce que le travail de l'interface utilisateur soit terminé. Et / ou, une nouvelle histoire est créée pour simplement mettre en page l'interface utilisateur, les autres histoires implémentant des fonctionnalités. Ou peut-être qu'un développeur effectue tout le travail d'interface utilisateur pendant que d'autres implémentent les fonctionnalités de cette interface utilisateur.

Sur une note connexe, si vous savez que plusieurs histoires vont toutes toucher le même fichier, vous voudrez peut-être simplement éviter de les traiter toutes en même temps. Ne les tirez pas tous dans le même sprint ou ne commencez pas à les travailler tous avant qu'un ou plusieurs ne soient terminés.

mmathis
la source
Honnêtement, l'outil de contrôle de version utilisé est plus essentiel au succès de la création de branches et de la fusion. Même avec le code C # et probablement le code WinForms ou WebForms avec lequel vous devez travailler, en général, cela ne change pas beaucoup . Si tel est le cas, vous devrez peut-être faire des maquettes avant de jouer avec du code. Les interfaces utilisateur basées sur le XAML sont aussi stables que le code standard et le code intermédiaire n'est pas
archivé
2
@BerinLoritsch Le code de concepteur WinForms peut en effet beaucoup changer, même avec de petits changements visuels. J'ai constaté que les lignes de code elles-mêmes sont identiques, mais l'ordre est très différent, en particulier lorsque plusieurs développeurs effectuent des modifications en même temps. C’est peut-être un problème d’outil VCS (nous en avons utilisé plusieurs, peut-être n’utilisons-nous que les mauvais), mais pour nous, il est beaucoup plus simple de modifier légèrement notre processus.
mmathis
2
@BerinLoritsch Je dois donner un second mot à mmathis ici, au moins pour les formes gagnantes (jamais utilisées pour les formes Web). Le concepteur d’interface utilisateur de winforms aime réorganiser au hasard tout le code du fichier du concepteur en réponse à une modification anodine, quelque part sur le formulaire. Sauf si vous annulez manuellement les réordonnances avant chaque validation (quelque chose qui peut facilement prendre 10 à 15 minutes sur un formulaire complexe), l'historique du fichier de concepteur est absolument inutile et si deux personnes travaillent simultanément sur l'interface du formulaire, le résultat sera: un conflit de fusion de l'enfer. Verrouiller est généralement une option terrible, mais avec Winforms est vraiment le moins mal.
Dan Neely
@DanNeely, Ce n'est qu'une des raisons pour lesquelles notre équipe a abandonné le code WinForms. Une autre raison est que le concepteur est terriblement fragile et que certaines de nos formes complexes ne peuvent de toute façon pas être modifiées de manière visuelle. Nous avons fini par apporter des modifications directement dans le code ci-dessous - probablement pourquoi je ne me souviens pas trop de bouleversements. Cela et nos utilisateurs qui travaillent avec des écrans haute densité nous ont vraiment poussés vers WPF. Un processus douloureux avec une courbe d'apprentissage élevée, mais une belle récompense à la fin. La plupart des articles de l'arriéré concernaient de toute façon différentes parties de l'application.
Berin Loritsch
@BerinLoritsch idem ici. Les formulaires Win ont payé une grande partie de mes factures pendant presque une décennie à mon emploi précédent, mais je serai assez heureux de ne plus jamais y toucher à l'avenir.
Dan Neely
2

Les drapeaux de caractéristiques sont une autre approche possible pour éviter les fusions tardives et volumineuses : vous protégez vos modifications avec un drapeau configurable (idéalement de manière dynamique) qui les empêche de devenir actives avant la fin prévue.

Cela vous permet de fusionner vos modifications très tôt dans l'une masterou l' autre de vos branches de développement conjoint sans rien casser. Les autres développeurs peuvent ensuite fusionner ces modifications dans leurs branches de fonctionnalités (ou rebasonner leurs branches en conséquence).

Comme les autres réponses l'ont déjà indiqué, cette solution devrait être associée à une solution d'intégration continue.

Les indicateurs de fonctionnalité présentent des avantages supplémentaires (par exemple, ils facilitent les tests A / B). Voir cet article de Martin Fowler pour plus d'informations.

Florian Brucker
la source
0

Nous suivons une approche de branche de développement distincte pour chaque fonctionnalité, puis nous fusionnons les branches en une branche d'assurance de la qualité pour les tester dans un environnement de test d'intégration.

Une fois les tests de régression et d'intégration terminés, nous déplaçons facilement les fonctionnalités prêtes à l'emploi vers la branche des versions.

Si tout se passe bien, nous fusionnons la branche release avec la branche master.

emarshah
la source
0

En termes simples, engager et fusionner réduit souvent la fenêtre d'opportunité pour la fusion de conflits et réduira considérablement les conflits. L’autre partie concerne en effet la planification par le chef de file, ce qui peut garantir une plus grande fluidité du travail.

Les autres réponses donnent un bon aperçu des meilleures pratiques pour les commits. En les observant, vous réduirez probablement la grande majorité de vos problèmes de fusion. Plus de fusions sont certainement une nécessité, mais pour une petite équipe, votre approche de branche par personne fonctionne probablement assez bien. Bien sûr, cela ne fait pas mal (beaucoup) d'entrer dans des pratiques plus extensibles!

Cependant, personne ne semble avoir répondu à l'une de vos questions les plus importantes: que faire lorsque vous touchez tous aux mêmes zones de code. C’est pourquoi il est utile de faire appel à un chef de projet qui connaît bien la base de code et peut reconnaître les dépendances de différentes tâches. S'ils n'orchestrent pas le temps de travail et les validations, vous vous retrouverez probablement avec des conflits de fusion et une résolution ligne par ligne. Organiser les tâches \ chronométrer est beaucoup plus difficile avec une équipe plus grande, mais avec une petite équipe, il est possible d'identifier ces tâches contradictoires. Le responsable pourrait alors même confier toutes les tâches liées au même ingénieur, afin d'éviter le conflit.

Mars
la source