mais on utilise un process waterfall datant de la fin des années 60 en utilisant un modèle de management qui n’est pas adapté. Le métier effectue beaucoup de demandes souvent mal priorisées, avec parfois un besoin mal défini. Il met alors de la pression pour voir le livrable ASAP ; or, la gestion actuelle des projets fait que les livrables n’arrivent qu’à la toute fin voire après la deadline. Les tests, vus comme optionnels car n’apportant pas de plus-value au métier, sont décalés à la fin voire jamais faits du tout. 4
durant le process découvrent l’appli une fois “finie”. Ils font souvent des retours violents, comme telle ou telle fonctionnalité importante qui manque ou qui ne marche pas du tout comme elle devrait. • Du coup le dev se met à corriger en urgence et introduit des régressions et des bugs récurrents. L’absence de tests commence à se faire sentir. • L’architecture devient de plus en plus alambiquée et difficile à comprendre, ce qui favorise les nouvelles régressions. • Il est alors de plus en plus difficile de toucher au code sans casser quoi que ce soit à côté mais un refactoring est hors de question puisqu’il faudrait demander aux utilisateurs et BA de retester toute l’appli depuis le début pour vérifier les TNR blocage au niveau du budget qui crève le plafond. • En plus, la doc et les specs écrites au début (“quand on avait le temps”) ne correspondent plus à l’état du code. Le code est monolithique, l’application bancale, les coûts sont monstrueux, tout le monde est mécontent. 5
servent à rien, au pire ils vont induire en erreur. Les rares commentaires utiles décrivent des comportements métier très pointus et difficiles à comprendre pour un non-initié (ex : grosse formule de maths). Mais le risque lié à l’obsolescence subsiste. 6
unitaires. Pas de code avant, le test doit planter. “Red, Green, Refactor” : • Red : Le test plante. • Green : On écrit juste le code nécessaire au passage du test, ce qui évite d’introduire du code inutile et un design potentiellement lourd. • Refactor : On met le code au propre (si nécessaire). Une fois la feature finie, on commite. On peut même commiter une fois que le test passe. Et on recommence. 8
métier en code ; on s’assure donc dès le départ de bien comprendre les specs. On a des tests qui valident un fonctionnement on peut donc refactorer le code testé quand on veut sans craindre les régressions à gogo. Le design de l’application se fait petit à petit, on part d’une base simple pour évoluer ensuite. On pourra en effet refactorer facilement, donc l’archi peut évoluer sans crainte. C’est un point majeur, car on évite de stagner dans une archi inadéquate, souvent source de bien des maux (contournements, régressions, etc…). Lorsqu’on a un bug, soit un ou des tests plantent et on peut cibler facilement ce qui ne va pas, soit on n’a qu’à ajouter le cas de test ensuite pour prévenir le bug de resurgir ensuite. On peut livrer au métier quand on veut puisque les tests passent. Cela ne signifie pas que l’appli est finie mais qu’une partie est livrable et testable en l’état. On peut donc mettre le métier dans la boucle plus vite et avoir des feedbacks plus rapprochés. L’itération et l’incrémentation sont au coeur du process : on est “Agile”. 9
faire attention à rester très précis et bien cibler ce que l’on teste. Un test d’intégration n’a pas lieu d’être à ce stade, car il couvre trop de périmètre et ne permet pas l’approche itérative citée précédemment, sans parler du temps et des ressources nécessaires au lancement de ce type de test. Le test unitaire a un but technique, il ne servira que peu aux BA ou utilisateurs. Contrairement au test d’intégration ou au test end-to-end qui valideront eux un véritable comportement métier. 10
donc impératif 1) de savoir communiquer et 2) que le métier soit OK avec ça ! Si le métier ne veut pas fonctionner dans ce mode, soit il faut avoir de bons BA, soit le projet est compromis. Pour des tests unitaires, on veut une granularité très fine. Il est donc indispensable de découper chaque demande métier en plusieurs tâches, elles-mêmes divisées en plusieurs parties. Chaque partie fera l’objet de plusieurs tests visant à vérifier le comportement pour plusieurs données en entrée. Afin de bien développer l’application et de la rendre testable, on a besoin de s’appuyer sur les principes SOLID, notamment S et D. Voir http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29 Evidemment, créer une batterie de tests unitaires n’est utile que si ces tests sont rejoués régulièrement… d’où le besoin d’un environnement d’intégration continue avec usine de build et lancement automatique des tests. 12
Un bon test unitaire : • Ne teste qu’une seule chose à la fois : une seule classe, une seule méthode • Isole le code de l’environnement et du contexte, quitte à fournir des implémentations tronquées ou bidon des dépendances (“mocking”). Sinon on tombe dans le test d’intégration et on est hors scope. • S’exécute rapidement car il est lancé souvent. • Teste aussi les cas à la marge pour éviter de ne tester que le “happy path” qui est le cas idéal où tout se déroule parfaitement. Si une méthode prend une chaîne en paramètre, il faut aussi penser à tester le cas où la chaîne est null ou vide. 13
va appeler du code qui n’existe pas encore. Ce n’est pas naturel… et c’est normal ! Mais l’habitude vient vite, il suffit de pratiquer. Du coup, quand on code, on a souvent envie d’aller plus loin que de répondre simplement au test. Oui mais cela signifie qu’on implémente un besoin pas demandé par le métier ou qu’on est en train de complexifier l’architecture pour rien… Il faut savoir résister à cette envie et faire simplement ce qui a été demandé. KISS : Keep It Simple, Stupid (Fais Simple, Gros Malin :p) Il faut le support de tout le monde. Sans l’aval du manager, les outils ne seront peut- être pas là et tout le monde ne fonctionnera pas sur le même mode. Donc impossible de livrer de façon incrémentale au métier. Si le métier ne suit pas, la communication sera difficile et les specs pas ou mal respectées. A noter quand même qu’on n’a pas forcément besoin de specs détaillées ou d’outils perfectionnés pour commencer à faire les tests simples… 14
passage obligé. Ils diffèrent selon les langages et les équipes de dev mais en maîtriser un ou deux est fortement recommandé. Idem pour le mocking et tout ce qui est injection de dépendances (http://en.wikipedia.org/wiki/Dependency_inversion_principle). En termes d’outils, il existe beaucoup de plug-ins aux divers environnements de dev qui facilitent la création et le suivi de tests. Certains sont même fournis avec le framework de test (ex : nUnit) ou carrément avec l’IDE. Les katas, comme dans les arts martiaux, représentent des exercices simples dont le but est d’assimiler une ou plusieurs techniques. C’est pareil en dev : en réalisant un exercice régulièrement en se tenant au TDD, on va finir par bien comprendre les concepts derrière. 16
“tu vas voir, en finance ils ont environ 10 ans de retard sur la gestion des projets informatiques”. Ca se vérifie aujourd’hui. Le problème c’est qu’en tant que consultant, il faut savoir se tenir à la page. TDD est un process important, ce n’est pas un effet de mode, il est là pour rester. Il est donc crucial de le maîtriser sous peine de devenir un dino à moyen terme. L’avantage c’est que ce n’est pas si dur ; en 2 semaines à pratiquer pendant 30 minutes par jour sur des exercices simples, on connaît bien les rouages. 17