Bonjour et bienvenue à l'Ancière Académie,
le podcast dédié à l'ingénierie logicielle et au software Craftsmanship.
Avant de commencer,
n'hésite pas à t'abonner et à me suivre sur LinkedIn pour recevoir régulièrement du contenu sur la programmation,
l'architecture logicielle,
les tests automatisés et bien plus encore.
Sur ce,
bonne émission !
Salut à toutes et à tous,
j'espère que vous allez bien,
et aujourd'hui un petit podcast en réaction et non pas en réponse,
en réaction au podcast de Mathieu Calahoui qui s'appelle Hands-On Podcast,
dans lequel il a invité plusieurs développeurs à discuter de sujets très intéressants,
notamment celui de la qualité logicielle.
Et pratiquement dès le début du podcast,
il pose une question extrêmement intéressante qui est...
Doit-on nécessairement avoir des tests et mettre en place une clean architecture et du clean code pour avoir un logiciel de bonne qualité ?
Et en une seule question,
pour moi,
il en a posé plusieurs.
Et je pense que déjà,
se mettre d'accord sur ce qu'est la qualité logicielle est extrêmement important.
Et ensuite,
faire le rapprochement entre les pratiques qu'il a énoncées et celles qui suivent,
d'une manière générale ce qu'on appelle les pratiques craft,
voir s'il y a un rapprochement à faire entre la qualité logicielle et ces pratiques-là.
Et la réponse n'est pas forcément évidente.
Et il y a pour moi une réponse extrêmement pertinente,
qui est la base de tout ce que je vais dire dans ce podcast-là,
je ne sais plus lequel des participants l'a donné,
mais il a dit...
Tu as un logiciel de bonne qualité si tu arrives tous les jours à déployer,
si tu arrives régulièrement à déployer.
Moi j'aime bien le principe de tous les jours,
pour moi on devrait être capable de déployer même plusieurs fois par jour.
Et ça pour moi c'est vraiment l'heuristique la plus importante.
C'est à dire que moi en tant que développeur qui se revendique comme étant hardcore agile,
Le plus important,
c'est de pouvoir avoir le feedback le plus rapide possible,
que ce soit avec mes clients ou que ce soit pour les clients de mes clients.
Le but,
c'est d'avoir un retour sur le logiciel que j'ai produit,
sur la valeur ajoutée de ce logiciel,
le plus rapidement possible.
Toutes les pratiques que j'applique derrière ont pour but de servir ce but-là.
Je n'appliquerai jamais une pratique qui irait à l'encontre de cet objectif.
Donc du coup,
pour moi,
c'est de maintenir cette vélocité.
et de maintenir ma capacité à rapidement rajouter de la valeur sur un logiciel existant dans le temps,
sans avoir le problème que l'on a aujourd'hui avec pratiquement tous les logiciels,
sans avoir ce problème de dette technique qui s'accumule avec le temps et qui fait que d'abord on arrive à déployer une fois par jour et puis une fois par semaine et puis une fois toutes les deux semaines,
puis une fois par mois et qu'après on doit faire des synchronisations entre les différentes équipes parce qu'on doit sortir la version de l'API en même temps que le front ou la version de l'application mobile en même temps que l'API.
Donc...
Tous ces effets-là sont des conséquences pour moi d'une application qui a été mal conçue et dont la qualité est mauvaise.
Donc ça rejoint exactement ma vision des choses.
On a un logiciel de bonne qualité si on arrive à produire de la valeur au quotidien.
Là-dessus,
on est parfaitement d'accord.
Et donc maintenant qu'on a une heuristique qui nous permet de savoir si oui ou non on a du code de bonne qualité,
il nous reste à savoir qu'est-ce que du code de bonne qualité et comment produire un code de bonne qualité.
Et c'est sur ces points-là que l'on va avoir énormément de désaccords.
Et la première chose qui va me choquer de la part de,
une fois de plus,
je ne sais plus lequel des intervenants,
de toute façon le but ce n'est pas de faire des attaques à nominés ou de nommer des responsables,
ce qui va beaucoup me gêner c'est cette réponse dans laquelle l'un des intervenants dit
que les tests ne sont pas nécessaires à une bonne qualité logicielle,
que la clean architecture n'est pas nécessaire à une bonne qualité logicielle.
Déjà,
pour la clean architecture,
je suis moyennement d'accord,
car une architecture qui est testable,
par définition,
suit les principes de la clean architecture.
En fait,
c'est un mot,
on en parlait aussi avec Michael Hazerath sur LinkedIn dernièrement en privé,
c'est que finalement,
dans son cœur,
la clean architecture,
c'est l'inversion de dépendance,
c'est l'architecture hexagonale,
c'est exactement ce même principe-là.
D'inverser les dépendances pour pouvoir remplacer ces dépendances,
que l'on soit dans un environnement de test,
un environnement de production,
ou tout simplement si on a envie de tester différents types de dépendances de production.
Donc déjà,
sans Clean Architecture,
en tout cas sans le principe fondateur de la Clean Architecture,
c'est-à-dire l'inversion de dépendance,
C'est compliqué de tester son code.
Il faut écrire des tests d'intégration à tout bout de champ.
Donc ça reste faisable.
Il me semble qu'il y a pas mal d'applications industrielles qui ont très peu de tests unitaires et beaucoup de tests d'intégration.
Ça permet de maintenir une bonne qualité.
Mais on se retrouve avec une qualité questionnable.
Pourquoi ?
Naturellement parce que ces tests d'intégration là sont beaucoup plus lents à tester,
donc ça devient beaucoup plus difficile de tester tous les cas possibles,
tous les différents chemins que peut emprunter le code.
Ces tests là nécessitent d'avoir en place une base de données ou un système de fichiers ou autre.
Donc du coup ça devient moins intéressant de les lancer vu qu'ils prennent beaucoup de temps à être lancés.
Donc du coup ils sont moins utilisés et donc du coup on a moins de possibilités,
c'est moins agréable de travailler sur la qualité du logiciel en lui-même.
Donc c'est ça.
C'est beaucoup plus pénible,
tandis que si on avait des tests véritablement unitaires,
par exemple j'ai cité dernièrement le cas de GCC qui a une batterie de 300 000 tests,
donc GCC c'est la suite de compilation de GNU Linux pour compiler du C.
Ils ont à peu près 300 000 tests,
je n'en doute pas qu'il y a une grande partie de ces tests,
voire la majeure partie de ces tests qui sont des tests unitaires,
ce qui fait que le développement est extrêmement simple.
Dès que je vais modifier un morceau de code quelque part,
je vais peut-être avoir une centaine,
plusieurs milliers de tests qui vont se lancer instantanément,
qui vont s'exécuter en une seule seconde,
et je vais avoir un retour immédiat.
Et ce retour immédiat-là va me permettre de travailler dans une boucle de feedback dans laquelle je vais pouvoir continuellement mettre à jour mon code.
le refactoriser et améliorer sa qualité.
Ce que l'on n'a pas avec des tests d'intégration,
parce que ces tests-là peuvent mettre
30 secondes,
1 minute,
5 minutes,
10 minutes à se lancer,
vous imaginez qu'on ne peut pas avoir des petites itérations,
de quelques modifications,
de quelques lignes,
parce qu'on a du véritable refactoring,
lorsqu'on a une boucle de feedback qui dépasse les 30 secondes,
la minute,
les 10 minutes,
etc.
Donc déjà,
sans clean architecture,
c'est difficile de maintenir une bonne qualité logicielle,
car cela implique que si l'on a des tests,
Ce sont nécessairement en grande partie des tests d'intégration.
Par contre à la question peut-on avoir une bonne qualité logicielle sans test tout court,
non.
Clairement pour moi la question ne se pose même pas,
c'est tout simplement impossible.
Les tests apportent une valeur tellement incroyable et tellement nécessaire à la maintenance d'une qualité logicielle.
que l'on ne peut pas avoir un logiciel de bonne qualité sans test.
D'autant plus que la plupart des logiciels que l'on développe,
ça va être des applications web,
des applications mobiles,
etc.,
sont des applications qui vont avoir une longue durée de vie.
On va les développer aujourd'hui,
il y a de grandes chances que dans 3 ans,
dans 5 ans,
dans 10 ans,
ces logiciels existent toujours et soient encore développés et maintenus,
soient encore actifs.
Et pour comprendre la nécessité des tests à une bonne qualité logicielle,
il faut comprendre déjà comment est-ce qu'on arrive à avoir un logiciel de mauvaise qualité.
D'abord,
qu'est-ce qu'un logiciel de bonne qualité ?
Donc déjà...
Il faut différencier le logiciel de bonne qualité et le code source de bonne qualité.
Je pense que c'est extrêmement important de différencier les deux.
Un logiciel de bonne qualité,
c'est un logiciel qui fonctionne d'un point de vue de l'utilisateur,
qui va utiliser l'application,
tandis qu'un code source de bonne qualité va concerner les développeurs qui travaillent régulièrement dessus et va concerner leur facilité et la flexibilité de ce code-là à être modifié pour s'adapter à de nouveaux besoins.
Pour moi,
c'est ça la qualité logicielle.
Ou plutôt la qualité du code source,
mais c'est ce que l'on va appeler qualité logicielle.
dans ce podcast-là.
C'est de ça dont on va parler.
La qualité de l'exécutable en lui-même,
c'est encore un autre sujet.
Il y a généralement une très bonne corrélation entre qualité du code source et qualité logicielle,
mais c'est pas ça dont on va parler.
Et donc,
comment est-ce qu'on en vient à avoir une dégradation de cette qualité logicielle ?
Eh bien,
tout simplement,
au fur et à mesure qu'on travaille sur ce logiciel,
on va avoir des retours et on va se rendre compte que ce que l'on pensait être la vérité,
ce que l'on pensait que le logiciel devait faire,
est différent de ce que le logiciel doit faire en réalité.
Premièrement,
soit parce qu'on n'a pas très bien compris ce qu'il fallait faire dans la définition de ce logiciel,
soit parce que tout simplement le logiciel a évolué,
on a de nouveaux besoins,
il faut adapter le code existant à ces nouveaux besoins-là,
et donc nécessairement il faut modifier le code qui est en place.
Et c'est à ce moment-là,
lorsque l'on va modifier le code existant,
que l'on va introduire de la complexité,
que l'on va rajouter de plus en plus de cas de spécification,
de plus en plus de cas à gérer.
et que l'on risque de complexifier le logiciel sans modifier son design,
sans adapter en fait le design de ce code-là aux nouveaux besoins.
Et c'est à ce moment-là que l'on arrive à avoir des classes qui font beaucoup trop de choses,
ou avoir des fonctions,
ou avoir des fichiers qui font beaucoup trop de choses,
parce qu'on a gardé l'ancien design et qu'on a ajouté de nouvelles fonctionnalités dessus,
sans l'adapter aux nouveaux besoins.
Et donc c'est là en général,
lorsque le nouveau besoin arrive et que l'on a besoin de modifier du code existant,
que l'on va se poser la question du refactoring.
Est-ce que le code qui existe actuellement est suffisant,
est adapté à ce nouveau besoin-là ?
Est-ce que je peux juste rajouter quelques lignes et ça fonctionnera très très bien ?
Ou est-ce qu'il y a besoin de redesigner ce morceau de code-là pour l'adapter à ce nouveau besoin et potentiellement aux besoins similaires qui pourraient arriver dans l'avenir ?
Parce que lorsque l'on parle de design et de refactoring,
nécessairement,
on anticipe un certain futur.
Mais pas trop loin,
parce que sinon on peut tomber dans ce qu'on appelle le Yagni,
le You're not gonna need it.
Donc c'est assez délicat de trouver le bon équilibre entre les deux.
Et lorsque l'on va avoir besoin de faire du refactoring,
on va avoir besoin d'une méthode,
d'une solution qui nous permet de nous assurer que pendant ce refactoring-là,
pendant que l'on modifie la structure,
le design de notre code sans modifier son comportement,
on a besoin d'une sécurité de s'assurer que notre code fonctionne toujours de la même façon.
Et c'est là que les tests unitaires vont intervenir et même les tests d'intégration dans une certaine mesure.
On aura une suite de tests qui va nous permettre de faire ce refactoring tout en gardant l'assurance que notre code fonctionne toujours.
Et c'est ce refactoring là qui va nous permettre de maintenir un code adapté à notre besoin et ce sont ces tests là qui vont nous permettre de faire ce refactoring en toute quiétude.
Donc le premier intérêt des tests est de nous faciliter cette phase de refactoring qui va nous permettre de continuellement améliorer la qualité logicielle.
Deuxièmement,
on peut parfois se rendre compte qu'une solution que l'on a développée à un problème n'est pas forcément très claire,
n'est pas forcément très optimale.
Et à ce moment là on va vouloir modifier ce code là,
une fois de plus ça va être du refactoring voire carrément du redesign,
et une fois de plus avoir ces tests là vont nous permettre de faire ces modifications tout en s'assurant que le code fonctionne toujours.
Donc ça c'est la deuxième raison pour laquelle les tests sont nécessaires à une bonne qualité logicielle.
Et enfin cette fois-ci on va parler de Test Driven Development,
donc de TDD,
qui est une pratique extrêmement intéressante cette fois-ci pour développer une feature,
pour développer une solution dont on a besoin.
Pourquoi est-ce que c'est intéressant ?
Car le TDD,
de par sa nature,
va nous pousser à créer un bon design et à penser à un design qui soit testable,
de base,
avant même que l'on commence à développer.
On va devoir penser à...
Donc nécessairement,
on va se poser la question de quels résultats est-ce que je vais obtenir,
quelles doivent être les conséquences des différents appels,
des différentes invocations que je vais faire.
Donc on va vraiment penser en termes de contrat et on va devoir créer du code qui soit testable parce que le TDD se fait en test unitaire.
Ce qui signifie que l'on va naturellement aboutir à une clean architecture.
Et donc que vient faire le TDD dans la qualité logicielle ?
Et bien tout simplement lorsque l'on a un problème complexe,
avec le TDD on va pouvoir commencer à travailler sur une solution petit bout par petit bout en commençant par des cas très très génériques et petit à petit en allant dans des cas de plus en plus spécifiques jusqu'à aboutir à une implémentation complète.
Et c'est ça l'avantage du TDD c'est que l'on peut attaquer le problème selon le dicton divide and conquer.
On commence par...
un petit problème et petit à petit un autre petit problème,
etc.
Et ensuite,
à la fin,
on a une solution qui est complète.
Et en travaillant sur des petits morceaux de problèmes,
on peut travailler sur des petits morceaux de code qui soient,
eux,
de très très bonne qualité.
On va pouvoir faire du découpage de fonctions,
appliquer des design patterns,
etc.
De telle sorte à avoir un programme de bonne qualité à la fin.
Et donc,
si vous appliquez rigoureusement le TDD,
c'est-à-dire que vous écrivez un test,
vous développez une solution,
vous refactorisez le test et la solution petit à petit à mesure que vous évoluez,
naturellement vous arrivez à un design de bonne qualité et à un code de bonne qualité.
Et quand bien même ce ne serait pas le cas,
parce que vous n'êtes peut-être pas forcément un développeur habitué au TDD,
ou vous n'êtes pas forcément habitué au refactoring,
ou la solution est complexe,
ou vous ne maîtrisez pas nécessairement les bons design patterns pour cette solution-là,
combien même vous avez une solution qui n'est pas forcément de très bonne qualité,
vous avez...
En conclusion,
en side effect de cette façon de développer qu'est le TDD,
des tests qui vont vous permettre de remodifier à nouveau ce code.
Donc si par exemple vous avez un éclair de génie dans la nuit ou quelques jours après,
ou si vous vous retrouvez avec un développeur qui a un meilleur niveau que vous,
vous pouvez reprendre là où vous êtes arrêté,
parce que vous avez en reliquat les tests que vous avez écrits,
modifier ce code source là pour l'adapter à votre nouvelle compréhension de ce problème là.
et graduellement améliorer la qualité logicielle en tout cas de cette partie là du code.
C'est pour ça que pour moi d'ailleurs le TDD se pratique sur l'ensemble de l'application et pas juste sur une petite partie.
On ne peut pas avoir un développeur qui bosse en TDD et d'autres développeurs qui ne bossent pas en TDD dessus.
Tout simplement parce que lorsque derrière on va avoir besoin de reprendre ce code là,
si on n'a pas les tests,
comment est-ce qu'on va s'assurer que les modifications que l'on va faire sur ce code là fonctionnent toujours ?
Eh bien soit on va devoir écrire des tests.
qui vont essayer de comprendre le code qui a été écrit,
de tester tous les cas possibles et imaginables,
donc ce n'est pas forcément simple à faire.
Soit on va devoir tester manuellement au fur et à mesure que l'on écrit notre code,
donc du coup rajouter beaucoup de temps dans notre cycle de développement,
et donc prendre moins de temps à améliorer la qualité du logiciel.
Donc là aussi,
une des raisons pour lesquelles les tests et le TDD,
appliqués à une équipe entière,
contribuent à la qualité du logiciel,
et je dirais même,
est nécessaire à une bonne qualité du logiciel.
Et maintenant la question à 100 000 euros.
Est-ce que toutes ces pratiques-là,
la clean architecture,
le TDD,
l'écriture de tests,
etc.
va nécessairement rallonger le temps de développement et donc du coup impacter notre capacité à délivrer de la valeur jour après jour.
Et c'est ça l'un des problèmes que j'ai eu avec une des réponses qui était donnée dans ce podcast.
Je ne sais plus lequel des participants une fois de plus.
Prends l'exemple d'un jeune développeur qui va coder une feature en une semaine sans appliquer de clean architecture ni quoi que ce soit,
et un autre développeur qui va appliquer toutes les bonnes pratiques et lui va passer six mois à le faire.
Donc c'est complètement irréaliste et je me prends moi-même comme exemple.
J'ai souvent bossé avec des clients qui m'ont dit mais lève le piège à nous,
comment fais-tu pour aller aussi vite ?
Comment fais-tu pour développer aussi vite ?
Les autres développeurs auraient mis trois mois de plus à développer ce que toi tu as fait.
Donc déjà mon expérience personnelle me sert moi-même de preuve.
Mais alors comment est-ce que je fais pour aller plus vite que d'autres développeurs qui eux n'appliquent pas toutes ces pratiques-là qui mettent pourtant factuellement plus de temps ?
Et bien tout simplement parce que le développement logiciel c'est pas juste pondre du code,
le livrer,
fin de l'histoire.
Le développement logiciel c'est pondre du code,
le livrer,
accueillir des feedbacks,
modifier le code,
relivrer,
etc.
Et là où moi j'aurais mis en place tout ce dont j'ai besoin pour faire mes modifications extrêmement rapidement et pour déployer dans le quart d'heure qui vient,
un autre développeur qui n'a pas mis ça en place va devoir reprendre son code,
le modifier,
retester manuellement et redéployer.
Imaginez ça sur 10,
15,
20,
30 retours.
Ça s'accumule très rapidement.
Donc le temps que je peux perdre au début,
entre guillemets perdre,
plutôt le temps que je vais investir au début à me mettre en place tout ce dont j'ai besoin pour aller vite par la suite,
je vais le rattraper largement après coup.
Dès les deux premières semaines.
Parce que moi,
quand je travaille en agile,
je déploie dès les deux premières semaines.
Ça va dépendre du projet,
ça peut être assez compliqué à estimer.
Mais d'une manière générale,
toujours le premier déploiement dans les deux premières semaines.
Idéalement,
même dans la première semaine.
Et pour ça,
ce qui est extrêmement important en tant que développeur,
c'est de prendre notre place à nous.
qui n'est pas seulement de créer,
de produire du code,
de programmer,
mais de développer une feature.
Vraiment,
c'est très différent programmer et développer une feature.
En tant que développeur d'une feature,
lorsque un client,
ou même si je fais partie d'une équipe et qu'il y a déjà un logiciel,
il y a déjà un product owner,
etc.,
qui a déjà défini le besoin,
peu importe qui va me demander de développer quelque chose,
je vais nécessairement challenger ce besoin.
Donc,
dès qu'on a besoin de mettre...
tout ça dès le début,
est-ce que ça c'est vraiment nécessaire ?
Est-ce que ce petit bout-là,
cette petite sécurité,
cette petite vérification,
ce petit bonus-là,
on a besoin de le sortir là directement en V1 ou est-ce que ça peut attendre un petit peu ?
Et là on arrive à la jonction entre le craftsmanship,
l'agilité et le lean.
Parce que ça c'est exactement le lean dont je suis en train de parler.
C'est le fait de vraiment chercher le minimum nécessaire pour recueillir le maximum de feedback le plus vite possible.
Ce sont trois choses pour moi qui sont absolument inséparables.
Peu importe le contexte dans lequel vous travaillez,
même si vous travaillez dans un contexte où la feature est posée,
c'est à carrière rien d'autre,
il est extrêmement important de travailler en tout petit incrément.
Car une fois de plus,
c'est de cette façon-là que l'on va pouvoir mettre quelque chose le plus rapidement entre les mains de l'utilisateur.
Et surtout,
travailler sur un petit morceau est beaucoup plus simple d'un point de vue de qualité logicielle.
Je peux développer ce petit morceau avec une très bonne qualité.
Et derrière,
si j'ai besoin de rajouter en proactif une amélioration à cette feature-là,
ce sera beaucoup plus simple pour moi de modifier ce code-là qui est déjà de bonne qualité parce qu'il ne sera pas trop gros,
ce sera un petit morceau de code.
Et donc si vous travaillez comme ça,
avec du TDD,
avec de la clean architecture,
que vous travaillez en agile avec de petits incréments de valeur,
dans lequel vous questionnez régulièrement le besoin qui vous est demandé par le PO ou le client ou autre,
vous irez nécessairement plus vite que n'importe quel autre développeur qui tape un rush de la feature avec le framework de son choix qui est extrêmement productif,
que ce soit Rails ou soit Symfony ou autre,
donc du coup qui ira très très vite dans le développement de la feature,
mais qui va ramer et qui va ramer de plus en plus à mesure qu'il va avoir ces feedbacks-là.
Et si vous travaillez avec un développeur qui fait de la clean architecture du TDD et qui ne sort rien au bout de
1 mois,
2 mois,
3 mois,
mais qui ne sort rien au bout de 2 semaines,
inquiétez-vous.
Pour moi,
il ne pratique pas proprement le craftsmanship et l'agilité.
Voilà,
donc pour répondre à la question,
qu'est-ce que la qualité logicielle et qu'est-ce qu'un logiciel de bonne qualité ?
La réponse a déjà été donnée dans le podcast,
pour moi elle est parfaite,
c'est un logiciel dans lequel on peut rajouter de la valeur et que l'on peut déployer régulièrement.
Et pour ça,
il n'y a pas de secret,
on a besoin d'avoir un environnement qui nous permette d'avoir l'assurance de pouvoir faire ce déploiement sans avoir à passer des heures sur les tests.
Et on a besoin aussi d'avoir les moyens de modifier ce code-là sans avoir peur,
sans avoir besoin de retester tout le périmètre.
Au début c'est facile lorsqu'il y a 10 000,
20 000,
30 000 lignes de code de faire un test de périmètre,
lorsque le code est assez simple,
il n'y a aucun problème.
Lorsqu'on arrive à 100 000,
150 000,
200 000 et qu'on commence à toucher les 500 000 lignes de code,
que le périmètre devient très large et qu'on est une équipe de 20 personnes,
ça devient beaucoup plus compliqué de le faire si on n'a pas les tests qui vont avec.
Et donc naturellement ça devient plus compliqué de maintenir cette qualité logicielle.
Donc voilà,
j'espère que ce petit podcast vous a plu en réaction au Enzone Podcast.
que je vous invite à regarder,
qui est extrêmement intéressant.
Moi,
j'aime beaucoup le travail de Mathieu Calaoui.
J'espère que je n'ai pas écorché son nom.
J'aime beaucoup son travail.
J'aime beaucoup le travail de Hill Studio.
Je prends toujours beaucoup de plaisir à l'écouter,
même si,
sur ce podcast-là,
j'ai eu beaucoup de désaccords.
Maintenant,
ça fait partie du jeu.
Il y a différents avis.
Le plus important,
c'est de ne pas aller insulter et d'aller embêter les gens qui pensent différemment de vous.
Ça fait partie du jeu aussi.
Sur ce,
je vous laisse et je vous dis à bientôt.