Pourquoi le logiciel coûte-t-il cher ?
Parce que les devs sont trop payés ? Nice try, mais non. Et puis nous ne sommes pas là pour Paul et Mickey.
Il y a en premier lieu cette fâcheuse tendance à développer des choses dont personne n'a besoin. Nous pensons savoir ce que l'utilisateur veut sans l'être nous-même, utilisateur.
Si les chats pouvaient parler… 🐈
D'où la nécessité d'une vraie user research, de persona et d'une attention constante portée au feedback des utilisateurs. Cela paraît évident et simple, mais la multiplication des strates organisationnelles et la segmentation des responsabilités font que celles et ceux qui créent les applications n'ont souvent plus aucune interaction directe avec les utilisateurs.
"Un utilisateur ? Oui, j'en ai vu un, une fois. Je m'en souviens très bien, c'était le 12 juillet 1990."
Ces principes constitutifs de la User Experience (UX) étaient bien compris des pères fondateurs de l'agilité, qui les ont intégrés pour partie et y ont adjoint des considérations propres au développement. On retrouve ainsi au cœur de l'agilité l'injonction à travailler en cycles courts et à livrer fréquemment en production afin de rester au plus près des besoins des utilisateurs. S'adapter au changement.
On sait malheureusement ce qu'est devenu l'agilité : "Nous, on fait des sprints de durée variable". Aïe. Si besoin, pas de honte, sachez que j'ai créé une formation pour vous aider à séparer le bon grain de l'ivraie. Vous apprécierez le titre : L'agilité au marteau.
Tout ça pour en arriver au sujet dont je voulais vous parler : le code. Écrire du code, au fond, ça n'est pas si compliqué. Quand on parle d'informatique de gestion, quelques mois d'apprentissage suffisent pour faire des choses simples. Oui, on tâtonne un peu, mais à la fin ça marche. Non, ce qui est compliqué, c'est le long terme. Je m'explique.
Les premières fonctionnalités sont posées. Quelques mois ont passé et il faut à présent en ajouter de nouvelles, ce qui implique de modifier à la marge le code déjà écrit. Les fonctionnalités déjà à l'œuvre deviennent des cas particulier de concepts plus larges, il faut donc principalement apporter de la généricité.
C'est là que les choses se compliquent :
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
Ah.
Vous comprenez comment fonctionne cette expression régulière ? Il s'agit de validation d'emails. Rassurez-vous, aucun humain ne peut comprendre ça vu que ces lignes ne traduisent en rien l'intention du développeur/de la développeuse. Impossible donc de faire évoluer ce code, d'autant qu'aucun test ne vous protège contre les régressions. Au moindre besoin, vous devrez repartir de zéro. Du code legacy pur.
Dans l'absolu, c'est aussi absurde que de changer de voiture parce qu'un clignotant ne fonctionne plus. Pourtant, c'est bien ce qui se produit. Il n'est pas rare de voir des applications d'entreprise mises au rebut au bout d'un an, un an et demi seulement. Les personnes ayant contribué à son développement sont parties, leur code est abscons, la compétence est perdue.
Le Software Craftsmanship ou "Craft" - en français l'artisanat logiciel - apporte heureusement de nombreuses réponses pour éviter de se retrouver dans ce genre de situation. On pourrait les catégoriser comme suit :
-
Lisibilité : faire en sorte que le code reste intelligible pour des humains. Ce sont avant tout des considérations de clean code, mais aussi de Domain-driven design (pour le nommage), de typage (pour celles et ceux qui seraient tentés d'écrire du JavaScript pur) et de programmation fonctionnelle (pour les fonctions pures, qui facilitent la compréhension d'un système) ;
-
Testabilité : disposer d'un filet de sécurité pour repérer la moindre régression, qu'elle se soit glissée au niveau d'une fonction (tests unitaires) ou réside dans la collaboration défectueuse entre plusieurs fonctions (tests d'intégration). Par extension, on peut y rattacher le typage, qui sert le même objectif, et tant qu'à faire la programmation fonctionnelle en ce qu'elle facilite le test. Mais bien plus encore, les tests peuvent nous guider dans la découverte fonctionnelle (Behavior-driven development) et dans l'écriture de code (Test-driven development) ;
-
Modularité : le problème, c'est quand tout dépend de tout. Vous réparez le clignotant de votre voiture et, soudain, la climatisation ne fonctionne plus. Bizarre, quand-même. À cet instant précis, c'est tout le champ de savoir du Domain-driven design qu'il faut convoquer pour constituer des zones d'isolation, sur base de considérations propres au métier. Un savoir essentiel pour maintenir votre système d'information en capacité d'évoluer.
Ce sont à mes yeux les 3 piliers de l'artisanat logiciel. Bien maîtrisés, ils évitent de créer trop de dette technique… notre prochain sujet.
À la semaine prochaine 👋 !