La mêlée et un développement stable sont-ils une contradiction?

11

Je fais partie d'un groupe de développement avec 5 équipes, un total d'environ 40 développeurs. Nous suivons la méthodologie Scrum, avec des sprints de 3 semaines. Nous avons une configuration d'intégration continue (Jenkins), avec un pipeline de construction prenant plusieurs heures (en raison de tests automatisés approfondis). Fondamentalement, le processus de développement fonctionne bien.

Cependant, nous observons qu'après quelques jours dans un nouveau sprint, notre build devient souvent instable et reste instable jusqu'à la fin du sprint "commit stop". L'effet néfaste de cela est que les étapes de construction loin dans le pipeline, en particulier les tests UI / Web ne sont pas exécutés pendant plusieurs jours (car ils ne sont déclenchés que sur une construction «verte»). Par conséquent, les bogues nouvellement introduits ne sont souvent détectés que très tard dans le sprint.

  • Chaque validation est vérifiée par rapport à un ensemble de tests de base. Une fois vérifié, le changement est poussé à maîtriser après une revue de code (Gerrit)
  • Les tests unitaires de base s'exécutent toutes les 30 min, durée inférieure à 10 min
  • Les tests d'intégration s'exécutent toutes les 2h, durée 1h
  • UI- / Webtests exécutés sur des tests d'intégration réussis, durée plusieurs heures

Selon qui est responsable de la stabilité de la construction pendant le sprint (cette responsabilité est transmise par sprint), il peut y avoir des "arrêts de validation" intermédiaires et ad hoc pour ramener la construction à stable.

Donc, nous voulons:

  1. Nos équipes de développement pour développer et valider des changements au cours d'un sprint sans entrave
  2. Notre processus de construction à abandonner si une étape de construction échoue, car les résultats de construction ultérieurs ont peu de sens
  3. Notre processus de construction pour fournir aux développeurs des commentaires de qualité en temps opportun

Étant donné (2), les points (1) et (3) semblent se contredire. Quelqu'un a-t-il une bonne pratique pour gérer cela?

( Nous relâchons actuellement le point (2) et autorisons la poursuite de la construction même en cas d'échec de la construction. Je n'ai pas encore de commentaires sur la façon dont cela influence notre qualité )

Merci Simon

Simon
la source
3
Je dirais que si une version prend, several hoursc'est le vrai problème. cela signifie que la solution combinée est trop grande et trop large. Vous devez chercher à composant la solution, puis disposer de petits morceaux de code sous forme de packages (disponibles d'une manière ou d'une autre dans toutes les langues principales sur toutes les plateformes). Ainsi, tout changement irait aux composants uniquement et sera détecté beaucoup plus rapidement. La construction complète consistera essentiellement à assembler des composants déjà combinés et sera également plus rapide. Vous ne pourrez alors éventuellement exécuter que quelques tests pour vous assurer que les bons composants ont été résolus.
zaitsman
Votre environnement de construction est-il sur site ou dans le cloud?
Lauri Laanti
@LauriLaanti, notre environnement de build est sur site, 1 instance Jenkins avec 3 esclaves.
Simon

Réponses:

7

Quelques principes de base en premier: - Les changements majeurs doivent toujours être sur une branche de fonctionnalité dans votre VCS - Les branches de fonctionnalité doivent passer tous les tests avant de fusionner dans le tronc. Ajouté - Les commits doivent toujours se construire - Une construction cassée nécessite une action immédiate de la part du committer et / ou du reste de l'équipe. - Un test ayant échoué ne doit interrompre les tests restants que s'il s'agit d'un test critique .

Si vous, en tant qu'équipe, suivez ces pratiques et les appliquez, par exemple: "nom et honte" lorsque la version est interrompue, alors vous devriez être prêt à aller car tous les commits qui pourraient interrompre la version seront sur une branche de fonctionnalité. Les autres validations qui interrompent la génération devront être traitées immédiatement, puis vous obtiendrez vos résultats de test en aval.

