De nos jours, l’apprentissage de tout programmeur passe par un certain nombre d’étapes. Une de celles-ci est la découverte des tests. Cette découverte se fait généralement progressivement et pour plusieurs d’entre nous, un peu à l’envers. Voici le récit de mon expérience personnelle, mais je me doute que certains d’entre vous s’y reconnaîtront.

Une perte de temps

Tout commence à l’université: on apprend à coder, tout va bien. On ne sait pas ce que sont des tests au-delà des tests manuels. On n’a aucune idée des différents types de tests. Jusqu’au jour où, dans un cours de génie logiciel, on se fait dire que ça existe, et que c’est une pratique répandue.

La première pensée qui nous vient en tête: « Mais c’est une perte de temps, je sais que mon application va fonctionner, je l’ai codée moi-même! » On lance l’application, on fait un test manuel rapide et ça fonctionne, alors pourquoi ajouter des tests supplémentaires? De plus, notre devoir est dû pour le lendemain matin et on est encore loin de l’avoir terminé, donc ce n’est vraiment pas le moment de se rajouter du travail en écrivant des tests…

Et cette mentalité continue. On prend des petits contrats, et puisqu’on est seul à travailler sur le code et que les projets sont généralement assez petits, on se dit que tester est une perte de temps. On termine notre baccalauréat et on commence la maîtrise. On travaille avec un projet ouvert beaucoup plus gros que tout ce sur quoi on a travaillé jusqu’à présent, mais il n’y a toujours pas de tests. L’idée de tests inutiles reste toujours très présente dans notre esprit.

La maîtrise se termine et on entre sur le marché du travail. On est recruté par une grosse compagnie qui fait des logiciels depuis maintenant plus de 35 ans. On se dit que ça doit être parce qu’ils savent ce qu’ils font. Encore là, les tests sont absents, renforçant encore plus notre impression qu’ils sont inutiles. On livre rapidement et notre patron est content.

Ça se complique…

Évidemment, cela mène à du code non testable et très couplé, mais nous ne le savons pas encore. Plus le temps avance, plus ça devient compliqué d’ajouter de nouvelles fonctionnalités dans l’application. On ne comprend pas trop pourquoi : avant c’était assez facile. À ce moment, il y a généralement deux explications:

  • Auparavant, notre chargé de projet nous donnait seulement des tâches faciles pour ne pas nous décourager, le temps qu’on apprenne;
  • Le projet est devenu un ramassis de code « spaghetti » qui ne peut plus être maintenu.

On se retrouve aussi à passer de plus en plus de temps à corriger des bogues au lieu d’ajouter des fonctionnalités. Et la plupart des bogues que nous corrigeons sont en fait causés par nous. C’est à ce moment qu’on se rappelle que les tests existent… On a besoin de corriger les bogues qu’on a introduits en cours d’année et on se demande ce qui nous est passé par la tête pour qu’on écrive quelque chose d’aussi mauvais.

Les conséquences

Le lendemain d’un gros Commit, on revient au bureau pour se rendre compte qu’il y a plusieurs courriels qui nous attendent pour nous dire que nous avons brisé la compilation de la nuit dernière avec notre Commit. On commence tout de suite à paniquer. Heureusement, la correction n’est pas trop compliquée, mais on se fait convoquer au bureau du patron parce qu’on a ralenti tout le monde en retardant la compilation.

Par la suite, chaque fois que nous avons un gros Commit à passer, on stresse de plus en plus parce qu’on ne veut pas avoir à retourner dans le bureau du patron. Les outils de compilation maison n’arrivent pas à détecter toutes les dépendances dans le code et on se rend compte qu’on ne peut pas s’y fier, augmentant davantage notre crainte.

À ce moment, la compagnie a plus de 350 employés dont la moitié sont des développeurs. Comment faire passer le message qu’il faudrait ajouter des tests dans l’application alors que les grands patrons au-dessus de nous sont en train d’engager plus de personnel pour faire de l’assurance-qualité? Quel patron ayant 30 ans d’expérience voudra écouter le petit nouveau et ajouter des tests à l’application? Surtout que cette application compte près d’un million de lignes de code. Il n’y a rien à faire et on commence à déprimer. Notre productivité diminue parce qu’il y a maintenant une liste de douze étapes de compilation à effectuer avant de pouvoir passer un Commit.

Le renouveau

Vient un jour où on n’est plus capable de suivre cette routine et on se trouve un nouvel emploi. C’est à ce moment que j’ai rejoint studio. Une petite compagnie avec une quinzaine d’employés qui fait des contrats pour diverses entreprises. Le renouveau est magique!  On apprend plein de nouvelles technologies et de façons innovantes de travailler. Et ce qu’il y a de mieux: les tests sont omniprésents dans les projets. On comprend enfin leur utilité et on veut en écrire des tonnes.

On écrit du code, on le teste manuellement et on écrit un test pour s’assurer que personne d’autre ne le brisera. De ce fait, notre code est beaucoup moins couplé et plus facilement réutilisable. Notre couverture de code est quasi universelle. Tout va bien!

Un nouvel obstacle

Un peu plus tard, on doit modifier une petite partie de notre code pour ajouter une nouvelle fonctionnalité. Le code est simple, découplé, donc le changement est facile. On fait la modification, on teste manuellement pour être sûr que ça fonctionne et on écrit  de nouveaux tests pour la modification. On relance tous les tests de la solution et… ça ne passe pas. On regarde les tests qui sont brisés: ce sont ceux que nous avons écrits en même temps que le code.

