TDD et Clean Architecture, partie 1
Par Guillaume le dimanche 18 mars 2012, 17h36 - Développement - Lien permanent
Après le kata, 2è vidéo sur TDD avec une petite appli d'exemple et un focus sur un type d'architecture particulier :
- Vous pouvez retrouver la présentation d'Uncle Bob ici
- La page du projet NCrunch
- Le code de la solution sur mon Github
Commentaires
Salut et merci pour cette vidéo.
Quelques petites questions…
Je ne suis pas certain d'avoir compris le changement de design de la liste vers un dictionnaire. Ton problème de départ semblait être la comparaison de Figurine. Puisque tu ajoutais n fois n Figurines avec le même nom, tu aurais voulu savoir si c'était la même figurine ou non. Après ton changement de design, il me semble que tu as eu le même problème et que du coup, tu as choisi d'ajouter n fois la même figurine. Si tu avais fait ce choix au moment où tu as rencontré ton problème, je pense que l'introduction du dictionnaire ne devenait pas nécessaire ?
Tu connais le "primitive obsession". Et bien je pense que tu l'as illustré parfaitement ;-)
En effet, si dès ton 1er kata, tu avais décidé d'introduire le concept de Figurine, simplement parce que tu manipulais le concept métier de Figurine, tu aurais gagné un peu de temps. Code expressif…
Dernière petite question. Il me semble que ton test de panier n'est pas unitaire puisqu'il dépend de Figurine, non ?
Bon courage pour la suite que j'attends avec impatience.
Salut Sylvain,
Je vais essayer de répondre dans l'ordre
1/ Tu as raison, dans le feu de l'action mon diagnostic du problème de figurine était mauvais ou du moins incomplet : j'aurais pu introduire n fois la même instance de Figurine dans la liste sans recourir à un dictionnaire. Mais la solution d'associer un produit à une quantité m'a paru plus élégante et plus raccord avec le domaine sur le moment, donc j'ai pris ce raccourci. Sans que mon cerveau percute tout de suite qu'il fallait du coup ajouter n fois la même instance et pas créer n instances ;)
2/ D'accord avec toi sur la primitive obsession, moins d'accord sur le code non expressif. Pour moi le code du kata était suffisamment clair comme ça, avec des méthodes comme AjouterFigurine("Tintin") on est loin d'un entier cryptique ou d'un code ésotérique sur 4 caractères. J'aurais certes pu refactorer dans ce sens mais j'ai dû faire des choix et m'arrêter de refactorer à un moment ;) J'ai d'ailleurs vu des implémentations du kata Harry Potter (celui d'origine) se baser sur des chaînes.
3/ Lequel ?
Merci pour ton retour en tout cas :)
Hello,
2/ je suis d'accord et un peu extrémiste ;-) Je pense juste que l'on a tendance à dire tout le temps "c'est assez lisible" mais qu'avec des classes avec plus de sémantiques, c'est pas mal non plus : lisible ET évolutif.
Et note que, finalement, tu as dû l'introduire cette classe Figurine ;P
3/ Ben, il me semble que la plupart de tes tests du Panier utilise des instances de Figurine non ? Ce n'est donc pas "réellement" unitaire…
@+
Aie aie aie... je sens d'ici un débat trollesque sur ce qui est unitaire ou pas ;)
Plus sérieusement, si tu fais allusion à mettre une interface au-dessus de Figurine et mocker à chaque fois, non je ne le fais pas systématiquement et je considère quand même les tests du panier comme unitaires dans ce cas précis.
Pourquoi ? Tout simplement parce que les tests du panier n'utilisent jamais de méthode de Figurine, tout au plus le constructeur et pour 2 tests une comparaison d'instance. Ca me parait suffisamment basique pour être considéré comme fiable ("don't test the platform"). D'ailleurs on peut mettre à peu près n'importe quoi dans le constructeur et les tests passent quand même (je viens de vérifier) donc ça montre bien que le constructeur est juste un prétexte à créer une instance de Figurine dont on se fiche du contenu. Dans la mesure où il fait le même travail qu'une doublure et où la construction d'une figurine est ultra-simple, je ne vois pas l'intérêt d'une doublure ici.
En revanche, dès que notre méthode A suppose la validité d'une méthode B d'une autre classe, j'estime qu'il faut isoler le test de la validité de A de la question de la validité de B, donc recours à une doublure. C'est justement ce que j'ai prévu de montrer dans la deuxième partie car les interacteurs, comme leur nom l'indique, communiquent avec beaucoup d'objets et ont pas mal de dépendances.
Loin de moi l'idée de vouloir troller…
Je comprends tes arguments et c'est plutôt d'ailleurs comme ça que j'ai l'habitude de faire.
Ceci dit, dans mes réflexions d'amélioration, je commence à penser que certains changements sont intéressants très tôt.
1. parce qu'ils apportent de la lisiblité ;
2. parce qu'ils facilitent l'évolution du code.
J'en ai parlé pour l'introduction de Figurine qui aurait pu être fait tout de suite. Son introduction plus tard a pris plus de temps.
Et bien, je me demande si l'introduction de l'abstraction, comme tu l'as dit, ne serait pas intéressante maintenant. Par exemple, si ton implémentation du panier dépend de la capacité de 2 figurines à pouvoir se comparer, alors il me semble important que cela apparaisse sur l'interface. D'où l'importance de cette interface. Et du coup, il faudra la doubler dans les tests…
C'était juste une réflexion et j'attends (toujours) la suite avec impatience.
Effectivement ta réflexion est intéressante, je n'avais pas vu les choses comme ça.
C'est toujours difficile de placer le curseur au bon endroit, trop KISS on risque en effet de se retrouver avec de gros chantiers à retardement, pas assez on risque de faire de la premature optimization ou du moins du premature design...
En ce qui concerne la comparaison d'instances de figurines, je ne pense pas avoir à en faire car même si ce n'est pas dit explicitement, je suis parti sur Figurine = référence catalogue/modèle de figurine dans une collection et pas Figurine = unité vendue au détail (SKU dans le jargon). On a donc une seule instance de Figurine associée à une quantité dans un panier, et pas X instances à comparer entre elles, ce qui nécessiterait effectivement du mocking quand on veut tester le panier en isolation.