Vous pouvez également ajouter un test automatique de la dernière version "réussie", (pas nécessairement celle qui réussit les tests d'intégration), pour les tests UI / Web comme une exécution de nuit rapportant la première chose le matin.

Steve Barnes
la source
3
Une bonne pratique à ajouter ici est que les branches de fonctionnalités doivent passer tous les tests avant d'être fusionnées avec la ligne principale
Bart van Ingen Schenau
@BartvanIngenSchenau - bon point ajouté!
Steve Barnes
@SteveBarnes, merci pour l'entrée. Un commit dans Gerrit est toujours sur une branche, et n'est fusionné qu'en cas de succès (ma première puce dans le processus de construction). C'est après cela que le problème commence. Avec 30 développeurs effectuant des changements plusieurs fois par jour, nous devons fusionner tôt, puis vérifier. Il y a une action immédiate après une build cassée, mais comme le temps entre la validation et le feedback de la construction est de 2 heures, il y aura plusieurs autres validations dans l'intervalle. Peut-être casser la prochaine version.
Simon
@Simon le but du "nom et honte" est d'amener vos développeurs à arrêter de commettre du code cassé! Sur la plupart des systèmes, il est possible d'effectuer un build de test en peu de temps en utilisant des outils comme ant, make, scons, etc. Si votre projet est bien structuré, la plupart des langages permettent aux reconstructions partielles de tester si les choses vont se construire, (full / clean les constructions doivent encore être faites bien sûr).
Steve Barnes
8

N'a rien à voir avec Scrum. Votre build doit être stable en permanence, peu importe.

Personne ne devrait rien archiver à moins d'avoir effectué une construction locale et exécuté les tests unitaires localement (et les deux réussis, bien sûr). Votre processus de génération et de test local doit être sensible aux modifications et peut ignorer les tests de code qui n'a pas changé.

Toute personne qui introduit quelque chose qui entraîne l'échec de la génération ou l'échec d'un test unitaire doit être publiquement honteuse . Si la construction est cassée, elle doit être corrigée immédiatement.

John Wu
la source
2
D'une part, il convient de souligner que la construction de la stabilité est la responsabilité de tous. D'un autre côté, je déconseille la honte publique, car (1) les membres de l'équipe plus expérimentés ont une plus grande responsabilité pour aider les membres juniors à atteindre la stabilité (par la révision du code, la programmation par paire, ou tout simplement en travaillant étroitement ensemble avant un commit, ou en réparer une construction cassée ensemble), (2) la honte enlève la sécurité psychologique de l' équipe .
rwong
1
Si les gens ne veulent pas être honteux, ils ne devraient pas casser la construction. Ce n'est pas comme si c'était un niveau déraisonnablement élevé. Si vous avez des développeurs qui ne peuvent pas le pirater, laissez-les avoir leur propre branche pour jouer jusqu'à ce qu'ils découvrent comment ne pas briser les communs critiques de l'équipe. (Cela étant dit, toute honte réelle devrait être de bon goût).
John Wu
Dans notre processus, tout commit est ramifié (dans Gerrit), et doit passer un ensemble de tests de base avant de fusionner avec master. Ces tests de base ne peuvent pas fonctionner pendant une heure, car nous voulons réviser le code et fusionner rapidement. C'est après la fusion que le problème commence, voir mon commentaire à @SteveBarnes
Simon
6

Votre problème semble être que les tests sont trop longs à exécuter. Heureusement, la loi de Moore nous a fourni une solution à ce problème. Aujourd'hui, les processeurs de serveur haut de gamme peuvent facilement avoir plus de 10 cœurs (et plus de 10 HyperThreads). Il peut y avoir plusieurs processeurs de ce type sur un même ordinateur.

Si j'avais des tests qui prennent autant de temps, je résoudrais le problème avec plus de matériel. J'achèterais un serveur haut de gamme, puis paralléliserais les tests afin que les tests profitent pleinement de tous les cœurs de CPU. Si vos tests sont aujourd'hui mono-thread, tirer parti de 10 cœurs et 10 HyperThreds rend probablement les tests 15 fois plus rapides. Bien sûr, cela signifie qu'ils utilisent également 15 fois la mémoire, de sorte que l'ordinateur doit avoir suffisamment de RAM.

Ainsi, les quelques heures se transformeront en 10-30 minutes.

Vous n'avez pas dit combien de temps prend la construction, mais les outils de construction standard tels que make permettent de paralléliser également la construction. Si vous parallélisez vos tests unitaires et qu'un ordinateur de développeur typique possède 4 cœurs et 4 HyperThreads, les moins de 10 minutes de tests unitaires se transformeront en moins de 2 minutes. Donc, peut-être pourriez-vous appliquer une politique selon laquelle tout le monde devrait exécuter les tests unitaires avant de s’engager?

À propos de l'échec des tests arrêtant d'autres tests: ne faites pas cela sur le serveur de build! Vous voulez autant d'informations que possible sur l'échec, et d'autres tests pourraient révéler quelque chose d'important. Bien sûr, si la construction elle-même a échoué, vous ne pouvez pas exécuter de tests unitaires. Si le développeur exécute des tests unitaires sur sa propre machine, vous souhaiterez peut-être abandonner au premier échec.

Je ne vois aucun lien entre Scrum et vos problèmes. Les problèmes peuvent vraiment se produire avec n'importe quel processus de développement.

juhist
la source
Je suis d'accord, avec une construction plus rapide, les choses seraient beaucoup plus faciles. Notre TechTeam a passé des jours à améliorer la vitesse de notre processus de construction, sinon nous attendrions des jours au lieu d'heures. Pour l'instant, cette durée de rétroaction est donnée à env. 2 heures. Je recherche donc une approche qui considère cela comme un «donné». (Bien sûr, nous essayons continuellement d'accélérer la construction. Mais pour un avenir proche, ce sera 2 heures)
Simon
Certains tests peuvent entrer en conflit avec l'exécution parallèle
deFreitas
Il n'est possible d'y jeter plus de matériel que si les tests sont écrits de manière à pouvoir fonctionner indépendamment les uns des autres sans introduire d'effets secondaires. Plus vous vous éloignez du matériel, plus cela devient difficile ... la plupart des développeurs ne le font pas bien faire les choses, donc bien que je sois d'accord avec vous, je me concentrerais d'abord sur la bonne structuration des tests.
c_maker
2