Pourquoi est-ce que ces tests sont maintenant brisés? La raison est simple: les tests sont directement liés au code. Ils testent chaque classe, fonction, boucle, condition, individuellement. Donc, si on change le code, sans pour autant changer la logique, les tests se brisent. On modifie donc les tests pour qu’ils passent, on enlève ceux qui ne sont plus nécessaires, on en ajoute de nouveaux et on Commit le tout.

Mais on se rend compte très vite que ça nous prend de plus en plus de temps pour ajouter des fonctionnalités. Pourtant, on fait des tests et on s’assure que le code est le plus propre possible. Ça ne devrait donc pas prendre de plus en plus de temps. Notre code est peut-être très propre, mais on comprend rapidement que le code des tests unitaires n’est vraiment pas propre et que ça nous ralentit beaucoup, surtout lorsqu’on doit modifier les tests chaque fois qu’on ajoute une fonctionnalité.

De plus, faire n’importe quel refactoring brise les tests, alors que la logique ne devrait pas avoir changé. On ne veut donc pas faire de refactoring parce que ça brise les tests et que c’est long de les corriger. À la longue, on se retrouve avec du code de moins en moins propre, tout comme on avait avant d’ajouter des tests.

Test-Driven Development

Vient un jour où on apprend l’existence du Développement piloté par les tests (TDD). Cette pratique nous semble étrange et sortie d’un esprit fou qui n’en pouvait plus des tests. Cependant, on ne fait qu’en entendre du bien et on se met donc à l’étudier.

Écrire un test avant même que le code ne soit lui-même écrit! Selon nous, ça ne semble pas fonctionner mais, après quelques vidéos, livres et essais personnels, on commence à en voir l’utilité. Tout à coup, nos tests ne sont plus reliés à l’implémentation. Faire un refactoring ne brise plus les tests, à moins qu’on ait fait une erreur en le faisant. Ça semble être un cadeau du ciel!

De ce fait, notre mentalité change aussi. On veut maintenant tester la logique d’affaires au lieu de la logique du code. Ça se reflète aussi lorsqu’on écrit les tests après avoir écrit le code: nos tests supplémentaires vont chercher d’autres cas possibles, ou des cas limites, qui sont peut-être déjà résolus par notre code, mais sans pour autant refléter l’implémentation du code. Ils servent à fortifier davantage la logique d’affaires dans le code et s’assurer qu’elle ne sera pas brisée.

Le besoin d’affaires

On arrive aussi à écrire des tests qui couvrent de plus en plus large, sans que ce soit compliqué. Ça nous permet donc de faire de moins en moins de tests manuels. La couverture que nous avons n’est peut-être pas infaillible à 100%, mais elle est beaucoup plus utile lorsque nous avons à faire des modifications dans le code.

Il devient aussi plus facile d’écrire des tests qui parcourent plusieurs couches de l’application ou qui sont capables de passer à travers des cas de tests beaucoup plus complexes. On peut donc très simplement écrire des tests d’intégration sans changer notre façon de penser, ce qui nous semblait être une tâche monumentale auparavant.

On essaie d’ajouter des tests partout dans l’application, incluant dans les sections qu’on jugeait non testables comme l’interface utilisateur, et on se rend compte que c’est plus facile qu’on le croyait initialement. L’implémentation devient de plus en plus délaissée au profit du besoin d’affaires, au point où on voit apparaître les cas de tests directement dans les récits avant même d’avoir pensé au travail qu’il y aura à faire pour ajouter la fonctionnalité.

Notre apprentissage continue. On va suivre une formation et on voit le formateur utiliser ce principe pour corriger une application. Ça semble si simple lorsqu’il prend le clavier et que tout le code se place comme par magie au bon endroit.

Derrière toute cette histoire se cache une leçon essentielle selon moi: il ne faut pas mettre de côté des pratiques qui vous semblent inutiles lorsque vous êtes encore jeunes dans le domaine. Certaines des pratiques que nous utilisons en développement logiciel sont complexes et peuvent demander des années avant d’être bien maîtrisées, mais ce sont souvent ces dernières qui sont les plus utiles et qui nous enrichissent le plus.

À propos de Studio Pyxis

Studio Pyxis est avant tout un lieu de création destiné au développement de logiciels. Nous nous spécialisons en développement sur mesure pour des clients qui cherchent des solutions uniques et qui veulent maximiser la valeur de leur investissement. Depuis plus de 15 ans, notre équipe de développement a fait la preuve de son Agilité, de sa créativité, de son esprit collaboratif et de son engagement indéfectible au succès de nos clients et partenaires.

Billet précédent

Agile Coach Camp 2017

Billet suivant

Pourquoi les leaders ont besoin d’espaces sécuritaires pour apprendre et grandir

Sébastien Lavoie-Courchesne

Sébastien est un passionné d'informatique, autant du point de vue programmation que recherche. Après un baccalauréat et une maîtrise en informatique à l'Université de Montréal, il a acquis de l'expérience avant d'atterrir chez Pyxis comme développeur. L'efficacité et la performance sont pour lui les points les plus importants de l'informatique.

Pas de commentaire

Laissez un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *