Affichage des articles dont le libellé est TDD. Afficher tous les articles
Affichage des articles dont le libellé est TDD. Afficher tous les articles

mercredi 2 novembre 2022

3P pour sortir du Legacy

Protéger, Préparer, Produire - 3P. Une machine pour sortir du legacy.

Photo by Ugne Vasyliute on Unsplash
Photo by Ugne Vasyliute on Unsplash

Peut-être que avez-vous déjà vécu des expériences du style

  • Un projet de refactoring sur plusieurs mois a été annulé
  • Des tests qui n'aident pas vraiment le dev, voire le ralentit
  • Des refactorings qui finalement se montrent pas terribles 
  • Le code qui se dégrade continuellement, malgré des stories dédiées au refactoring et aux tests que vous faites régulièrement.

Si c'est bien le cas vous seriez probablement intéressés par savoir pourquoi ces efforts n'apportent pas le bénéfice escompté et pourquoi les 3P vous aiderait.

Considérons d'abord les approches classiques de faire du refactoring ou tests dans des stories dédiés, ou le simple fait de faire la majorité du refactoring et les tests en fin de story. Certes ces approches semblent attrayantes à première vue,  mais elles ont un gros problème de ROI. En effet, elles rallongent le temps entre investissement (le refactoring) et retour sur investissement (une nouvelle fonctionnalité, facilité par ledit refactoring). 

Justement, quand on fait du refactoring dans un projet ou story à part, ou même en fin de story : qui récolte la valeur, et ce sera quand

C'est la prochaine personne qui touche le code, d'ici qq temps, avec un peu de chance. Et ce à condition que le refactoring facilitera bien le futur travail qu'on ne connaît pas... En gros le ROI sera pour quelqu'un d'autre, peut-être. Et ce dans un futur potentiellement lointain. Pas idéal, mais on peut remarquer que le ROI est plus proche si on le fait en fin de story que si on le fait dans un projet à part.

Même question pour les tests. Qui récolte la valeur des tests écrits après coup? Et ce sera quand?

La réponse est essentiellement la même. C'est la prochaine personne qui touche le code, d'ici qq temps, avec un peu de chance. A condition que les tests seront encore pertinents face à la nouvelle demande, qu'on ne connaissait pas lors de l'écriture des tests.

Bref on voit bien qu'il y un temps qui peut être plus ou moins long entre l'investissement et la récolte du bénéfice. Plus ce temps est court plus on va y trouver un intérêt. Mais ce n'est pas tout. Dans mon expérience, on ne fait pas toujours le refactoring idéal et pas toujours les tests idéaux. Entre autres parce qu'on connaît pas bien le futur.

On aurait donc intérêt à trouver une façon de récolter le plus rapidement le feedback sur la qualité de nos tests et notre refactoring, ainsi que de minimiser l'incertitude par rapport au futur. Si jamais on le faisait, on aurait alors des actions de refactoring et de tests qui apporteraient nettement plus pour un même temps investi. Dans ces conditions on aura tendance à en faire plus, voire beaucoup plus.

3P

C'est là que se trouve l'intérêt des les 3P, où nous rapprochons non seulement l'investissement du bénéfice, mais en plus c'est nous même qui sommes les premiers bénéficiaires des tests que nous venons d'écrire et du refactoring que nous venons d'opérer!  

L'idée est simple, pour chaque story décomposer le travail en 

  1. Protéger
  2. Préparer
  3. Produire

Protéger

Mise en place des tests manquants

D'abord il faut protéger les modifications avec des tests. Pour cela il faut identifier le code qu'on doit toucher pour compléter avec des tests manquants. Attention il s'agit uniquement des tests pour le code qui sera touché, tester plus serait une distraction

Le code qui sera touché doit être parfaitement couvert avec des tests bétons. Sans quoi on n'osera pas faire de refactoring digne de ce nom.

On fait plutôt des tests haut niveau dans cette phase afin qu'elles ne cassent pas lors du refactoring. Pour gagner beaucoup de temps, on ignore complètement l'aspect maintenabilité dans cette phase (voir la suite)

Préparer

Refactoring en profondeur pour rendre plus facile la nouvelle fonctionnalité

On fait en sorte que la nouvelle fonctionnalité puisse s'insérer de façon élégante dans le code. 

On rend également le code facilement testable. Peut-être qu'on a écrit des tests end-to-end dans la phase protéger. C'est le moment de refactorer pour rendre possible de déplacer ces tests à un niveau où ils seront plus rapides et où il sera plus facile de maintenir les tests.

Produire

Coder la nouvelle fonctionnalité en TDD

Puisque le code est propre et testable, cette phase peut se faire en TDD, quel que soit le code au départ.

Conclusion

