Le pragmatisme coûte très cher !
Ou en tout cas sa définition totalement galvaudée dans le monde de l'IT
Qu’entend-on par pragmatisme dans l’IT ?
D’après le définition du Robert :
“Doctrine selon laquelle n'est vrai que ce qui fonctionne réellement.”
“Attitude d'une personne qui ne se soucie que d'efficacité.”
Ce sens initial a rapidement été galvaudé dans le monde de l’IT pour devenir synonyme de “quick & dirty”. Car qu’est-ce que le code quick & dirty après tout sinon “ne se soucier que d’efficacité et de ce qui fonctionne réellement” ? Le mot pragmatisme est alors invoqué tel un cantique ou comme une ode à la productivité, à la création de valeur, et donc à l’argent. Mais est-ce bien efficace de miser sur le court-termisme ? Combien de fois avez-vous vécu la situation de devoir rapidement livrer en production sous la pression d’une deadline irréaliste ? Combien de fois les décideurs vous ont rétorqué “il faut faire au plus vite, on n’a pas le temps pour faire les choses vraiment bien” alors que, ironiquement, un temps infini semble être disponible derrière pour réparer les différents bugs rencontrés après la mise en production ?
Cette vision du pragmatisme comme synonyme de “quick & dirty” est donc dangereuse, car elle devient l’excuse d’une médiocrité assumée qui coûte insidieusement de l’argent aux entreprises. Beaucoup d’argent. J’emploie le terme insidieux car le code “quick & dirty” camoufle totalement cette perte d’argent en faisant, au contraire, miroiter des revenus rapides, et récurrents. Le bât blesse une fois que le produit doit évoluer et que l’on garde cette même vision du “pragmatisme”.
Je vais revenir sur la “vraie” notion de pragmatisme dans le monde de l’IT, celle que j’essaye de mettre en place au sein de mon équipe, avec difficulté, car nécessairement sous couvert de différents compromis. Mais avant cela, il faut d’abord revenir sur une notion fondamentale dans l’informatique : la complexité. Alexey Zimarev en fait une analyse très pertinente dans son livre “Hands-On Domain-Driven Design with .NET Core” que je vais donc paraphraser ici.
Qu’est-ce que la complexité ?
“There is no silver bullet”
Je suis sûr que vous avez déjà entendu cette phrase à un moment donné dans vos lectures ou recherches. Elle signifie qu’il n’existe pas une solution unique pour tout types de problème. Mais savez-vous d’où elle vient ?
En 1986, Fred Brooks écrit un papier appelé “No Silver Bullet - Essence and Accident in Software Engineering”. Il y fait la distinctions entre deux types de complexité : la complexité essentielle, et la complexité accidentelle.
La complexité essentielle est celle qui fait partie intégrante de la solution que l’on cherche à développer. Sans cette complexité, le logiciel, l’application, ne fait tout simplement pas ce qui est requis par les besoins métiers.
La complexité accidentelle est apportée par la solution en elle-même. C’est par exemple l’ensemble des frameworks que l’on peut utiliser, l’ensemble des décisions architecturales de code, le type de base de données, les outils de mise en production, etc.
Les deux sont donc inévitables, mais la complexité accidentelle doit en permanence être réévaluée par rapport à la complexité essentielle, afin qu’elle ne devienne pas prédominante.
Les différents domaines de complexité
En 2007, Dave Snowden et Mary Boone ont publié un papier appelé “A Leader’s Framework For Decision Making”. Ils cherchent à y catégoriser les différents types de complexité, et propose un cadre de travail pour répondre à chaque type de complexité. Ils distinguent donc quatre catégories de problématiques :
Les problématiques simples :
Ces problématiques là sont évidentes. Ce sont des problématiques que l’on connait, et dont on connait les solutions aussi. Pour appréhender ce genre de problématique les étapes sont simples :
Etablir les faits, c’est-à-dire se rendre compte que l’on connait cette problématique et que l’on sait très bien la résoudre.
Identifier les process et les règles à mettre en place pour résoudre la problématique.
Agir pour résoudre la problématique grâce aux étapes identifiées.
Les problématiques compliquées :
Ces problématiques demandent de l’expertise et des compétences pour comprendre les causes et les conséquences car il n’existe pas de solution unique aux problèmes qu’elles génèrent. Ce sont les “inconnus connus”. Les actions à appliquer sont cette fois-ci :
Etablir les faits, comprendre que l’on a à faire à une problématique compliquée.
Analyser. Ici on ne peut pas identifier les process permettant de résoudre la problématique directement. Il convient donc d’analyser pour identifier les bonnes pratiques à appliquer.
Agir pour résoudre la problématique grâce aux bonnes pratiques identifiées pour ce problème en particulier.
Les problématiques complexes :
Ce genre de problématiques réunissent les problèmes que personne n’a vraiment résolus avant, il est donc impossible de faire ne serait-ce qu’une estimation du temps de réalisation de la solution. Ici nous avons donc à faire à “ce que l’on ne sait pas que l’on ne sait pas”, il convient donc de faire très attention au feedback de développement, et aux problèmes rencontrés pendant la réalisation de la solution, tout au long du développement de la solution. Les actions à suivre sont les suivantes :
Enquêter, obtenir des feedbacks le plus rapidement possible, par des prototypes, avec des itérations les plus courtes possible. Des techniques de modélisations comme l’EventStorming, l’Example Mapping, ou le StoryMapping sont ici tout à fait adaptées pour tenter de saisir l’essence du problème et avancer dans la bonne direction.
Analyser ce qui doit donc être développé, itération après itération
Agir pour développer concrètement ce qui a été convenu dans chaque itération, en prenant en compte le feedback
Les problématiques chaotiques :
L’enfer sur Terre. Rien n’est maîtrisé. C’est typiquement le moment où le “mode pompier” est activé dans les équipes. De ce fait il convient d’agir vite, très vite, mais de rétrospectivement analyser les causes du problème pour éviter de se retrouver à l’avenir dans cette catégorie :
Agir ! Régler le problème par tous les moyens dans un premier temps pour éteindre l’incendie.
Analyser les cause de cet incendie.
Mettre en place des pratiques en amont qui empêcheront à ce genre de problème de survenir à nouveau.
Le vrai pragmatisme
Le vrai pragmatisme c’est donc d’adapter chaque solution en fonction du type complexité rencontré.
Ce n’est en aucun cas une excuse pour écrire du code impropre, au risque de se retrouver dans la catégorie des problématiques chaotiques.
Il faut choisir les solutions en fonction des catégories de complexité énoncées plus haut. En aucun cas il est nécessaire de toujours faire la même chose aveuglément (sauf dans le cas utopique ou chaque membre de l’équipe a exactement la même expérience et les mêmes compétences en modélisation / architecture logicielles, et que c’est devenu une seconde nature d’appliquer ces méthodes).
Quand la problématique est simple, le pragmatisme nous dicte de ne pas réinventer la roue, et d’éventuellement acheter une solution toute faite. La simplicité de cette problématique indiquant de toute façon que ce n’est probablement pas le coeur de métier de notre application.
Quand la problématique est compliquée, le pragmatisme nous dicte de réfléchir en amont à la solution, de ne pas foncer tête baissée dans le code, appliquer des méthodologies de travail comme le Domain Driven Design, dans ses aspects stratégiques et techniques, pour limiter les risques d’échec est alors parfaitement sensé. Des ateliers de partage et compréhension des problématiques métiers ne sont pas forcément indispensables mais toutefois conseillés, comme l’EventStorming par exemple.
Quand la problématique est complexe, il y a énormément d’inconnues et il est nécessaire de pouvoir avancer rapidement, par itérations courtes, en profitant d’un feedback rapide. Des outils de modélisation comme le Domain Driven Design, et surtout les ateliers type EventStorming sont donc totalement nécessaires pour saisir l’essence des problématiques que l’on adresse. Il faut cependant limiter le périmètre au maximum, puisque l’on ne sait pas que l’on ne sait pas beaucoup de choses encore. Il faut donc réduire ces inconnues pour ramener ces problématiques de la catégorie “complexe” à “compliquée”. Les outils stratégiques du Domain Driven Design (comme les bounded contexts, le context mapping) sont extrêmement pertinent pour réduire les zones d’ombre à mesure que la compréhension de la problématique évolue. On pourra toutefois se passer de certains aspects technique du Domain Driven Design lors de la réalisation de spikes ou de POC.
Quand la problématique est chaotique il n’y pas le temps et le budget pour appliquer des méthodologies poussées, c’est ici le seul moment où le pragmatisme nous dicte l’option “quick & dirty”. Mais à la condition sine qua non d’analyser a posteriori , sous peine de rester bloqué dans cette catégorie.
Et peut-être le point le plus important de tous, n’oubliez pas que vous travaillez en équipe, et que le point de vue de tout le monde est à prendre en compte, et notamment la “douleur” de chacun dans son expérience de développement. Cela demande beaucoup d’intelligence sociale et cela s’apprend avec le temps, l’écoute, et la bienveillance. A vous de décider si vous souhaitez accompagner les développeurs moins à l’aise avec certains concepts pour monter le niveau de l’équipe, ou faire des compromis plus importants, tant que ça respecte le “vrai” pragmatisme.
Happy coding :)