Je suis toujours ingénieur logiciel en formation, mais j'ai entendu à plusieurs reprises l'adage suivant:
Les bons codeurs n'ont pas à gérer les conflits de fusion.
Chaque fois que je travaille sur un projet avec d'autres, je perds beaucoup de temps et d'efforts à résoudre les conflits de fusion. Alors, j'ai commencé à me demander à quel point cet adage est vrai. Je connais des techniques comme GitFlow et agile qui permettent aux développeurs de fractionner efficacement leur travail, de s'engager plus souvent et de maintenir plusieurs branches de code, donc les conflits de fusion sont beaucoup moins probables. Mais ils se produisent sûrement encore et peuvent potentiellement faire des ravages?
En d'autres termes, combien de temps et d'efforts les développeurs chevronnés perdent-ils pour résoudre les conflits de fusion (quand ils pourraient travailler sur leurs projets)? Les techniques disponibles sont-elles capables d'annuler réellement les effets des conflits de fusion?
Je pense qu'il est un peu fallacieux de dire que les bons développeurs n'ont jamais de conflits de fusion, mais ils peuvent sûrement réduire le nombre de fois que cela se produit. Il est également très important de se rappeler que le développement de logiciels est une activité d'équipe. Les actions d'autres membres des équipes peuvent également augmenter ou diminuer la probabilité de conflits de fusion.
Tout d'abord, il est important de comprendre les façons courantes dont les conflits de fusion se produisent:
.vsproj
des dossiers)Développement équipes ont trouvé des moyens d'éviter ces situations:
Avec de tels changements, vous pouvez réduire considérablement la probabilité de conflits. Vous ne pourrez jamais les éliminer complètement.
La citation est probablement incomplète:
Les bons codeurs n'ont pas à gérer les conflits de fusion ...
... parce que les bons codeurs poussent la force.
Sérieusement, cependant, la seule façon d'éviter les conflits de fusion est de travailler seul (et même cela n'aide pas; il m'est arrivé d'avoir des conflits de fusion avec moi-même sur des projets personnels). Dans une entreprise qui embauche des développeurs expérimentés, il existe cependant trois facteurs qui réduisent la douleur des conflits de fusion:
Excellente communication au sein de l'équipe.
Autrement dit, vous savez sur quoi vos collègues travaillent et ils savent ce que vous faites. Par conséquent, lorsque vous modifiez éventuellement un domaine sur lequel un membre de votre équipe travaille, vous demandez (ou vous dites). De cette façon, vous réduisez considérablement le risque d'un commit douloureux.
Cela s'applique en particulier à celles des tâches de refactoring qui pourraient affecter de manière substantielle une grande partie de la base de code, ou effectuer des changements qui sont pénibles à fusionner. Supposons que vous modifiez le type d'une variable donnée partout, pendant que votre collègue implémente une fonctionnalité dans laquelle cette variable est utilisée. Non seulement vous risquez d'avoir un conflit de fusion douloureux, mais aussi de casser la construction pendant la fusion.
Grande architecture.
Si vous travaillez sur une base de code héritée avec des fichiers 4K-LOC et que vous avez besoin de toute modification de base pour modifier des dizaines de fichiers, il y a des chances qu'à chaque changement, vous obtiendrez un conflit de fusion.
D'un autre côté, lorsque l'architecture est suffisamment bonne, vous réduisez le risque d'avoir un conflit de fusion à deux situations: (1) où vous modifiez une interface, ou (2) où deux collègues modifient exactement la même partie de l'application . Dans le premier cas, vous communiquez, réduisant encore plus le risque d'une fusion douloureuse. Dans le second cas, vous effectuez une programmation par paires, supprimant complètement la fusion.
Interface appropriée avec d'autres équipes.
Parfois, il arrive qu'il y ait des conflits de fusion entre différentes équipes. Supposons qu'une équipe modifie un module, tandis qu'une autre modifie le code qui utilise ce module.
Les développeurs expérimentés auraient tendance à adopter des interfaces appropriées, telles que SOA, ce qui rendrait les parties distinctes du système plus indépendantes sur le plan technique. De plus, ils s'appuieront beaucoup plus sur des pratiques spécifiques telles que les requêtes Push pour éviter de modifier directement le code de quelqu'un d'autre.
Il s'agit essentiellement des deux premiers points, mais inter-équipes: vous communiquez mieux et vous vous assurez que les pièces sont plus entremêlées.
Un de mes collègues est tombé sur un développeur qui n'a pas eu à gérer les conflits de fusion.
Il a fait quelques changements, les a fusionnés et quelques jours plus tard, les changements avaient disparu. Il a découvert que quelqu'un d'autre (sur un autre continent également) avait remplacé des fichiers au lieu de fusionner.
Il remit les changements en place, légèrement vexé - et quelques jours plus tard, les changements avaient de nouveau disparu.
C'est à ce moment-là qu'il a eu une longue conversation avec son manager, qui à son tour a eu une longue conversation avec le manager de l'autre équipe, qui peut ou non inclure des menaces de violence physique, et le manager de l'autre équipe a apparemment eu une longue conversation avec le développeur dans question, et le comportement a cessé.
Cela dit, les développeurs expérimentés peuvent éviter certains conflits de fusion.
Lorsque vous renommez un fichier, effectuez une fusion où renommer le fichier (et évidemment les changements causés par cela, comme changer les instructions d'inclusion ou les fichiers de projet) est absolument le seul changement.
Assurez-vous que les paramètres de l'éditeur de tout le monde sont les mêmes, afin de ne pas créer de modifications simplement en regardant le code.
Vous obtenez des conflits de fusion si deux personnes changent de code au même endroit. Donc, si vous ajoutez à un fichier, n'ajoutez pas à la fin, mais ajoutez à l'endroit logiquement correct. De cette façon, si un autre développeur fait de même, les conflits de fusion sont beaucoup moins probables.
Fusionnez de temps en temps la base de code commune dans votre branche, afin de ne jamais avoir de conflits de fusion many. Un conflit est facile, 10 dans une fusion sont un problème.
La fusion de votre branche vers la base de code commune doit jamais provoquer un conflit. C'est parce que vous avez fait (4) juste avant d'essayer de faire la fusion, donc la fusion finira par prendre votre code sans aucun changement.
Juste remarqué: Oui, c'est vrai, les bons développeurs n'ont jamais de conflits de fusion fusionnant de leur branche dans la base de code commune. Parce que tous les conflits de fusion ont été traités plus tôt.
Comme d'autres réponses l'ont décrit, les conflits de fusion se produisent indépendamment de l'expérience ou des compétences, et un adage qui prétend qu'il s'agit d'une sorte de faiblesse provenant d'un manque de compétences est ridicule.
D'autres réponses ont noté des façons dont les développeurs qualifiés peuvent apprendre à rendre les conflits de fusion moins probables, en empêchant le chaos de mise en forme, les fusions fréquentes et une meilleure coordination d'équipe, mais je pense qu'il y a du vrai dans le concept plus large que vous soulevez: les développeurs qualifiés peuvent devenir meilleurs gérer les conflits de fusion lorsqu'ils surviennent.
La résolution des conflits de fusion est délicate. Vous devez trouver les conflits, comprendre les marqueurs de conflit, comprendre ce qui a changé de chaque côté compte tenu du contexte du code (impliquant éventuellement des problèmes difficiles à repérer comme le formatage), peut-être rechercher des validations individuelles des deux côtés de la fusion pour comprendre l'intention d'origine, résoudre réellement le conflit, traiter les implications possibles du changement ailleurs dans la base de code (ou même dans d'autres référentiels si des API ou des interfaces sont impliquées), compiler, tester, valider, etc ... Vous devez vous rappeler comment demandez au système de contrôle de version de faire ce que vous voulez pendant ce processus. Et puis il y a des cas plus compliqués: conflits impliquant des fichiers et répertoires déplacés/supprimés; conflits impliquant des fichiers binaires; les conflits impliquant des fichiers générés (y compris des choses comme les fichiers de configuration Visual Studio et Xcode; même si le conflit est simple, le fichier lui-même ne sera pas familier jusqu'à ce que vous en ayez une certaine expérience); conflits assez désagréables où vous allez trouver la personne de l'autre côté de la fusion et le découvrir ensemble; toutes sortes de plaisir.
C'est beaucoup de choses à gérer. Cela peut provoquer un peu de panique: vous roulez avec impatience pour emballer quelque chose, et tout à coup, vous êtes confronté à des messages d'erreur, des trucs ">>>>>>>" étranges au milieu de vos fichiers, et un tas de code inconnu qui est soudainement apparu ailleurs. Comme toute autre tâche de programmation, l'expérience peut aider à développer les compétences pour y faire face plus efficacement et moins douloureusement. La première fois que vous rencontrez un conflit de fusion, c'est une épreuve déroutante, tandis que la 500e fois est plus routinière. Par ce point:
Avec tout cela, la plupart des conflits de fusion deviennent routiniers, donc moins de temps et d'efforts sont consacrés à leur résolution. Ils se produisent toujours et causent parfois une frustration importante, mais causent généralement beaucoup moins de ravages.
Ce n'est pas tant l'existence de conflits de fusion, mais l'ampleur du problème qu'ils causent.
Les "dommages" des conflits de fusion avec des développeurs inexpérimentés sont considérés comme un énorme problème. Les gens inventent des schémas de contrôle de source fous ou même cessent d'utiliser le contrôle de source tous ensemble pour éviter ces problèmes "massifs".
Mais avec une équipe expérimentée, les conflits de fusion ne posent pratiquement aucun problème et sont résolus rapidement.
Je pense qu'il y a deux différences d'approche principales qui contribuent à cela:
Utiliser le contrôle de source correctement. Branches caractéristiques, beaucoup de petits commits, tirer avant de pousser, tester avant de pousser, etc.
Comprendre les changements des autres peuples. Si vous comprenez les modifications de fonctionnalités et de code qui sont en conflit avec votre modification, la fusion des deux est simple.
Faites attention aux autres tâches lors des stand-ups, discutez avec d'autres personnes de la façon dont ils mettent en œuvre le changement et des points sur lesquels vous pouvez entrer en conflit. Convenez à l'avance de la façon dont les choses devraient fonctionner.
Pour comprendre pourquoi CI aide à considérer que pour expérimenter un conflit de fusion, le ou les changements dans cette branche doivent entrer en conflit avec un ou plusieurs changements sur le maître:
A B C
master *--*--*--*--*
\ /
feature-x *--------
Plus la branche existe depuis longtemps, plus les modifications seront effectuées sur le maître, et donc plus les chances que l'une de ces modifications provoque un conflit (même si la modification sur la branche est très faible):
A B C D E F G H
master *--*--*--*--*--*--*--*--*--*
\ /
feature-x *-----------------------
Il y a diverses choses que nous pouvons faire pour réduire les risques de conflit entre 2 changements (comme éviter de reformater ou organiser soigneusement le travail pour éviter que plusieurs développeurs travaillent sur la même zone), mais l'approche la plus simple consiste à simplement fusionner les changements plus rapidement, en réduisant le nombre de changements effectués sur le maître, et à son tour la possibilité d'un conflit:
A B C
master *--*--*--*--*--*
\ / \ /
feature-x *-- *--
Si vous pratiquez correctement l'IC, alors tout le monde devrait s'engager dans une branche partagée plusieurs fois par jour , c'est-à-dire une fois toutes les quelques heures. C'est assez rapide pour que la plupart du temps, il n'y ait pas de changements sur master, et encore moins des changements contradictoires. Ce qui est encore mieux, c'est que même si vous voyez un conflit, vos modifications seront minimes et donc la résolution du conflit devrait être relativement simple - dans le pire des cas (où vous devez rejeter et implémenter complètement votre changement), vous avez perdu à la plupart des quelques heures de travail.
Dans les commentaires, il a été suggéré que les développeurs fusionnent régulièrement de master au lieu de master, ce qui est certainement utile, mais pas autant qu'une intégration continue. Par exemple, dans le graphique suivant, chaque validation sur le maître (A, B et C) a une chance d'entrer en conflit avec l'une des validations de la branche (X, Y ou Z), pour un total de 9 conflits potentiels. Fusionner une fois en maître à la fin signifie que les 9 conflits potentiels doivent être résolus en même temps:
A B C
master *--*--*--*--*
\ /
feature *--*--*--
X Y Z
Si au lieu de cela, nous fusionnons de maître dans notre branche de fonctionnalité après chaque changement sur maître:
A B C
master *--*-----*-----*---*
\ \ \ \ /
feature *--*--*--*--*--*
X Y Z
Ensuite, chaque fois que nous fusionnons, nous devons faire face aux conflits suivants:
Notez cependant que nous n'avons jamais eu besoin de résoudre les conflits entre A et Y, car la modification A a été fusionnée dans notre branche de fonctionnalité avant la modification Y. Au total, nous avons réussi à éviter 3 des 9 conflits de fusion potentiels en fusionnant régulièrement avec le maître.
Notez également que chaque fois que nous fusionnons, le nombre de conflits potentiels augmente - plus la branche de fonctionnalité existe, plus de changements (et donc de conflits potentiels) seront effectués sur le maître, mais le vrai tueur ici est que chaque modification que nous apportons sur la branche de fonctionnalité a un effet multiplicateur sur le nombre de conflits potentiels à chaque fusion.
Voyons maintenant ce qui aurait pu arriver si nous pratiquions l'IC:
A B C
master *--*--*--*--*--*--*
\ / \ / \ /
feature *-- *-- *--
X Y Z
Cette fois, nous avons dû faire face aux conflits de fusion suivants:
Comme auparavant, nous n'avons jamais eu besoin de résoudre les conflits entre A et Y, car le changement A était déjà fusionné dans notre branche de fonctionnalité avant de faire le changement Y, mais cette fois nous n'avons pas non plus besoin de fusionner les changements X et B, X et C ou Y et C, en évitant 6 des 9 conflits potentiels.
Voir cette question pour plus d'informations/conseils sur la fusion régulière avec master:
"Les programmeurs font des erreurs tout le temps " --- John Carmack
Les personnes qui font des affirmations semblables à "Je suis un développeur" rockstar "" ou "Les bons codeurs n'ont pas à gérer les conflits de fusion ..." sont le plus souvent des poseurs qui semblent être nombreux dans la communauté générale du développement de logiciels. et devrait être sommairement ignoré en tant que tel.
Construire un logiciel qui sera en production utilisé par des personnes réelles en dehors de vous n'est pas une mince affaire. Vous ferez des erreurs ... et les gens avec qui vous travaillez feront souvent des erreurs. Fonder une évaluation de la compétence d'ingénierie de quiconque sur la question de savoir s'ils doivent gérer des conflits de fusion est un non-sens à première vue.
Celui qui a dit cela a en tête une notion particulière de "bon codeur", qui va probablement comme ceci: