Dans notre série en cours DevOps pour la Victoire, nous documentons notre parcours de transformation DevOps. Dans le chapitre 1, nous avons présenté le Triangle DevOps : Outils, Architecture et Personnes dans le Développement de Produits, où nous avons discuté des éléments fondamentaux qui sont les moteurs du succès de DevOps. Dans le chapitre 2, nous avons exploré Les Premières Étapes de Notre Transformation DevOps, partageant comment nous avons jeté les bases de changements significatifs.
Maintenant, dans le chapitre 3, nous abordons le prochain défi majeur que nous avons rencontré : la conception pour la testabilité. Après avoir amélioré la structure de notre équipe, affiné notre définition de « terminé » et mis en œuvre l'analyse automatisée du code, nous avons réalisé que le principal goulot d'étranglement de notre pipeline s'était déplacé vers la conception logicielle – plus précisément, la testabilité. Le travail s'accumulait dans la phase de test, nous empêchant d'atteindre des cycles de publication plus rapides. Ce chapitre explore comment nous avons surmonté ce défi et amélioré notre capacité à livrer des logiciels de haute qualité de manière efficace.
Le goulot d'étranglement des tests.
La principale raison de ce retard était que les tests étaient principalement manuels, se concentrant sur les tests d'interface utilisateur et les flux de travail des utilisateurs. Étant donné que l'interface utilisateur était généralement l'un des derniers éléments à être achevés, il y avait peu ou pas d'automatisation en place, et les tests manuels sont devenus la seule approche viable. Les cas de test d'interface utilisateur automatisés (par exemple, les tests Selenium) étaient généralement écrits après la fin des tests manuels, principalement à des fins de régression.
Cette dépendance aux tests manuels a entraîné :
- Retards importants dans les versions logicielles.
- Le besoin de déploiements multiples pour permettre des tests parallèles par plus d'un membre de l'équipe QA.
Cela a souligné l'importance de rendre le code plus testable pour optimiser le flux de valeur. Cependant, y parvenir s'est avéré plus difficile que prévu.
Prioriser les tests d'API et les tests unitaires
Pour relever ce défi, nous nous sommes concentrés sur deux domaines principaux :
- Tests unitaires - Garantir que les composants individuels pouvaient être testés de manière isolée.
- Tests d'API - Réduire la dépendance aux tests basés sur l'interface utilisateur et aux dépendances de base de données.
Tests d'APIs : Déplacement vers la gauche pour un retour plus rapide
Nous avons redéfini notre stratégie de test d'API avec ces améliorations clés :
- APIs bien définies - Les APIs ont été conçues pour être simples, bien documentées et disponibles dès le début du développement.
- Éviter la base de données comme point d'intégration - S'appuyer sur des bases de données pour l'intégration a créé des dépendances qui ont ralenti les tests. Au lieu de cela, nous nous sommes orientés vers une intégration basée sur les API en utilisant REST sur HTTP et GraphQL. Cela a minimisé le temps de configuration de la base de données et amélioré l'automatisation des tests.
Ce changement a considérablement réduit les délais, permettant une automatisation plus rapide et des tests précoces, démontrant qu'une approche axée sur les conceptions API-first a amélioré à la fois la testabilité et l'efficacité.
Tests unitaires : Un changement de mentalité
Initialement, nos efforts de tests unitaires ont entraîné une augmentation rapide de la couverture des tests, mais nous avons rapidement identifié des problèmes :
- Certains tests étaient superficiels, rédigés uniquement pour atteindre les objectifs de couverture de code.
- Ils manquaient de validation significative des fonctionnalités, des cas limites et des scénarios d'échec.
Pour y remédier, nous avons souligné :
- Former les développeurs à la rédaction de tests pertinents.
- Refactoriser le code pour améliorer la testabilité.
Défis liés à la rédaction de code testable
Le plus grand obstacle aux tests unitaires efficaces était le manque de testabilité dans la base de code elle-même. Les problèmes clés comprenaient :
- Fonctions larges et monolithiques.
- Composants étroitement couplés.
- Mauvaise séparation des préoccupations.
- Abstraction insuffisante.
Ces problèmes rendaient difficile l'isolement et le test efficace des unités individuelles. Pour y remédier, nous avons :
- Fournir des lignes directrices: Nous avons partagé les meilleures pratiques concernant :
- Sélection des fonctions pour les tests unitaires.
- Refactoriser le code pour améliorer la testabilité.
- Concevoir et utiliser des maquettes pour faciliter les tests.
- Axé sur les améliorations progressives : Les développeurs ont été encouragés à apporter des changements petits mais significatifs pour améliorer la testabilité au fil du temps.
Progrès lent mais constant
Malgré ces efforts, les progrès étaient lents, en particulier pour les produits existants. L'architecture existante limitait le nombre de tests unitaires que nous pouvions écrire. Cependant, ces actions ne visaient pas seulement à améliorer la base de code actuelle, elles représentaient un investissement pour l'avenir :
- L'amélioration des compétences des développeurs dans la conception de code testable a permis de s'assurer que les futurs projets ne rencontreraient pas les mêmes problèmes.
- Les améliorations progressives ont évité les perturbations tout en augmentant régulièrement la couverture de l'automatisation des tests.
- Un changement de mentalité a aidé les équipes à considérer la testabilité non pas comme un fardeau, mais comme une nécessité pour le succès durable de DevOps.
Pour les équipes et les organisations qui s'engagent dans une transformation DevOps, la testabilité est un domaine d'attention essentiel. Elle aide à atténuer les goulots d'étranglement dans la phase de développement. Cependant, il est important de gérer les attentes : des résultats immédiats pourraient ne pas être possibles, surtout lorsqu'il s'agit de grandes bases de code existantes. La refactorisation d'un tel code sans tests unitaires et de régression suffisants est un défi majeur.
Leçons tirées de The Pragmatic Programmer
Pour les scénarios où démarrer avec une nouvelle base de code n'est pas réalisable, The Pragmatic Programmer: Your Journey to Mastery, par Andy Hunt et David Thomas offre des conseils pratiques :
- Cibler les changements incrémentiels : Concentrez-vous sur la refactorisation de petites parties gérables de la base de code.
- Découpler les composants : Réduire les dépendances pour faciliter le test des unités individuelles.
- Décomposer les fonctions monolithiques : Diviser les fonctions importantes en unités plus petites et plus ciblées.
- Adopter une conception modulaire : Rendre le code plus testable et maintenable en améliorant la modularité.
Le message est clair : une fois les goulots d'étranglement initiaux résolus, la testabilité doit devenir un axe prioritaire. Cela permettra d'alléger les contraintes de la phase de test et d'accélérer la livraison de logiciels de haute qualité.
Perspectives d'avenir
Notre parcours pour améliorer la testabilité nous a appris de précieuses leçons sur le rôle de la conception logicielle pour permettre des transformations DevOps fluides. En nous concentrant sur la testabilité, nous avons résolu les goulots d'étranglement, amélioré les compétences des développeurs et jeté les bases d'un succès futur. Bien que les résultats immédiats puissent être lents, les avantages à long terme en termes de qualité, d'efficacité et de croissance de l'équipe rendent cet investissement rentable.
Alors que nous poursuivons notre parcours DevOps, mesurer le succès devient le prochain défi majeur. Dans le Chapitre 4, nous explorerons comment nous avons établi des KPI et des tableaux de bord pour suivre nos progrès et identifier d'autres domaines d'amélioration.
Restez à l'écoute pour découvrir comment la prise de décision basée sur les données nous a aidés à affiner nos processus DevOps et à optimiser nos performances !