[3/3] 3 acronymes que TOUS les développeurs devraient connaître : YAGNI

Pourquoi et comment laisser "évoluer" son design de code ?

Dans l’article de la semaine dernière, nous avons vu à quoi se référait l’acronyme KISS : Keep It Simple Stupid.

Il s’agissait de gérer deux types de complexité :

  • la complexité métier, inhérente aux problématiques que le logiciel doit résoudre

  • la complexité accidentelle, générée en créant du code qui devient difficile à lire, maintenir et faire évoluer

Il existe un autre acronyme, celui qui nous intéresse aujourd’hui, qui semble en apparence être très similaire à KISS, l’acronyme YAGNI : You Ain’t Gonna Need It (vous n’en aurez pas besoin).

Ce principe stipule donc de se concentrer uniquement sur le développement des fonctionnalités prévues, ni plus, ni moins. En ce sens, il s’inscrit donc parfaitement dans la mouvance Lean ou Agile, et semble être simplement le résultat du bon sens.

Mais voilà, tout comme KISS, c’est bien plus subtile que cela.

Une histoire de coûts

La réussite d’un projet peut se mesurer de plein de façon différente, mais s’il en est une qui a le mérite de mettre tout le monde d’accord, c’est que s’il n’y a plus d’argent, alors il n’y a plus de projet…

Développer une fonctionnalité coûte cher, très cher. Les mouvements Lean et Agile, par exemple, prônent donc tout deux une approche prudente des développements, afin de réduire au maximum le ratio coût/bénéfice.

Dans les années 90, la méthodologie de développement logiciel était plutôt basée sur une grande réflexion en amont (big design upfront) sur les fonctionnalités attendues d’un logiciel, et comment elles vont être développées.

Comme vous pouvez vous en douter, tout prévoir et développer en amont coûte de l’argent, beaucoup d’argent. Le coût du développement en lui-même, certes, mais pas que. Voyez plutôt :

  • le coût de production : c’est donc le fameux coût de développement de toutes les fonctionnalités. Le temps total passé à développer.

  • le coût de délai des bénéfices : si l’on passe son temps à développer beaucoup de fonctionnalités en amont, avant même de mettre en production, on se prive des revenus potentiels générés pendant ce laps de temps par les premières fonctionnalités qui auraient pu être mises en ligne.

  • le coût de maintenance : toute fonctionnalité développée doit être maintenue. Maintenir le code n’est pas gratuit, donc c’est un coût à part entière avant même que ces fonctionnalités soient forcément utiles à l’utilisateur final.

  • le coût de réparation : le risque en développant toutes les fonctionnalités en amont est de se rendre compte qu’en fait elles ne correspondent pas vraiment aux besoins actuels des utilisateurs. On doit donc les “réparer” quand il ne faut tout simplement pas les supprimer.

Dressant ce tableau peu flatteur, la mouvance eXtreme Programming (XP) est née pour, entre autre, remédier à ce problème.

Elle a renversé complètement la table, en privilégiant au contraire la notion de “design évolutif”. Pas de réflexion conséquente en amont, juste du code écrit au moment où c’est nécessaire. Je ne vais pas rentrer dans les détails de l’XP ici, mais sachez que c’est entre autre ce qui a donné naissance au mouvement Agile !

Le design évolutif

Il a été démontré dans une étude effectuée par Kohavi et al se concentrant sur les produits Microsoft que, même après une analyse minutieuse des besoins en amont, seulement 1/3 des fonctionnalités prévues avaient l’effet escompté sur les chiffres clés de l’entreprise.

Ce n’est pas une surprise, personne n’a de boule de cristal…

Le design évolutif repose sur une idée simple : développer uniquement les fonctionnalités au moment où on en a besoin.

Cela va donc totalement à l’encontre de la grosse préparation en amont qui prévoit tout et son contraire avant un projet.

Là est le cœur du principe YAGNI : ne pas développer une fonctionnalité “parce qu’on en aura potentiellement ou surement besoin un jour”.

Lorsque l’on est tenté de faire une évolution ou prévoir une fonctionnalité en amont, on peut se retrouver dans deux situations :

  • il est certain que cette fonctionnalité sera nécessaire dans le futur. Auquel cas on se dit qu’il est préférable de l’implémenter directement

  • il est possible que cette fonctionnalité évolue plus tard, et comme on est déjà “le nez dans le code”, on se dit “tant que j’y suis, autant le faire directement”.

Dans ces deux cas, il faut appliquer le principe YAGNI en se concentrant uniquement sur ce dont on a besoin sur le moment présent. Autrement dit, pas de “futur-proofing”, c’est-à-dire de décisions prises en pensant à d’éventuelles fonctionnalités futures.

“Pas besoin de réfléchir à l’architecture logicielle t’inquiète, on garde le code le plus simple possible donc supprime moi tout ça :) YAGNI rappele-toi !”

Ici le principe YAGNI est invoqué à tort ! C’est là toute la subtilité du principe YAGNI : il ne s’applique qu’au code concernant d’éventuelles fonctionnalités futures ! Pas au code censé rendre le code plus simple à modifier !

En effet, si le principe stipule qu’il faut pouvoir faire évoluer le code pour ajouter une nouvelle fonctionnalité le plus rapidement possible, et juste quand on en a besoin, alors il faut que le code le permette.

Le code doit donc être refactorable, pour tendre vers toujours plus de simplicité à mesure que les fonctionnalités évoluent ou s’ajoutent.

Quel est le meilleur moyen pour pouvoir faire évoluer du code sans risquer de tout casser à chaque fois ? Une bonne suite de tests !

Et comment s’assure-t-on d’avoir une bonne suite de tests ? En créant du code découplé, modulable. Bref, en réfléchissant à l’architecture, au design, au fur et à mesure. Le tout, sans créer d’abstractions inutiles. Pour l’éviter je vous renvoie à mon article sur l’acronyme DRY.

Ce n’est pas un hasard si le principe YAGNI vient de l’eXtreme Programming, car il est le découlement logique des 4 règles censées qualifier un système de “simple” :

  • Passe tous les tests

  • Pas de duplication

  • Code clair, qui révèle son intention (à travers de bonnes abstractions par exemple)

  • Avoir le moins possible de classes / fonctions / méthodes.

Ce qui est “drôle”, c’est que le principe YAGNI est souvent invoqué comme une sorte de carte ultime, une ode au pragmatisme pour repousser toute tentative d’un quelconque embryon de réflexion sur l’architecture logicielle, voire sur certaines bonnes pratiques pourtant éprouvées depuis des décennies.

Galvauder le principe YAGNI pour le rendre synonyme de “quick & dirty” est donc la pire chose à faire.

Un code qui évolue en permanence, sans réflexion, sans refactorisation, augmente considérablement son entropie et devient totalement impossible à maintenir à moyen et long terme.

Du coup la prochaine fois que vous écrivez du code en essayant de le rendre facilement modifiable et évolutif et que vous vous voyez rétorquer : “YAGNI !!!”, vous pourrez répondre : “Génial ! Toi aussi tu voues une importance fondamentale à l’architecture logicielle ?” ;)

Pour en savoir plus, je vous renvoie aux excellents articles (en anglais) de Martin Fowler à ce sujet :

Happy Coding !