Cet article explore les principes du décalage vers la gauche et suggère que les PR empilés deviendront de plus en plus utiles.
Le processus de revue de code par les pairs est une partie essentielle du développement logiciel. Il aide à maintenir la qualité des logiciels et favorise le respect des normes, des exigences du projet, des guides de style et facilite l'apprentissage et le transfert des connaissances.
Alors que l'efficacité est élevée pour examiner des changements de code suffisamment petits, elle chute de façon exponentielle avec l'augmentation de la taille du changement. Pour maintenir le niveau de concentration mentale nécessaire pour être efficace, les grandes revues de code sont épuisantes.
Habituellement, plus la durée de l'examen est longue, moins l'examen global devient efficace :
Alors pourquoi ne pouvons-nous pas simplement limiter la taille des pull requests (PR) ? Alors que de nombreux changements peuvent commencer petit, un petit changement de deux lignes peut soudainement se transformer en un refactor de 500 lignes, y compris de multiples échanges avec les réviseurs.
Certaines équipes d'ingénierie maintiennent également des branches de fonctionnalités de longue durée tout en continuant à travailler, ce qui rend la révision difficile.
Alors, comment trouver le juste équilibre ? Simple. Utilisez des PR empilés.
Les demandes d'extraction empilées effectuent des modifications itératives plus petites et sont empilées les unes sur les autres au lieu de regrouper de grandes modifications monolithes dans une seule demande d'extraction. Chaque PR de la pile se concentre sur un seul changement logique, ce qui rend le processus de révision plus gérable et moins chronophage.
Nous avons également écrit un article l'année dernière expliquant comment cette aide représente les changements de code comme un récit au lieu de décomposer les choses par fichiers ou fonctionnalités.
Outre la création d'une culture d'examens de code plus efficaces, les PR empilés présentent quelques autres avantages :
Imaginez que vous implémentez une grande fonctionnalité. Au lieu de créer l'intégralité de la fonctionnalité, puis de demander une révision du code, envisagez de découper le cadre initial et de le soumettre rapidement à des commentaires.
Cela pourrait potentiellement vous faire économiser d'innombrables heures en obtenant des commentaires précoces sur votre conception.
Les PR empilés prennent en charge la pratique du décalage vers la gauche car les modifications sont continuellement intégrées et testées, ce qui permet une détection et une correction précoces des problèmes.
Les modifications sont fusionnées par morceaux, ce qui permet de détecter rapidement les problèmes par rapport à la fusion d'un changement géant en espérant qu'il ne réduira pas la prod !
Les revues de code sont également merveilleuses pour la postérité. Vos modifications de code racontent votre processus de réflexion derrière la mise en œuvre d'une fonctionnalité, par conséquent, la répartition des modifications crée un transfert de connaissances plus efficace.
Il est plus facile pour les membres de l'équipe de comprendre les changements, ce qui favorise un meilleur partage des connaissances pour l'avenir.
Attendre que le code soit examiné et approuvé peut être un processus frustrant. Avec les PR empilés, les développeurs peuvent travailler sur plusieurs parties d'une fonctionnalité sans attendre que les examinateurs approuvent les PR précédents
Alors, pourquoi n'y a-t-il pas plus de développeurs qui utilisent des PR empilés pour les revues de code ?
Bien que ce flux de travail de relations publiques empilé réponde à la fois aux pratiques souhaitées pour maintenir la gestion des révisions de code et la productivité des développeurs, malheureusement, il n'est pas très bien pris en charge de manière native par Git ou GitHub.
En conséquence, plusieurs outils ont été développés au sein de la communauté open source pour permettre aux ingénieurs d'intégrer cette technique d'empilement dans les plates-formes Git et GitHub existantes. Mais empiler les PR n'est qu'une partie de l'histoire.
Au fur et à mesure que nous recevons des commentaires sur la révision du code et que nous apportons des modifications à la partie de la pile, nous devons maintenant rebaser et résoudre les conflits dans toutes les branches suivantes.
Prenons un exemple. Imaginez que vous travaillez sur un changement qui nécessite un changement de schéma, un changement de backend et un changement de frontend.
Avec cela, vous pouvez maintenant envoyer un simple changement de schéma pour examen en premier, et pendant que cela est en cours d'examen, vous pouvez commencer à travailler sur le backend et le frontend. En utilisant des PR empilés, tous ces 3 changements peuvent être examinés par 3 examens différents.
Dans ce cas, vous pouvez avoir une pile qui ressemble à ceci où demo/schema
, demo/backend
et demo/frontend
représentent les 3 branches empilées les unes sur les autres.
Jusqu'à présent, cela a du sens, mais que se passe-t-il si vous avez des commentaires de révision de code sur le changement de schéma qui nécessite la création d'un nouveau commit ? Soudain, votre historique de validation ressemble à ceci :
Maintenant, vous devez rebaser manuellement toutes les branches suivantes et résoudre les conflits à chaque étape. Imaginez si vous avez 10 branches empilées où vous devrez peut-être résoudre les conflits 10 fois.
Mais ce n'est pas tout, fusionner un PR dans la pile peut être un vrai cauchemar. Vous avez 3 options squash
, merge
et rebase
pour fusionner un PR. Essayons de comprendre ce qui se passe dans les coulisses de chacun.
squash
, Git prend les modifications de tous les commits existants du PR et les réécrit dans un seul commit. Dans ce cas, aucun historique n'est conservé sur l'origine de ces modifications.
Un commit merge
est un type spécial de commit Git qui est représenté par une combinaison de deux commits ou plus. Ainsi, cela fonctionne de manière très similaire à un commit squash
mais il capture également des informations sur ses parents. Dans un scénario typique, un commit de fusion a deux parents : le dernier commit sur la branche de base (où le PR est fusionné) et le commit supérieur sur la branche de fonctionnalité qui a été fusionnée.
Bien que cette approche donne plus de contexte à l'historique de validation, elle crée par inadvertance un historique git non linéaire qui peut être indésirable.
rebase
et de fusion, Git réécrira les commits sur la branche de base. Ainsi, similaire à l'option de validation squash
, il perdra tout historique associé aux validations d'origine.
En règle générale, si vous utilisez la stratégie de validation merge
lors de l'empilement des PR, votre vie sera un peu plus simple, mais la plupart des équipes découragent l'utilisation de cette stratégie pour garder l'historique git propre. Cela signifie que vous utilisez probablement un squash
ou une fusion rebase
.
Et cela crée un conflit de fusion pour toutes les branches empilées non fusionnées suivantes.
Dans l'exemple ci-dessus, disons que nous fusionnons la première branche demo/schema
dans la ligne principale. Il créera un nouveau commit D1
contenant les modifications de A1
et A2
.
Étant donné que Git ne sait pas d'où vient D1
et que demo/backend
est toujours basé sur A2
, essayer de rebaser demo/backend
au-dessus de la ligne principale créera des conflits de fusion.
De même, rebaser demo/frontend
après rebaser demo/backend
causera également les mêmes problèmes. Donc, si vous aviez dix branches empilées et que vous fusionniez l'une d'entre elles, vous devriez résoudre ces conflits neuf fois.
Nous ne faisons qu'effleurer la surface; il existe de nombreux autres cas d'utilisation tels que la réorganisation des commits, le fractionnement, le pliage et le changement de nom des branches, qui peuvent créer d'énormes frais généraux à gérer lorsqu'il s'agit de PR empilés.
C'est pourquoi nous avons construit une gestion des relations publiques empilées dans le cadre d'Aviator.
Considérez Aviator comme une couche d'augmentation qui se trouve au-dessus de votre outillage existant. Aviator se connecte à GitHub, Slack, Chrome et Git CLI pour offrir une expérience de développement améliorée.
Aviator CLI fonctionne de manière transparente avec tout le reste ! La CLI n'est pas seulement une couche au-dessus de Git, mais comprend également le contexte des piles sur GitHub. Prenons un exemple.
Créer une pile est assez simple. Sauf dans ce cas, nous utilisons av
CLI pour créer les branches afin de nous assurer que la pile est suivie. Par exemple, pour créer votre branche de schéma et le PR correspondant, suivez les étapes ci-dessous.
av stack branch demo/schema # make schema changes git commit -a -m "[demo] schema changes" av pr create
Comme Aviator est également connecté à votre GitHub, cela vous permet de visualiser facilement la pile.
Ou si vous souhaitez le visualiser depuis le terminal, vous pouvez toujours le faire avec les commandes CLI :
L'utilisation de la pile devient désormais un jeu d'enfant. Vous pouvez ajouter de nouveaux commits à n'importe quelle branche et exécuter simplement av stack sync
depuis n'importe où dans la pile pour synchroniser toutes les branches. Aviator rebase automatiquement toutes les branches pour vous, et s'il y a un vrai conflit de fusion, vous n'avez qu'à le résoudre une fois.
C'est là que les outils Aviator se démarquent facilement de tout outillage existant. Chez Aviator, nous avons construit l'une des MergeQueue les plus avancées pour gérer la fusion automatique de milliers de modifications à grande échelle.
Aviator prend en charge une intégration transparente avec la CLI et les PR empilés. Ainsi, pour fusionner une pile partielle ou complète de PR, vous pouvez les affecter à Aviator MergeQueue à l'aide de CLI av pr queue
ou en publiant un commentaire sur GitHub : /aviator stack merge
.
Aviator gère automatiquement la validation, la mise à jour et la fusion automatique de toutes les piles en file d'attente dans l'ordre.
Maintenant, lorsque les PR sont fusionnés, vous pouvez cette fois exécuter av stack sync --trunk
pour mettre à jour tous les PR et nettoyer tous les PR fusionnés.
Les PR empilés peuvent initialement sembler plus de travail en raison de la nécessité de décomposer les modifications en parties plus petites. Cependant, l'augmentation de l'efficacité de la révision du code, des boucles de rétroaction plus rapides et des opportunités d'apprentissage améliorées compenseront certainement ces frais généraux.
Alors que nous continuons à adopter les principes du décalage vers la gauche, les PR empilés deviendront de plus en plus utiles.
L'Aviator CLI offre un excellent moyen de gérer les PR empilés avec beaucoup moins d'ennui. La CLI est open source et entièrement gratuite. Nous aimerions que vous l'essayiez et que vous partagiez vos commentaires sur notre forum de discussion .
Chez Aviator, nous construisons des outils de productivité pour les développeurs à partir des premiers principes pour permettre aux développeurs de construire plus rapidement et mieux.