N'est-il pas possible d'avoir plus d'installations Jenkins et de demander aux développeurs de vérifier une instance Jenkins distincte?

Je pense que la meilleure solution ici est de faire passer le code à tous les tests avant qu'il ne soit archivé dans la branche master et compilé / testé par l'instance principale de Jenkins. Ne laissez pas les gens archiver du code qui rompt la construction.

Je vérifie mon code dans la branche de développement, vois s'il passe les tests et crée une demande de pull. Mais vous pourriez évidemment demander à jenkins de tirer une branche de fonctionnalité et de la tester.

xyious
la source
1

Le point (2) semble être le point le plus douloureux, je vais donc me concentrer sur cela.

Il serait peut-être temps de diviser le projet en plusieurs modules.

https://en.wikipedia.org/wiki/Dependency_inversion_principle

A. Les modules de haut niveau ne doivent pas dépendre de modules de bas niveau. Les deux devraient dépendre d'abstractions.

B. Les abstractions ne devraient pas dépendre des détails. Les détails doivent dépendre des abstractions.

Si un module ne parvient pas à se construire, la construction des autres modules pourra continuer, tant que ces autres modules peuvent dépendre d'une interface et que le code qui compose cette interface a été construit avec succès.

Cela vous donnera des informations sur les autres échecs de génération susceptibles de se produire, afin que vous ayez le temps de réparer plus d'un module cassé avant la prochaine génération.

En général, les principes SOLID sont conçus pour traiter les problèmes de bibliothèques et de génération. En d'autres termes, cet ensemble de principes est conçu pour résoudre le type exact de problèmes auxquels vous êtes confronté.


En remarque (voir la réponse de juhist), vous ne pouvez pas accélérer la construction (par parallélisation) si vous ne partitionnez pas la construction en modules séparés.

rwong
la source
0

Je pense que votre équipe manque l'un des principes clés de la mêlée: terminé, logiciel fonctionnel. Un PBI ne doit pas être marqué comme terminé tant qu'il n'a pas atteint la définition de Terminé établie par votre équipe. La définition de Terminé est différente pour chaque équipe, mais inclurait probablement des éléments comme:

  • Le code a des tests unitaires
  • Test de réussite unitaire dans le cadre d'une construction automatisée
  • Le code a été fusionné en main (et les conflits ont été résolus)
  • etc.

Donc, essentiellement, ce qui se passe, c'est que votre équipe marque des choses comme qui ne le sont pas . C'est un problème en soi.

En dehors de cela, cela se résume à une bonne gestion du contrôle de version. Si vous utilisez Git, alors tout le travail est effectué dans le référentiel local du développeur et ils ne devraient rien pousser à distance à moins qu'il ne soit "terminé" et potentiellement libérable. Un travail incomplet ne doit jamais être poussé vers votre référentiel principal. Si le développeur doit travailler sur une branche de fonctionnalité plus longue et veut pousser à distance pour s'assurer qu'il ne perd pas son travail, alors il devrait travailler à partir d'une fourchette, et vous fusionneriez alors cette fourche en main lorsque le fonctionnalité est "terminée" et potentiellement libérable - pas avant.

Pour TFVC, c'est un peu plus compliqué car tout se passe sur "à distance". Cela signifie que les développeurs devraient donc toujours travailler hors des succursales, à moins que ce ne soit une solution rapide. Les mêmes règles s'appliquent ici qu'avec Git, cependant: les logiciels incomplets ne sont pas validés. Période. Dans le contrôle de version correctement géré, "main" doit toujours être libérable. Si un commit a été fait qui borks est "principal", alors vous ne le faites pas correctement.

Chris Pratt
la source