Avec les 3P nous écrivons les tests, pour faire nous même le refactoring derrière. Nous pouvons travailler en TDD pour bénéficier nous même des nouveaux tests. Nous minimisons le temps entre refactoring et introduction de la nouvelle fonctionnalité. Nous connaissons la fonctionnalité avant de commencer. Comment le ROI pourrait-il être plus idéal?

Et toi lecteur, tu fais comment?

Notes de fin

Je ne dis pas qu'il faut éviter le refactoring en fin de story, simplement c'est pas la part principale.  

Je ne donne pas beaucoup de détails sur comment s'articule les 3P concrètement. Je vais tâcher à rendre ça plus claire dans un autre post.



samedi 28 mai 2011

Software Craftsmanship 2011 - décoiffant!


Je dois dire qu'une conférence où l'on a l'occasion de parler directement avec Gojko Adzic, Steeve Freeman, Michael Feathers, Jason Gorman, etc est forcément passionnante! C'est sans mentionner des sessions d'un très bon niveau où l'on a l'occasion de pair-programmer avec d'autres passionnés! Puis toutes les conversations entre participants.
Voici un petit résumé des sessions auxquelles j'ai assisté.
How object oriented are you feeling today?
Il fallait résoudre un petit problème tout en respectant 9 principes qui mènent infailliblement à un code orienté objet.

Ce que j'aime bien avec les exercices bornés par des règles fortes est que ça permet de sortir de ses habitudes et avoir un inspecteur de code derrière le dos pour nous aider à nous mettre en cause. Aussi lorsqu'une alerte est levée par la violation d'une des règles alors c'est souvent pas important quelle règle a été violée mais signe d'un problème plus profond. Par exemple pendant cette session nous nous sommes trouvés à vouloir avoir 3 collaborateurs (le max étant 2) dans un objet Account: Client, Bank et Money. La banque était nécessaire pour autoriser ou pas un transfert (autorisés uniquement au sein de la même banque). Le problème n'était pas d'avoir un troisième collaborateur, mais que le compte allait gérer trop de choses – le transfer ET la demande de l'autorisation. Une meilleure solution est que la banque autorise le transfert puis délégue le transfert au compte (Single Responsability Principle). Les règles nous ont permis de le voir plus tôt.

Les règles que je compte appliquer strictement au jour le jour
  • first class collections (wrapper chaque collection une classe métier)
  • one level of indentation
Celles que je vais essayer d'appliquer un peu plus
  • no else statements (même pas dans les factories).
  • Wrap all primitives and string in their own class
Détail intéressant, tous les développeurs java à qui j'ai parlé ont adoré, mais j'ai parlé avec deux développeurs Ruby qui trouvaient que ça rendait leur code dégueulasse!


Functional programming with Michael Feathers
Session pas très bien préparée et pas très avancée. Plutôt dirigée sur la question quels éléments de la programmation fonctionnelle devons nous utiliser dans les langages objet. Il a essentiellement montré les expressions lambda (opérations sans état sur collections), avec la conclusion que parfois ça facilite mais parfois elles manquent un peu d'expressivité (même avec un bon nommage).

Bon point : tant que l'interface d'une fonction est pure (pas d'effet de bord, toujours le même résultat pour les mêmes entrées) peu importe si tu utilises la mutabilité à l'intérieure.

J'ai posé la question à Michael Feathers et à Steeve Freeman qui était là aussi « Why should we still develop with object oriented languages today ». C'est une question que je me pose depuis environ un an. Et toutes les réponses que j'ai trouvé sont à mon avis insatisfaisantes (performance, habitude des développeurs, moins de pouvoir = moins de risque) c'est certainement pas parce que l'objet est plus facile à maitriser! J'avais trop hâte de connaître le point de vu de ces cadors. Seulement aucun des deux avaient une réponse à part « I haven't yet seen a project of size written in a functional language ». On manquerait seulement de recul?

Lean code challenge
C'était absolument fabuleux! Chris Parsons a traduit 4 des principes de Lean, (waste, deliver fast, build quality in, customer value) dans un défi ludique de développement.
A travers 6 itérations de 10 minutes nous avons construit un calculateur de prix de panier de fruits avec des stratégies de prix évolutives et franchement changeantes(!). Je ne peux m'empêcher de dire que les stratégies, quoique réalistes, n'étaient absolument pas lean, où il vaut mieux éliminer la complexité que l'automatiser...

Nous avons terminé toutes les exercices et avec un code plus qu'acceptable. Si on n'avait pas fait du TDD j'imagine pas comment on aurait pu y arriver. Bel exemple du ROI sur le TDD en seulement 60 minutes! Gojko Adzic a dit qu'il n'avait commencé le TDD qu'au bout de la deuxième ou troisième itération – avant il ne trouvait pas que c'était utile, intéressant.


L'année prochaine j'y retourne!