Dans ce deuxième chapitre de notre série – DevOps pour la victoire, nous explorons les étapes initiales et cruciales d'une démarche de transformation DevOps. Les premiers pas d'une transformation sont souvent les plus difficiles. En matière de DevOps, il est essentiel d'identifier les bonnes mesures initiales, à la fois percutantes et réalisables, pour progresser concrètement.
De nombreuses organisations commettent l'erreur d'appliquer aveuglément les meilleures pratiques sans tenir compte de leurs contraintes spécifiques, ce qui génère souvent frustration et fatigue face à l'échec. Une approche plus stratégique est requise : elle consiste à identifier les goulets d'étranglement pour les éliminer méthodiquement.
Comment identifier les premières étapes ?
Un principe puissant pour savoir par où commencer est issu de recherches publiées il y a 30 ans dans l'ouvrage Le But : un processus d'amélioration continue d'Eliyahu M. Goldratt. L'idée est simple : identifier le principal goulet d'étranglement, c'est-à-dire le facteur limitant qui restreint les performances du système. Dans notre cas, cela est apparu clairement lorsque nous avons vu le travail s'accumuler au sein de l'équipe de développement. Les tâches étaient entamées mais non achevées, et l'arriéré n'cessait de croître.
Pour en identifier les causes profondes, nous avons organisé des sessions approfondies avec les équipes de développement, les responsables techniques et les chefs de produit. Ces discussions ont mis en lumière plusieurs problèmes majeurs :
- Les équipes acceptaient de nouvelles tâches avant d'avoir terminé celles en cours.
- Il n'existait aucun critère clair d'achèvement des tâches : la définition de « terminé » selon les développeurs différait souvent des attentes des parties prenantes.
- Aucune mesure objective de la qualité n'était en place avant de valider le travail, ce qui entraînait des défauts et des retouches.
- Les réaffectations fréquentes ont nui à la stabilité des équipes et généré des inefficacités.
Mise en place d'équipes stables
L'une des premières mesures correctives a consisté à restructurer les équipes pour garantir cohérence et concentration. Plutôt que de traiter des groupes d'individus comme des groupes de travail ponctuels, nous avons constitué des équipes stables et pérennes dotées de responsabilités clairement définies.
Mettre sur pied certaines équipes, comme celles de développement, s'est avéré relativement simple. En revanche, l'organisation des équipes de soutien – telles que l'infrastructure, la gestion de projet, la gestion de produit et l'analyse commerciale – s'est révélée plus délicate. Nous avons dû procéder à plusieurs essais pour trouver les bonnes combinaisons.
En suivant le principe de priorité à l'équipe présenté dans l'ouvrage Team Topologies de Matthew Skelton et Manuel Pais, nous avons :
- Créé de petites équipes autonomes (de 4 à 7 membres) afin de stimuler l'expertise sectorielle approfondie et la responsabilisation.
- Suppression des dépendances entre les équipes en veillant à ce que chaque personne soit entièrement affectée à une seule équipe.
- Adaptation des structures d'équipe, en particulier pour les fonctions de soutien telles que l'infrastructure et la gestion des produits, afin d'optimiser le flux de travail.
Utilisation d'outils pour la visibilité et la gestion
Une fois les équipes structurées, nous avons adopté Azure DevOps pour la gestion des carnets de produits et des tâches. Une plateforme unifiée a permis :
- Une meilleure visibilité du travail afin que les équipes puissent suivre les progrès en toute transparence.
- Des définitions normalisées de « l'état terminé » pour harmoniser les attentes entre les services.
- Une meilleure gestion du carnet de commandes, ce qui réduit la dérive des objectifs et les conflits de priorités.
Imposition de critères de qualité objectifs
Pour résoudre le problème du manque de clarté des mesures de qualité avant de marquer les tâches comme « prêtes pour les tests », nous avons intégré un outil d'analyse statique du code, fournissant des perspectives objectives sur :
- La couverture du code
- Les vulnérabilités de sécurité
- Les anomalies de code
Nous avons également amélioré notre définition de « l'état terminé » pour faire des contrôles de qualité une étape obligatoire avant de marquer les éléments de travail comme achevés.
Gestion du travail en cours (WIP)
L'un des changements les plus marquants a été la surveillance et la limitation du travail en cours (WIP). Un niveau élevé de WIP mettait en évidence des goulets d'étranglement, ce qui nous a permis d'intervenir de manière proactive sur les zones où l'activité ralentissait.
Cette approche systématique, ancrée dans The Goal et Team Topologies, a jeté les bases d'une amélioration continue, réduisant les dépendances et améliorant la responsabilisation.
Au cours de notre démarche de transformation DevOps, l'une de nos plus grandes prises de conscience a été qu'après les améliorations initiales, le principal frein au flux de travail s'était déplacé vers la conception logicielle, plus précisément vers la testabilité de notre code. Après avoir résolu les premiers goulets d'étranglement en améliorant la configuration des équipes, en définissant une « définition de fini » et en mettant en œuvre l'analyse de code, nous avons constaté que le travail s'accumulait pendant la phase de test. Le code développé par les équipes Scrum attendait souvent d'être testé par les membres de l'équipe QA au sein de ces mêmes équipes Scrum.
Résolution du goulet d'étranglement suivant : l'écart de tests
Une fois les goulets d'étranglement initiaux résolus, une nouvelle contrainte est apparue : les retards de tests. Alors que les tâches de développement progressaient efficacement, les tests sont devenus un obstacle, empêchant des livraisons plus rapides. Après enquête, nous avons identifié les principaux défis qui ralentissaient le processus :
- Recours aux tests manuels : La plupart des tests étaient exécutés manuellement, ce qui entraînait des boucles de rétroaction lentes et une détection tardive des défauts.
- Dépendance de l'interface utilisateur lors des tests : Les composants de l'interface utilisateur étant généralement achevés en dernier, les tests ne pouvaient pas commencer avant la fin du cycle de développement.
- Absence d'automatisation proactive : Les tests automatisés, tels que les tests d'interface utilisateur basés sur Selenium, n'étaient rédigés qu'après les tests manuels, ce qui limitait leur efficacité lors de la validation préliminaire.
Passage à des approches axées d'abord sur les tests
Pour surmonter ce goulet d'étranglement, nous avons donné la priorité aux tests unitaires et aux tests d'API par rapport aux tests d'interface utilisateur. Ce changement a nécessité des transformations fondamentales dans l'état d'esprit du développement et la conception des logiciels :
Améliorations des tests d'API
Pour rendre les tests d'API efficaces :
- Des APIs bien définies : les APIs devaient être simples, bien documentées et disponibles dès le début de la phase de développement afin que les testeurs puissent créer des cas de test de manière proactive.
- Éviter la base de données comme point d'intégration:
- L'utilisation de bases de données comme point d'intégration entre les équipes a créé des dépendances qui ont ralenti les tests.
- La création de cas de test nécessitait la configuration de bases de données comportant des données complexes, ce qui augmentait le temps de préparation et limitait la possibilité de tester de multiples scénarios.
- En passant à une intégration basée sur les API (principalement REST sur HTTP et, plus récemment, GraphQL), nous avons considérablement réduit les retards et la complexité induits par les dépendances des bases de données.
Ce changement a permis d'accélérer l'automatisation des cas de test pour les APIs, prouvant que se concentrer sur une conception axée sur les APIs améliorait à la fois la testabilité et l'efficacité.
Renforcer les pratiques de test unitaires
Les tests unitaires ont posé un défi plus important :
- Progrès rapides, puis couverture de façade : Au départ, nous avons atteint des niveaux élevés de couverture de code, mais les revues de code ont révélé que de nombreux tests unitaires étaient superficiels, rédigés uniquement pour atteindre les objectifs de couverture. Ces tests ne parvenaient pas à vérifier les fonctionnalités importantes, à couvrir les scénarios d'échec ou à valider les cas limites.
- Changer les mentalités : Les développeurs devaient comprendre la valeur des tests unitaires, non seulement pour améliorer la qualité du code, mais aussi pour accélérer le développement en détectant les problèmes plus tôt.
Difficultés liées à l'écriture de code testable
Le principal obstacle à l'efficacité des tests unitaires était l'absence de testabilité du code source lui-même. Les principaux problèmes étaient les suivants :
- Fonctions vastes et monolithiques.
- Composants fortement couplés.
- Mauvaise séparation des préoccupations.
- Abstraction insuffisante.
Ces problèmes rendaient difficile l'isolation et le test efficace de chaque unité. Pour y remédier, nous avons :
- Fourni des lignes directrices : Nous avons partagé les meilleures pratiques concernant :
- Sélectionné les fonctions destinées aux tests unitaires.
- Refactorisé le code pour améliorer la testabilité.
- Conçu et utilisé des simulations (mocks) pour faciliter les tests.
- Accent mis sur les améliorations progressives : Les développeurs ont été encouragés à apporter de petits changements significatifs pour améliorer la testabilité au fil du temps.
Progrès, défis et perspectives d'avenir
Pour les produits existants, l'amélioration de la testabilité est restée un processus lent en raison de contraintes architecturales. Cependant, ces actions ne visaient pas seulement à améliorer la base de code actuelle ; elles constituaient un investissement pour l'avenir :
- Les développeurs ont adopté de meilleures habitudes en intégrant la testabilité dans les nouvelles bases de code.
- Les équipes sont devenues plus autonomes, réduisant leur dépendance à l'égard des efforts externes de QA.
- L'organisation a éradiqué les erreurs passées, garantissant ainsi que les futurs produits seraient plus faciles à maintenir et à faire évoluer.
L'enseignement principal ? Le DevOps ne se résume pas à l'adoption d'outils ou de listes de contrôle. Il s'agit d'améliorer continuellement le flux de travail, un verrou à la fois.
Dans le prochain chapitre de cette série, nous aborderons la « Conception axée sur la testabilité ». Nous verrons en détail comment l'amélioration de la conception logicielle permet de lever les contraintes de test, favorisant des boucles de rétroaction plus rapides et une meilleure qualité logicielle. En agissant d'abord sur la structure des équipes, puis sur la gestion des flux de travail et enfin sur la testabilité, nous posons les bases d'une transformation DevOps pérenne.
