J'ai travaillé sur un grand système de transactions financières pour une banque qui s'occupait des pensions et des investissements. Après 15 ans de changements de fonctionnalités, le coût du test de régression manuelle était passé à 200 000 $ par version. (10M LOC, 10M $ traités par jour). Ce système s'interface également avec 19 autres systèmes de l'entreprise qui déplacent de nombreuses données. Ce système a été implémenté en Java.
Ce que nous observons cependant, c'est que plus nous réutilisons, plus les coûts des tests de régression augmentent. (La raison étant que vous devez "tester le code que vous touchez" - et que le code réutilisé / partagé a un impact sur une multiplicité d'endroits quand il est touché. - nous observons une incitation financière à copier et coller du code. Cela permet de réduire les coûts des tests de régression, car nous ne voulons pas modifier le code qui pourrait être partagé, car cela entraînerait un impact important du test de régression.)
Ma question est la suivante : existe-t-il un principe de génie logiciel qui décrit la relation entre les coûts de réutilisation et de régression?
La raison pour laquelle je poserais cette question est qu'il est sans doute avantageux de décomposer le système en parties plus petites à tester.
Hypothèses:
«Test de régression» signifie «test d'acceptation» - c'est-à-dire qu'un autre groupe passe du temps à écrire de nouveaux tests et à réutiliser d'anciens tests sur le système au nom de l'entreprise, y compris l'environnement et les configurations de données.
Je sais que la réaction instinctive à un gros coût de test de régression est «des tests plus automatisés». C’est un bon principe. Dans cet environnement, il y a quelques défis.
(a) Les tests automatisés sont moins utiles au-delà des frontières du système, à moins que ce système n'ait également une couverture de test automatisée élevée. (Défi sphère d'influence).
(b) Il est culturellement difficile d'obtenir un élan sur le temps du programmeur ou un investissement en capital sur une couverture de test automatisée élevée lorsque votre système est déjà volumineux et complexe.
(c) Le coût de la maintenance des tests automatisés est caché dans un projet et peut donc être facilement éliminé au niveau du projet.
(d) C'est juste la réalité culturelle du travail dans une banque.
(e) Je travaille pour résoudre ce problème d'une manière différente (décomposition).
la source
Réponses:
Les sons ci-dessus me conviennent. Plus le code est important, plus il est partagé, plus les exigences de qualité sont élevées, plus l'assurance qualité doit être impliquée lorsqu'il change.
Puisque votre système est implémenté en Java, vous pouvez voir un exemple ci-dessus, dans les bibliothèques standard Java (JDK). Ses versions majeures sont peu fréquentes et s'accompagnent de tests très gourmands. Et même des versions mineures passent par une suite de tests JCK très complète pour vérifier l'absence de régressions.
Vous pensez peut-être que cela étouffe en quelque sorte l'évolution du code partagé, et ... oui, c'est à peu près juste. Plus l'impact et le risque sont associés au changement de code, plus vous devez faire attention à le faire, plus d'efforts doivent être impliqués dans le test de ses versions.
Idéalement, la qualité des versions de code largement partagé devrait être telle qu'elle ne nécessite pas de grands changements (sauf pour des améliorations peu fréquentes). Cette ligne de pensée se reflète dans une célèbre citation de Joshua Bloch :
Cela dit, il semble que certains des problèmes que vous décrivez soient causés par une stratégie inefficace de développement de code partagé. En particulier, il semble particulièrement gênant que pour le code réutilisé, seules deux options soient envisagées: soit dupliquer ce code, soit l'inclure immédiatement dans les bibliothèques partagées "de base".
Il n'est pas nécessaire de se limiter à ces deux options et, encore une fois, vous pouvez trouver des exemples de la meilleure façon de le faire dans le JDK que vous utilisez. Jetez un coup d'œil aux
java.util.concurrent
packages ( JSR 166 ) - jusqu'à la version Java 5, il s'agissait d'une bibliothèque distincte, qui ne faisait pas partie des versions JDK principales.Pensez-y, c'est une troisième option que vous avez négligée, et assez pragmatique, celle que vous devez considérer lors de la "création" du nouveau code partagé. Lorsque vous venez de comprendre du code qui peut être partagé entre 2-3 composants, rien ne vous oblige à l'inclure immédiatement dans l'API de base du système.
Vous pouvez empaqueter et publier ce code partagé "immature" en tant que bibliothèque distincte, comme cela a été fait pour les utilitaires Java simultanés. De cette façon, vous évitez d'avoir à effectuer des tests de régression complets, car vous ne pouvez utiliser qu'une quantité relativement faible de composants impliqués. En conséquence, vous avez plus de latitude pour modifier et améliorer ce code partagé et pour tester son fonctionnement en production.
Une fois que votre bibliothèque est arrivée à maturité et s'est suffisamment stabilisée pour vous donner l'assurance que de nouveaux changements sont improbables, vous pouvez envisager son inclusion dans les bibliothèques principales du système, tout comme les utilitaires concurrents ont finalement été inclus dans JDK.
Un exemple concret de combien d'efforts (y compris les tests) peuvent être impliqués dans la modification de code fortement réutilisé peut être trouvé, encore une fois, dans JDK. Dans la version 7u6, ils ont changé la
String
représentation interne, ce qui a entraîné un changement desubstring
performances. Les commentaires d'un développeur de fonctionnalités chez Reddit décrivent combien d'efforts ont été impliqués dans ce changement:la source
Je ne pense pas qu'il existe de métriques pour calculer "le coût des tests de régression / LOC du code réutilisé construit". Et je ne pense pas que quiconque ait jamais investi autant de temps et d'argent pour construire le même "gros" système deux fois, une version avec beaucoup de composants réutilisables, et une sans, pour faire des recherches sérieuses à ce sujet.
Mais j'ai vu des problèmes causés par une réutilisation comme la vôtre auparavant, et peut-être êtes-vous intéressé par quelques réflexions sur la façon de mieux gérer cela.
Tout d'abord, ce n'est pas la réutilisation qui est votre problème - c'est plutôt la tentative de construire vos propres composants réutilisables et de les utiliser dans votre système. Je suis sûr que vous réutilisez beaucoup de gros progiciels où vos problèmes ne se posent pas: pensez à la pile Java entière que vous utilisez, ou peut-être à certains composants tiers (en supposant que vous soyez satisfait de ces composants). Mais qu'est-ce qui est différent avec ce logiciel, par exemple, les bibliothèques Java, alors que vos propres composants réutilisables vous causent tellement de coûts supplémentaires pour les tests de régression? Voici quelques points qui, je suppose, pourraient être différents:
ces composants sont très matures et stables
ils sont développés et entièrement testés isolément, par une organisation complètement différente
pour les (ré) utiliser, vous n'avez pas à les changer (en fait vous ne pourriez pas même si vous le souhaitez, car vous ne conservez pas le code source)
vous n'obtenez pas quotidiennement une nouvelle version, seulement des mises à jour mineures (au maximum par mois), ou des mises à jour majeures à intervalles par an
la plupart des mises à jour sont conçues pour être compatibles à 100% vers le bas, en particulier les mises à jour mineures
Donc, pour rendre vos propres composants réutilisables plus efficaces, vous devez adapter certaines de ces choses d'en haut pour votre propre développement:
pour tout composant réutilisable, ayez une responsabilité claire qui s'occupe de la maintenance et assurez-vous que toutes les personnes qui réutilisent un composant peuvent être sûres d'obtenir une correction de bogue immédiatement si des problèmes surviennent.
établir des politiques strictes de version et de version. Lorsque vous faites évoluer un composant réutilisable, ne le publiez pas "à tout le monde" tous les jours (du moins, pas si cela impliquerait d'exécuter un test de régression complet de 200 000 $ sur le système). Au lieu de cela, laissez les nouvelles versions être publiées de temps en temps et fournissez des mécanismes pour permettre à l'utilisateur de ce composant de reporter la modification à la nouvelle version.
plus un composant est souvent réutilisé, plus il est important qu'il fournisse une interface stable et un comportement compatible vers le bas.
les composants réutilisables nécessitent des suites de tests très complètes pour les tester isolément.
Beaucoup de ces choses signifieront que le coût de construction du composant lui-même augmentera, mais cela diminuera également les coûts des changements causés par les régressions échouées.
la source
Bien qu'il puisse y avoir une augmentation "observable" des coûts en raison de la nécessité de plus de tests, ce type de refactorisation rend généralement le code plus maintenable à l'avenir, car vous réduisez la dette technique du système.
Nous espérons que cela réduira les bogues futurs et facilitera la mise en œuvre de nouvelles fonctionnalités ou modifications des fonctionnalités existantes.
Par plus simple, je veux dire qu'ils devraient prendre moins de temps et donc coûter moins cher.
Réduire, plus facile et moins sont tous des termes plutôt nébuleux ici et toute économie future (ou plutôt espérée) est impossible à calculer car elle ne s'est pas encore produite.
Une base de code plus simple devrait permettre aux nouveaux employés ou aux employés existants qui entrent dans le projet de se mettre à niveau plus rapidement, en particulier pour les grands systèmes.
Cela peut également réduire le roulement du personnel dans la mesure où le moral des membres du projet pourrait être amélioré.
Bien sûr, il n'est pas garanti que vous obtiendrez ces avantages, mais ce sont des choses qui devraient être prises en compte parallèlement aux coûts (comme l'augmentation des tests) qui peuvent être mesurés.
En fait, un meilleur code devrait éventuellement réduire les coûts de test au fil du temps, même s'il y a une augmentation initiale due à ce que vous décrivez.
la source