Introduction
Je m'appelle Christophe Thibaut. Je suis un coach XP, un consultant avec plus de 30 ans d'expérience dans le développement logiciel, le leadership technique, le conseil et le coaching. J'aide mes clients à améliorer leurs pratiques et à résoudre des problèmes complexes ensemble.
Autres Publications
- En finir avec la "Dette Technique"
- Dette Technique et Procédés en Conflit
- La Fin de la "Dette Technique" : Résoudre les Conflits
- La Fin de la "Dette Technique" : du Passé ne pas Faire Table Rase
- Le demi cercle - une équipe et son état de l'art (52 épisodes)
Livres
Podcasts
-
Interview avec Benoît Gantaume - Artisan Développeur : en finir avec la "Dette Technique"
-
Interview avec Thomas Wickham - Café Craft : Améliorer la qualité des conversations
-
Interview avec Thomas Wickham - Café Craft : 4 étapes de la qualité
Dette Technique
- La Dette Technique, qu'est-ce que c'est ?
- Chiffrer la Dette ?
- Une Traduction Incohérente
- Au Cœur du Processus
- Le Rôle du Management
- Un État de l'Art Désaligné
- Pratiques de Prévention
- Le Rôle du Product Owner
- Un Levier de Vitesse
- Retour d'Information
- Une Facture Imaginaire
- Mission Failed ?
La Dette Technique, qu'est-ce c'est ?
Le code qui tourne à l'instant t sur nos machines est la cristallisation de conversations entre ces 3 acteurs : Métier, Technologie, Management.
Dans une situation de code legacy, le code tourne toujours, mais la conversation n'a plus lieu.
Dans une situation où la conversation a toujours lieu mais est entravée par des barrières de communication, nous disons du code qui tourne sur nos machines qu'il est "endetté techniquement".
Dette Technique ?
La Dette Technique est une métaphore créée par Ward Cunningham qui permet de penser le traitement de ce déchet ("cruft"), en le voyant comme une dette financière. L'effort supplémentaire requis pour ajouter des fonctionnalités représente l'intérêt payé sur la dette.
(Martin Fowler)
L'explication que je donnais à mon chef -- et c'était du logiciel financier -- était une analogie que j'appelais "la métaphore de la dette". Et qui disait que si nous échouons à aligner notre programme avec ce que nous comprenons comme la façon adéquate de penser nos objets financiers, alors nous sommes condamnés à buter sans arrêt sur ces désaccords, ce qui nous ralentit et qui équivaut à payer des intérêts sur une dette.
(Ward Cunningham)
De simple métaphore élaborée à des fins d'illustration, la dette technique est devenue une métrique. Elle se mesure, se calcule, et on peut ainsi la "manager" :
Technical Debt (sqale_index): Effort to fix all Code Smells. The measure is stored in minutes in the database. An 8-hour day is assumed when values are shown in days.
Technical Debt Ratio (sqale_debt_ratio): Ratio between the cost to develop the software and the cost to fix it.
(Manuel Sonar)
Il s'agit en fait d'une pseudo-métrique. Il est facile de voir qu'un tel "effort" est impossible à calculer dans l'absolu (même en "minutes"), et de plus il n'est pas question d'argent.
Dans l'entreprise qui m'emploie, si je détériore un actif, je vais tôt ou tard en assumer les conséquences. À ma connaissance aucun développeur dans aucune entreprise n'a jamais eu de retenue sur salaire du fait d'avoir un code endetté. La création de dette technique ne semble pas préjudiciable aux résultats de l'entreprise. Au contraire, elle est plutôt encouragée.
La dette technique, est-ce vraiment technique d'ailleurs ? Dans mon expérience, lorsque le code est "endetté", c'est plutôt le résultat de décisions bien en amont de la technique.
Pour en savoir plus sur le sujet, rendez vous demain !
publié sur Linked In le 19/01/2023
Chiffrer la Dette ?
La dette technique ce n'est pas de la dette, et ce n'est pas technique.
Lorsque nous disons que le code d'une application présente de la dette technique, deux simplifications s'opèrent :
-
nous considérons le problème uniquement sous l'angle du code
-
nous convertissons ce problème en euros
On sait bien que le problème n'est pas intrinsèquement dans le code lui-même. On dit souvent que le code "pourrit", mais en réalité, le code c'est-ce qu'il y a de plus stable dans notre industrie.
Ce code legacy en C, soigneusement rangé au fond d'un disque sur mon NAS, depuis la dernière amélioration que j'y ai apporté le mardi 19 janvier 1993, il n'a pas changé d'un bit : c'est tout le reste qui a changé.
C'est ce qui rend le code legacy si intéressant : il reflète des conversations qui se sont perdues depuis longtemps. C'est une traduction enfouie.
J'ai extrait ce code en vue d'en faire "chiffrer la dette technique" par trois personnes expérimentées.
Ce code implémente une table de hachage en C, ce qui permettait, à l'époque, de stocker en mémoire des dictionnaires de types "clé/valeur" assez performants.
A : Le C, c'est portable. Bravo, c'est du code propre que tu as là. Est-ce qu'il y a des tests au fait ?
B : Pourquoi t'embêter avec ce code quand n'importe quel langage moderne offre gratuitement des dictionnaires clé/valeur ? A minima, tu pourrais utiliser glib…
C : Qu'est-ce que tu veux faire précisément, avec ce code ?
Ni A,ni B, ni C ne me fournissant une réponse chiffrée, tournons-nous vers l'outil cité hier, qui propose cette métrique :
Technical Debt (sqale_index): Effort to fix all Code Smells. The measure is stored in minutes in the database. An 8-hour day is assumed when values are shown in days.
Il semble que ceux qui ont mis au point cet outil cherchaient un nom qui sonne bien plus que tout autre chose. De ces trois suppositions audacieuses :
-
la dette technique c'est un ensemble de "code smells",
-
que l'on peut détecter automatiquement,
-
dont le coût de réparation en minutes est connu.
la numéro 3 est la plus spectaculaire. Elle amène tant de questions :
- avec ou sans tests automatisés ?
- avec ou sans relecture de code ?
- à l'aide de quelle documentation ?
- est-ce qu'il y a un délai de réparation ?
- qui prend en charge la réparation ?
- avec quelle expérience ou ancienneté dans le langage ?
- avec quelle expérience du refactoring ?
- avec quelle connaissance du contexte métier dans lequel tourne ce code ?
- est-ce que la réparation se fera en binôme ou en solo ?
- quelles compétences spécifiques sont requises ?
- est-ce qu'on testera la réparation ?
On peut s'arrêter là, on voit bien que c'est sans espoir. En matière de chiffrage automatique, l'outil n'a pas toutes les réponses; il n'a même pas les bonnes questions.
Pour en savoir plus sur la dette technique, ne manquez pas mon prochain post sur le sujet, demain !
publié sur Linked In le 20/01/2023
Une Traduction Incohérente
La dette technique, c'est donc juste une façon de parler. Mais de parler de quoi, au juste ?
Pour Ward Cunningham à l'origine, contracter une dette technique, c'est prendre un raccourci sur notre état de l'art et nos standards le temps d'atteindre un objectif intermédiaire. Une tactique à n'utiliser que ponctuellement, sous peine de se sur-endetter.
Pour l'ensemble de l'industrie aujourd'hui -- à en croire en tout cas les articles de blog des sites de conseil stratégique -- la dette technique est une sorte d'externalité financière globale présente dans toute entreprise qui innove en développant du logiciel. Elle serait principalement causée par :
- l'entropie, ou le fait que "le code pourrit"
- le code de mauvaise qualité
- un leadership technique médiocre
(tant qu'on y est, je pense que l'on pourrait ajouter :
- le court-termisme en général
- la vie)
Je pose que les problèmes que nous désignons (ou que nous masquons) à l'aide du terme "dette technique" ne sont en fait, ni purement financiers, ni purement techniques. Pour mieux le voir, je propose de changer de modèle.
La représentation du développement logiciel la plus répandue aujourd'hui est celle d'un système de fabrication. Dans ce modèle, certains acteurs, les thinkers, ont pour tâche de concevoir, de traiter le "pourquoi", le "quoi" et le "quand". D'autres acteurs, les doers ont pour tâche de réaliser, de traiter le "comment".
Dans ce modèle, les thinkers font des propositions "sur le papier", et les doers "mettent les mains dans le cambouis". La dette technique, c'est l'épaisseur du cambouis.
Cette représentation ne fonctionne pas. Les organisations qui y souscrivent fabriquent invariablement (grâce à la fameuse "software factory") du code legacy.
Une autre représentation est possible, qui voit le développement (et la maintenance) de logiciel comme un système de traduction. Trois acteurs :
- le Métier, dont l'objectif est de réaliser de la valeur,
- la Technique, dont l'objectif est d'apprendre,
- le Management, dont l'objectif est de maintenir l'activité dans la durée
opérent ensemble une traduction d'un système d'idées vers un autre système d'idées.
Il n'y a pas de cambouis ni de papier dans ce processus. Il y a seulement des traductions à de multiples niveaux, dans un sens et dans l'autre, entre le Métier, la Technique, et le Management.
C'est un processus complexe, riche et incomplet, que nos trois acteurs essaient de mettre en œuvre de la manière la plus cohérente possible.
La dette technique est ce qui se produit lorsque des barrières de communication entre ces acteurs empêchent ou diminuent fortement la cohérence de cette traduction.
La dette technique, c'est une traduction incohérente.
Un exemple là maintenant serait le bienvenu, mais on manque un peu de place, et un peu de temps. Pour en savoir plus, restez branché ! 📡
publié sur Linked In le 21/01/2023
Au Cœur du Processus
La dette technique, vue depuis le modèle Développement = Production :
-
des concepteurs imaginent un système, déclinent une roadmap, mettent en œuvre un projet
-
des développeurs écrivent le code, concrétisent le système, font marcher la technologie, et la livrent en production
-
après un temps plus ou moins long, le code du système présente un certain nombre de caractéristiques indésirables : la dette technique.
La dette technique, vue depuis le modèle Développement = Traduction :
— Trois acteurs (Métier, Technique, Management) aux objectifs complémentaires mais distincts partagent un projet commun.
— Ils s'accordent sur un certain état de l'art : celui permettant de traduire au mieux leurs idées vers un système utilisant la technologie.
— Au cours du processus de développement, cet état de l'art se désaligne. La traduction devient incohérente. Certaines idées sont perdues, ou déformées, voire détournées.
Voici quelques exemples de création de "dette technique" :
-
Un client fait produire à une société de conseil un "Proof of Concept". Après démo et restitution des résultats du POC, le client demande à ce que ledit POC soit déployé en production. Les consultants insistent sur le fait que leur livrable ne constitue qu'une expérimentation et non un produit exploitable. Le POC finit tout de même en production.
-
Un projet de développement démarre sous les auspices de la qualité logicielle: l'état de l'art initial décrit entre autres les pratiques de tests automatisés et de revue qui auront cours. 3 mois plus tard, parce qu'une partie de la complexité du projet a été sous-estimée, et du fait que le risque de dépassement n'est pas partagé ouvertement, l'équipe technique, sous pression, sacrifie une partie de ses standards. Elle s'inflige alors cette ironie : puisque le problème est plus complexe qu'initialement prévu, on réalisera moins de vérifications, moins de revues, moins de tests.
-
En début de sprint, le P.O demande à l'équipe : "s'il vous plaît, pas de tâches de refactoring sur le board. Nous devons absolument finir les fonctionnalités. Vous vous ferez plaisir après la mise en production."
Vous me direz : ces exemples ne sont pas de la dette technique. Ce sont des histoires de décisions Métiers hâtives, de mauvaise méthodo de projet, d'incompréhension mutuelle, de stratégie de gestion du patrimoine logiciel...
Pourtant tous ces projets ont commencé dans la cohérence. La dette technique c'est cela : la cristallisation, dans la technologie, de conversations qui ont perdu de leur cohérence.
Alors que faire ? On peut faire quelque chose ! Stay Tuned.
publié sur Linked In le 22/01/2023
Le Rôle du Management
Thèse : Le développement de logiciel comporte un coût caché lié à la mauvaise qualité du code et/ou du leadership technique, la dette technique, qu'il revient à la Technique de réparer sous peine de grever le budget des évolutions fonctionnelles futures.
Antithèse : Le code d'un logiciel est la cristallisation de conversations entre trois acteurs : Métier, Technique et Management, obtenue à travers un processus continu de traduction multiple et complexe, faisant intervenir de nombreux états de l'art. Lorsque ces conversations perdent en cohérence, le code cristallise en retour ce désalignement.
Synthèse : La dette technique est relative aux objectifs et contraintes que se donnent les trois acteurs dans leur projet de développement logiciel et dans ses évolutions. Dans cette perspective, manager "la dette technique" revient à gérer les conséquences au lieu de prévenir les problèmes. En revanche, prévenir la dette technique, empêcher qu'elle se produise ou du moins qu'elle augmente, constitue la tâche du Management (bien sûr, en étroite symbiose avec le Métier et la Technique).
Dans l'organisation, trois acteurs se réunissent afin de développer et maintenir du logiciel. Ce n'est pas nécessairement leur but premier à chacun, mais c'est le but qu'ils ont en commun, le temps que ce logiciel existe :
Le Métier a pour objectif de réaliser de la valeur. À ce titre, le "rêve" du métier, son pattern de référence, sa "caricature" si l'on veut, est l'innovation. Le Métier veut se retrouver demain, ou avant demain, devant la compétition.
La Technique a pour objectif d'apprendre. Sa caricature est de faire école. Lorsque les acteurs techniques n'apprennent plus, ils démissionnent.
Le Management a pour objectif de maintenir. Sa caricature est la factory, une sorte de machine à produire qui serait fiable, stable, régulière et pérenne.
La persistence des problèmes (que j'appellerais des problèmes de croissance) que rencontrent les entreprises qui développent et maintiennent du logiciel montre à quel point le rôle du Management est difficile dans ce domaine. En effet,
- il doit prendre en compte un très grand nombre de tenants et aboutissants liés au Métier comme à la Technique
- il doit créer au sein de l'entreprise une institutionnalisation des fondations qui permettent de maintenir du logiciel de manière cohérente, tandis que le marché du service accentue le mercenariat des activités
- il doit traiter avec le quotidien des équipes aussi bien qu'avec la stratégie et la politique dans l'entreprise
- il doit vivre au rythme absurde de la technologie sauf à défendre un conservatisme incongru
À cet égard il est difficile de ne pas voir dans les tendances actuelles l'augure d'une augmentation en masse de la "Dette Technique" dans les entreprises.
Bon, encore des généralités, voire des généralisations... La dette technique : Que faire ? Nous y arrivons, stay tuned !
publié sur Linked In le 23/01/2023
Un État de l'Art Désaligné
Stabilité du code. Le code Forth écrit sur mon C64 il y a 40 ans "marche" encore. Lancer ce code aujourd'hui sur une telle machine me serait difficile, coûteux (et inutile), mais ce code, lui, n'a pas bougé. C'est tout le reste qui a changé.
De même pour le code que nous avons déployé en production il y a 3 mois. Il ne subit aucune altération, et pour peu que nous sachions comment le redéployer via un plan de secours, il est en sécurité.
Tout le reste va changer. Voici ce que nous allons découvrir :
-
un nombre indéterminé mais fini d'oublis, de distractions, de contresens, de calembours, d'erreurs de type et autre pointeurs nuls, qui mesurera en partie l'écart entre la réalité du comportement du système tel que nous l'observons et l'idée que nous nous en faisons
-
certaines des règles qui déterminent le comportement du code sont incomplètes, contradictoires ou incohérentes avec ce que nous croyions avoir conçu correctement, en accord avec le Métier et le Management
-
sa structure nous semblait adéquate pour l'objectif Métier tel que nous le comprenions, mais un nouveau pan fonctionnel, dévoilé il y a peu en comité de pilotage, nous fait dire que des remaniements importants seront nécessaires
-
la seule personne qui militait (oui, c'est le mot, dans beaucoup d'équipes, il faut militer pour cette cause) pour qu'on écrive des tests automatisés sur la partie middleware, quitte le projet, et nous ne savons pas si l'état de l'art de l'équipe — et donc de la future version du code — sera maintenu
-
notre optimisme — cette maladie professionnelle — va à nouveau buter sur le constat que ce programme, ce projet, sont plus complexes qu'ils en avaient l'air initialement, lors du chiffrage
Et nous appellerons cela, de la Dette Technique. Nous continuerons à prêcher pour une méthodo plus Agile, un delivery plus Craft, mais sans quitter nos modèles et sans nous poser la question cruciale :
Comment se fait-il qu'un projet cadré le 2 Janvier par une équipe soudée, cohérente et dynamique, produise au 30 Septembre une dette technique aussi élevée ?
La dette technique est la cristallisation d'un état de l'art désaligné qui, depuis le code, nous parle des contraintes, des objectifs, et de l'équipe au sens large.
La contre-mesure consiste à réaligner votre état de l'art : faire en sorte que les objectifs, les contraintes et l'ensemble des procédés qui constituent le standard du projet soient mieux alignés et plus cohérents. C'est un travail compliqué, assez peu technique. Pour "désendetter" il faut certes un menu Refactor, mais il faut aussi et avant tout des conversations.
Dans un modèle de développement vu comme un processus de fabrication, la dette technique culmine, parce que dans ce modèle on essaie de limiter le nombre et la durée des conversations.
Dans un modèle de développement vu comme un processus de traduction, il en va autrement. Stay Tuned !
publié sur Linked In le 23/01/2023
Pratiques de Prévention
La dette technique, c'est un rebut, présenté comme un fait accompli. La dette passée nous empêche de faire évoluer rapidement le logiciel. Mais la dette future, nous la paierons plus tard, il y a plus urgent dans le backlog.
Que faire ?
Créer comme certains le recommandent une équipe transverse de désendettement ? Elle travaillerait sur les mauvaises priorités, toujours après la bataille, coûteuse, inessentielle.
Nous pouvons changer de modèle. Nous n'avons pas nécessairement besoin d'adhérer à un système de représentations s'il ne produit pas des changements dans le bon sens, et nous devrions même le questionner.
Si nous fabriquons de la dette spontanément, sans le savoir : nous devrions examiner la façon dont nous travaillons, et y remédier. Toute industrie améliore ses procédés.
Si nous sommes conscients de créer de la dette mais continuons à le faire : d'où nous vient un tel fatalisme ?
De fait nous connaissons des pratiques qui limitent la dette technique. En voici quelques unes :
🏷 Product Owner : rôle définissant les responsabilités et prérogatives liées à la traduction en application, des idées élaborées avec le Métier
🏷 Architecte : rôle définissant les responsabilités et prérogatives liées à la traduction Technique des contraintes et objectifs stratégiques élaborées avec le Métier
🏷 User Story : pattern d'interaction dans lequel le Métier et la Technique partagent une description succincte d'un comportement possible du logiciel du point de vue de ses utilisateurs
🏷 Backlog Grooming : rituel durant lequel le Métier et la Technique raffinent ensemble la traduction d'idées à ajouter prochainement au logiciel en cours de développement
🏷 Ensemble Programming : session d'écriture de code en équipe, dans laquelle l'équipe raffine et traduit une idée de comportement à ajouter au code
🏷 Pair Programming : session d'écriture de code à deux, qui combine les rôles de manière à ce qu'une idée de comportement passe toujours par la compréhension d'un coéquipier avant d'entrer dans le code
🏷 Test Automatisé : pattern de code auto-exécutable décrivant les aspects intéressants du comportement d'un logiciel et les vérifiant à travers une exécution
🏷 Refactoring : action de modifier le code d'un programme afin d'en améliorer la facilité d'évolution, sans modification de son comportement
🏷 Revue de Code : procédé de relecture de code permettant à l'équipe de valider des améliorations faites individuellement sur le code, de consolider ses standards, et de maintenir sa cohésion d'équipe Technique
🏷 Rétrospective : rituel au cours duquel une équipe examine et améliore ses procédés, son organisation, ses patterns de communication ainsi que sa cohésion
Remarquez vous à quel point ces pratiques ont pour sujet la traduction, et non la fabrication ? Stay tuned !
publié sur Linked In le 24/01/2023
Le Rôle du Product Owner
Dans mon post précédent, j'affirme que le pattern Product Owner :
🏷 rôle définissant les responsabilités et prérogatives liées à la traduction en application, des idées élaborées avec le Métier
permet à une équipe de limiter sa dette technique, c'est à dire de prévenir ou de mitiger le désalignement de son état de l'art.
Comment est-ce possible ?
Dans une vision du développement comme processus de fabrication, cela paraît difficilement possible, car :
-
la dette technique est un problème situé dans le code
-
seuls les développeurs, qui sont des doers, mettent les mains dans le code
-
le PO, qui est un thinker, n'a pas d'influence, positive ou négative, sur le code
On pourrait objecter que certains POs ont une influence (négative) sur la dette technique quand ils dépriorisent des tâches de refactoring sur le backlog, ou bien font pression pour intégrer un maximum de stories dans le sprint en dépit des mesures de vélocité constatée. Mais ces deux actions : décider des tâches techniques, négocier le coût des stories, ne font pas partie des prérogatives normales du rôle de PO, ce sont là des dérives de la software factory.
Si l'on adopte une vision du développement comme processus de traduction, l'influence du PO sur l'état de l'art de l'équipe devient évidente. Le pattern Product Owner permet d'établir une conversation entre la Technique et le Métier, laquelle vise une correspondance maximale entre les choix dit fonctionnels et les possibilités de la technologie (dans un contexte incertain, en présence d'un problème partiellement défini, et avec des ressources limitées).
Le PO offre aux développeurs un échantillon des idées élaborées lors d'échanges avec des acteurs Métier éloignés de l'équipe Technique. Les développeurs le rejoignent à mi-chemin avec leurs outils de programmation, leurs tests, et leur démarche de conception guidée par le domaine.
Les patterns Ubiquitous Language, Bounded Context, Hands On Modelers sont particulièrement représentatifs de cette démarche.
Voici un exemple, tiré d'une conversation entre un PO et deux développeurs :
▶️
PO : pour ce qui est du portefeuille...
D1 : Question: dans le schéma de BD du back-end existant, il n'y a pas de table Portefeuille...
PO : Peut être, mais en fait, les agents parlent de portefeuille dans les agences..
D2 : La table des comptes contient des comptes spéciaux. Il y a un flag qui permet de les voir comme "portefeuille".
D1 : Wouah !
PO : Ah oui, c'est vrai. OK, donc...
D2 : Euh... On devrait peut être modéliser ce qu'est un portefeuille ?
⏸
À votre avis : ce que va dire ensuite le PO aura t'il une influence sur la dette technique de l'équipe ?
À mon avis : oui, une influence cruciale.
Stay Tuned !
publié sur Linked In le 25/01/2023
Un Levier de Vitesse
Telle que présenté par Ward Cunningham, le pattern Dette Technique est un curseur avec lequel l'équipe peut "jouer" : face à un objectif intermédiaire important et urgent, elle peut décider de déroger temporairement à son état de l'état de l'art, quitte à réaliser par la suite un effort supplémentaire pour revenir au standard.
Exemple :
▶️
PO : La démo est vendredi, et la story qu'on avait décidé de montrer n'est pas prête, on est d'accord ?
D1 : Techniquement, la story est prête, mais la BD migrée au nouveau schéma ne sera pas disponible d'ici vendredi.
PO : Donc, prête ou pas prête ?
D2 : Si on n'avait pas besoin de la BD, la story serait déjà pratiquement démontrable.
PO : Je vois. C'est dommage. C'est une démo attendue par le Métier.
D2 : Et si on disait, le temps de la démo, que les données saisies sont enregistrées en local, dans un fichier plat ?
D1 : Tu veux dire qu'on sérialise les objets directement ? C'est crade.
PO : Ça nous permettrait de ne pas annuler la démo ?
D1 : Oui, mais c'est crade.
D2 : Et ensuite on remet en place la persistance normale. Qu'est-ce que vous en pensez ?
⏸
Dans cet exemple ce qui va se produire pour le projet vendredi dépend crucialement de la dette technique :
-
scénario A : l'équipe explique que la démo doit être annulée ou déroulée incomplètement pour des raisons technique diverses.
-
scénario B : l'équipe déroule la démo, reçoit des félicitations et des encouragements, et inscrit une tâche de désendettement dans sa todo du prochain sprint.
💡 Conséquence :
Si la dette technique est un curseur avec lequel l'équipe Technique peut moduler la rapidité avec laquelle elle produit, alors elle va immanquablement devenir un LEVIER pour le Métier (tel que représenté par le PO).
⬆️ En poussant le curseur DT vers le haut, l'entreprise peut se doter plus rapidement d'un logiciel moins pérenne, moins robuste, moins stable, etc.
⬇️ En tirant le curseur DT vers le bas, elle concède des délais (bien souvent des délais imprévus au départ) et "donne du temps au temps" afin de se doter d'un logiciel de meilleure qualité, plus conforme à ses besoins à moyen et long terme.
On voit assez bien comment l'entreprise peut passer d'un usage raisonné de ce curseur à un abus chronique :
- un projet démarre, sur la base d'un cadrage "optimiste" (complexité sous-estimée)
- l'équipe Technique prend du retard (en fait, recadre la complexité réelle du projet)
- elle fait, sous la pression, le choix de se sur-endetter techniquement
- le retard est aggravé par le paiement des intérêts (le code est plus difficile à changer)
- la pression augmente; l'équipe prend de nouveaux expédients, etc.
et le tour est joué !
La dette technique est un levier de productivité. Dans le monde complexe du développement logiciel, nous jouons avec ce levier et nous en tirons avantage, à nos risques et périls.
🙏 Merci @ArmelleLelarge pour ta suggestion d'hier, qui a déclenché cette réflexion.
Stay Tuned ! 📡
publié sur Linked In le 26/01/2023
Retour d'Information
Le développement de logiciel est un travail complexe. Pour simplifier ce travail, nous le divisons :
🗺 en vues hiérarchiques et transversales, à l'intérieur et entre lesquelles s'opèrent les traductions : le domaine fonctionnel, le système d'information, l'architecture applicative, la conception, l'implémentation, l'infrastructure etc.
👩🏽💻 en rôles spécialisés : PO, Proxy PO, Architecte, Tech Lead, Développeur, Business Analyst, DevOps, QA Testeur, etc.
⏬ en étapes dans un flot de transformation des idées qui "descend" du stratégique conceptuel (idéation) vers l'implémentation, jusqu'à des interactions concrètes entre acteurs humains et/ou numériques.
Il existe un flot de retour d'information, qui remonte depuis les observations ou les analyses concrètes vers le conceptuel stratégique, mais proportionnellement le flot descendant est beaucoup plus large : nous passons beaucoup plus de temps à créer du logiciel neuf qu'à étudier du logiciel existant.
Pendant plusieurs décennies nous nous sommes concentrés sur la conception et la spécification. Les délais importaient peu, ce qui comptait c'était la conformité aux idées initiales, au plan, et la qualité des traductions descendantes. On disait "les études montrent qu'une erreur de conception coûte 1000 fois plus cher qu'une erreur de programmation."
Puis nous avons passé deux décennies à améliorer la construction, l'intégration continue et le déploiement continu. Le maître-mot d'aujourd'hui est la vitesse. La vitesse compte, car elle permet d'augmenter la fréquence des retours d'information, qui à leur tour permettent, en théorie, de faire moins d'erreurs de conception, ou plutôt de faire plus d'erreurs mais beaucoup moins conséquentes.
En théorie seulement, car nous ne sommes pas encore à l'ère du retour d'information. Le retour d'information se produit non pas quand la boucle est en place mais quand les acteurs utilisent effectivement l'information.
Nous ne livrons plus 1 an de projet, mais nous livrons l'un après l'autre, 26 incréments de 2 semaines.
⏫ La remontée d'information ?
- quelques logs
- une poignée de tickets d'incident
- Une heure de rétro par quinze jours de travail
Ces activités :
- relire
- déboguer
- tester
- documenter
sont inexistantes ou minoritaires, ne sont pas enseignées et sont menacées d'obsolescence. Les vérifications automatisées et l'IA vont bientôt remplacer tout ça.
Le feedback structuré, l'art de formuler et de recevoir des retours d'information, fait tâche : c'est une pratique insolite, un rien clivante, un truc de coach.
Nous ne savons pas lire dans la réalité d'aujourd'hui l'histoire de l'état de l'art du projet, son évolution depuis le cadrage, sa cristallisation dans le code.
Nous déclarons une dette imaginaire en euros, et puis nous l'effaçons. Elle était imaginaire.
Au lieu d'apprendre à maintenir l'existant, nous démarrons une refonte.
Nous n'apprenons pas, nous changeons de technologie.
🤔 Stay Tuned !
publié sur Linked In le 27/01/2023
Une Facture Imaginaire
Poncifs :
👉 Un projet de développement logiciel est une opération affreusement compliquée. Nous simplifions les choses parce qu'il faut bien passer à l'action.
👉 Le problème à résoudre n'a pas fini d'être posé, son exploration n'a peut être même pas commencé, que nous chiffrons déjà des "solutions".
👉 Les acteurs concernés : le Métier, la Technique et le Management ont des objectifs complémentaires mais distincts.
👉 Nos méthodes de développement (que nous appelons "méthodologies" pour leur donner un petit côté scientifique) ne garantissant nullement la cohérence et l'efficacité de l'équipe, nous tablons également sur le leadership, une compétence individuelle difficile à "objectiver".
👉 Notre culture agile est balbutiante et minoritaire : un projet qui s'arrête est toujours perçu, et parfois vécu, comme un échec.
Voilà autant de conditions propices à créer des frictions, voire des barrières de communication.
La dette technique se forme autour des barrières de communication. Elle se manifeste par l'effet résiduel sur le code de toutes les dérives apportées à notre état de l'art.
Impossible de parler de dette technique sans la rapporter à un état de l'art, lui même relatif à nos objectifs, nos contraintes et nos capacités. La DT n'est pas "dans le code".
Le script python non testé, non relu, non documenté qui aide Victor à gérer le contenu de son congélateur ne comporte pas de dette technique en soi. La même stratégie (0 test, 0 revue, 0 doc) apportée au code python de l'ERP que son employeur a choisi d'adapter ménerait à une calamité de dette technique.
Si on considère la DT comme une caractéristique du code, celle présente dans son fichier CONGELO.PY
n'est ni plus ni moins importante que celle présente dans les scripts qu'il écrit au travail. Or l'impact est négligeable dans un cas, incalculable dans l'autre.
La dette technique est l'aboutissement dans le code d'une série de dérives et de désalignements dans l'état de l'art d'une équipe, relativement à ses objectifs et ses contraintes. Avec une équipe Métier-Technique-Management parfaitement alignée dans son état de l'art, créer de la dette ou du code legacy est impossible, à moins que cela fasse partie du projet, comme une sorte de défi.
🤔 Vous allez réagir — ou du moins vous pourriez — en disant : "Comment ça l'état de l'art de l'équipe Métier-Technique-Management ? Il y a une équipe de développement, mais que je sache, on ne forme pas d'équipes Métier-Technique-Management"
Et vous auriez raison. On touche là une source majeure de création de dette technique : au lieu de nous organiser pour traduire ensemble des idées, nous déléguons ces traductions par le biais de rôles spécialisés. Après un temps de délégation plus ou moins long, la Technique additionne un montant en euro qu'elle communique à ses deux autres partenaires, comme une facture ou un devis imaginaire.
On doit pouvoir faire mieux que cela.
Stay tuned !
publié sur Linked In le 28/01/2023
Mission Failed ?
Janvier 2018 : un projet démarre, une équipe se met en place, on fait un cadrage, un chiffrage, on réalise, puis on fait évoluer une application.
Janvier 2023 :
🙂 l'application est en succès : elle contribue aux bénéfices de l'entreprise depuis bientôt 5 ans !
😉 elle a évolué avec les besoins propres au métier qu'elle sert, ainsi qu'avec l'infrastructure.
☹️ le code est difficile à modifier, parce qu'il est endetté : pas assez modulaire, il faudrait plus de tests auto, réunifier le vocabulaire, moderniser la conception… bref il faut réécrire l'application.
Mythe : la dette technique, c'est une érosion de la conception : le code "pourrit", est sujet à l'entropie. Si nous ne mettons pas d'énergie à préserver l'ordre dans le système, celui-ci se détériore. Les solutions d'hier deviennent les problèmes de demain.
Réalité : TOUT ce que l'entreprise met en œuvre, déploie et maintient est sujet à l'entropie.
Paradoxe : Dans le code de cette entreprise, la dette technique règne. Mais dans son activité, non. Elle ne perd pas les dossiers de ses clients. Dans ses armoires (numériques), tout est (numériquement) bien rangé, ou à peu près. Au bout de cinq ans de fonctionnement, les employés ne disent pas : désolé, le fonctionnement du service est sujet à la dette technique, il va falloir refondre.
Relisons l'histoire, cinq ans ce n'est pas si loin : ce code dont nous disons qu'il est endetté jusqu'au point où seule la refonte est possible, il est le fruit d'un cadrage initial, qui était le rendez-vous de 3 acteurs :
- le Métier, qui parlait résultats et délais
- la Technique, qui parlait conception, et faisabilité
- le Management, qui parlait coûts et pérennité
Entre ces trois acteurs, ça a bien fonctionné, et puis ça a progressivement cessé de fonctionner, dirait-on. Cette équipe là avait trois missions :
1️⃣ créer de la valeur (vite, si possible),
2️⃣ contrôler les coûts (gérer les ressources),
3️⃣ maintenir la maintenabilité.
Mais on dirait que la mission #3 a failli. Le code du projet est devenu comme un navire qui prendrait l'eau. Des consultants passent et prêchent : "un bateau ça se maintient… vous auriez dû réagir dès les premières voies d'eau", voire pour certains : "ça ne flottait pas au départ de toutes façons."
Où et quand la mission a-t'elle failli ? Est-ce que l'équipe Technique n'était pas assez Technique (c'est la thèse de la "dette technique") ? Est-ce que le Métier ne voyait pas assez loin ? Le management n'était pas à son poste ?
Les entreprises adaptent en permanence les technologies à leurs besoins, et vice-versa. Quand elles se sont informatisées (pour certaines, c'était il y a 50 ans), elles ont appris à manager un système d'information. Comment se fait-il que le développement, l'art de traduire en code un système de création de valeur, cette activité qui se loue comme un service depuis plus de 50 ans également, conduise toujours à ce mur qu'on appelle la dette technique ? Qu'est-ce que nous n'avons pas appris ?
publié sur Linked In le 29/01/2023
Cohérence
- Quel Problème Essayons Nous de Résoudre Ensemble ?
- À la Recherche de la Cohérence
- 3 Sources sur la Dette Technique
- Déspécialiser
- État de l'Art et Cohérence
- Outillage
- État de l'Art, Cohérence et Dette Technique
- Cohérence Perdue
- Métaphores
- Factory
- Conversations, Observations
Quel Problème Essayons Nous de Résoudre Ensemble ?
C'est ma question préférée. Elle peut être incisive, à en juger par les réactions qu'elle provoque parfois :
— on n'est pas en train de résoudre un problème spécifique, on fait [X,Y,Z]
— pas sûr qu'il y ait un unique problème…
— pas sûr qu'on soit en train de le résoudre ensemble…
— qu'est-ce tu entends exactement par "problème" ?
— où est-ce que tu veux en venir exactement ?
Lorsqu'une équipe se pose cette question, c'est comme si une nappe blanche était posée sur une grande table, et qu'ensuite chaque personne posait là des objets de toutes sortes, de toutes tailles, utiles ou inutiles, pratiques, encombrants, incongrus. Les objets forment des relations dans cet espace qui devient l'espace du problème, en quelque sorte.
On peut simuler cet espace facilement dans une salle de réunion ; il suffit de se donner comme consignes :
- j'écris une réponse à cette question sur une note
- je place cette note là où elle doit être
Lorsque l'équipe voit son activité comme la simple exécution d'une tâche, elle trouve un moyen d'être active, d'avancer dans une direction donnée.
Lorsque l'équipe voit son activité comme la résolution d'un problème, elle trouve des blocages intéressants. Elle a des difficultés à poser des tests de non-régression, à identifier des bugs, à prendre des décisions. Elle essaie de concilier un planning tendu avec une stratégie d'amélioration du code. Elle découvre qu'il faut négocier la quantité de refactoring du prochain sprint. Elle débat pour savoir si le ticket no 4807 est un bug ou une demande d'évolution. Elle est tentée, ou bien priée, d'aller plus vite, dans une direction à peine ébauchée.
Avec cette question :
quel problème essayons nous de résoudre ensemble ?
l'équipe peut explorer ses désaccords, et trouver au cours de cette exploration, de quoi améliorer son efficacité.
Définissons un problème comme la différence entre un état désiré et un état souhaité.
Ajoutons quelques informations clés :
- qui a le problème ? (qui perçoit ? qui désire ?)
- quels sont les objectifs ?
- quelles sont les contraintes ?
- quelles ressources pouvons-nous utiliser ?
- quels procédés s'appliquent ici ?
- quel est notre état de l'art ?
Lorsque je pose ces questions je peux m'attendre à découvrir une variété de positions en conflit concernant tout ou partie de ces caractéristiques.
Je n'ai pas rencontré d'équipe qui soit à la fois bloquée ET munie d'une réponse "alignée" et cohérente à ces questions.
C'est en quoi cette question :
quel problème essayons nous de résoudre ensemble ?
permet de localiser précisement la "dette technique" à sa source.
publié sur Linked In le 03/02/2023
À la Recherche de la Cohérence
Considérons une application qui a 5 ans d'existence. Elle forme dans l'entreprise un petit foyer d'activité autour duquel gravitent des acteurs Métier, Technique et Management occupés à traduire ensemble des idées vers la technologie, à négocier des fonctionnalités et à maintenir l'existant.
Après 5 ans le constat est doux-amer :
Ça marche : l'application crée de la valeur, et le travail a du sens.
Cependant
-
La valeur produite diminue. L'activité une fois "rationalisée" dans un modèle de type software factory subit la loi des rendements décroissants : il y a une limite à ce que l'ajout de "ressources" peut contribuer à réaliser.
-
Le système est "endetté techniquement" : l'état de l'art qui guidait sa conception a perdu en cohérence et s'est dégradé au gré des changements d'objectifs ou de contraintes.
-
L'équipe mise en place il y a cinq ans n'existe plus, non parce que ses premiers membres sont partis, mais parce qu'elle s'est métamorphosée progressivement en un groupe dont le focus est perdu et au sein duquel les conversations, ingrédient essentiel de la conception d'application, se sont raréfiées et codifiées.
-
Retenir et remplacer les acteurs Techniques devient plus difficile.
-
L'application évolue lentement mais sûrement vers l'état de legacy. Un legacy c'est un système que l'on maintient en vie, en dépit du fait que les conversations de conception nécessaires à la vie de ce système n'ont plus lieu.
Paradoxe : toute application, dans les conditions de maintenance et d'évolution courantes à l'heure actuelle, devient à plus ou moins long terme du legacy. Or les acteurs techniques, s'intéressent majoritairement non au legacy, mais à l'innovation.
Le marché de l'emploi et des services en développement de logiciel est un immense jeu de chaises musicales dans lequel les "nouvelles technologies" font office de chaise.
L'activité idéale de l'acteur Technique, c'est apprendre, transmettre, et "faire école". Comme le touitte Martin Fowler,
N'importe quel idiot peut écrire du code que l'ordinateur comprend. Les bons programmeurs écrivent du code que les humains peuvent comprendre.
Si l'on considère le marché de l'emploi et des services, les bons programmeurs sont plutôt ceux qui travaillent avec des technologies nouvelles : le salaire annuel moyen d'un développeur expérimenté en IA est de €67K, contre €50K en COBOL.
Considérée dans son ensemble, toute notre activité présente une dynamique en forme de tragédie industrielle :
- elle se nourrit de nouvelles technologies et d'innovation
- elle produit à grande échelle du code legacy
Mais contrairement à la tragédie, il n'y a ici aucune fatalité. Il n'y a aucune raison fondamentale pour qu'il en soit ainsi de toute application, dans toutes les entreprises. Et contrairement à la croyance en cours, cet état des choses ne dépend nullement de la technique seule.
Stayed Tuned !
publié sur Linked In le 05/02/2023
Trois Sources sur la Dette Technique
Sur les conseils de Stéphane Dalbera, je lis en ce moment Managing Technical Debt (cf ref en commentaire). Le livre foisonne d'exemples et de modèles, et propose de nombreuses heuristiques ainsi qu'un plan de recouvrement de la DT. Le chapitre 1 offre cette définition :
Dans des système à forte composante logicielle, la dette technique se caractérise par des conceptions ou des constructions qui sont des expédients à court terme, mais qui créent un contexte technique qui peut rendre des changements futurs plus coûteux ou impossibles. La dette technique est un passif contingent dont l'impact se limite aux qualité internes du système, notamment et en premier lieu mais pas seulement : la maintenabilité et l'évolutivité.
Ainsi qu'une analogie :
On peut penser la dette technique comme une analogie avec la friction dans les appareils mécaniques; plus un appareil subit la friction dûe à l'usure, le manque de lubrification, ou une conception défectueuse, plus l'appareil est difficile à utiliser, et plus il faut appliquer d'énergie pour obtenir l'effet original. En même temps, la friction est une condition nécessaire lorsque des parties mécaniques fonctionnent ensemble. Vous ne pouvez pas l'éliminer complètement; vous pouvez seulement la réduire.
Analogie qui m'a ramené à The Art of Action que Laurent m'avait conseillé, lequel reprend la notion de friction définie par Clausewitz et l'applique au management :
Aucun ingénieur ne rêverait de concevoir un moteur sans prendre en compte les effets de la friction mécanique. Si Clausewitz a raison, personne ne devrait développer une stratégie sans prendre en compte les effets de la friction organisationnelle. Et pourtant nous continuons à être surpris et frustrés lorsque celle-ci se manifeste. Nous avons à tendance à penser que tout a mal tourné alors qu'en fait tout s'est passé normalement. L'existence de la friction est la raison pour laquelle les armées ont besoin d'officiers et les entreprises de managers. Anticiper et traiter avec la friction constitue l'essence du travail managérial. Le reconnaître est en soi libérateur.
Il y a quelques temps, la lecture de Discussion of the Method de Billy Koen a fortement contribué à changer ma conception de la dette technique. Koen définit l'ingénierie comme l'application de procédés heuristiques (heuristics) en vue de produire un changement.
Heuristique ?
Un prodédé heuristique (heuristic) est tout ce qui fournit une aide plausible dans la direction de la solution d'un problème, mais qui en dernière analyse n'est pas justifié, n'est pas justifiable, et demeure potentiellement faillible.
Un ingénieur, une équipe ou une organisation mettent en œuvre des solutions qui sont définies par leur état de l'art, c'est à dire l'ensemble des heuristiques spécifiques utilisées à un moment donnée afin de produire le meilleur changement dans une situation mal comprise, à l'aide de ressource limitées.
So what ? Qu'est-ce que ça change ? Quel est le rapport ? Stay Tuned !
publié sur Linked In le 07/02/2023
-
The Art of Action: How Leaders Close the Gaps between Plans, Actions and Results,Stephen Bungay
-
Discussion of the Method: Conducting the Engineer's Approach to Problem Solving,Billy Vaughn Koen
Déspécialiser
Mon prof de Français avait conclu notre dernier cours de 1ère avec un conseil d'apparence anodine : méfiez vous de la spécialisation. Je m'étais promis d'essayer de m'en souvenir à l'époque, mais en toute honnêteté je n'avais pas idée de ce qui m'attendais dans le monde du travail.
La dette technique, ça m'intéresse depuis longtemps parce que c'est la difficulté principale que rencontrent des équipes qui veulent résoudre des problèmes ensemble en s'aidant de la technologie. Une difficulté persistante, inhérente, et d'autant plus coriace qu'elle se présente d'abord sous les traits du pragmatisme, comme une alliée de l'agilité. Il y a la bonne dette et la mauvaise dette.
En 2014 mes collègues et moi avons commencé à distinguer DT "tactique" et DT "endémique". Ce n'était pas satisfaisant. S'il faut 4 mots et une distinction pour identifier un problème aussi général, c'est que notre langage est peut être trop technique, justement. La conséquence d'un langage trop technique, c'est qu'il "en impose", tout en masquant des barrières de communication.
Comme les Anglais et les Américains qui se considèrent comme deux peuples que sépare une langue commune, le Métier, le Management et la Technique partagent des termes sur lesquels ils projettent des significations différentes.
Pour le Métier, il s'agit d'un problème relativement opaque lié au coût du changement.
Pour le Management, c'est un problème de report de décisions : l'éternel combat entre le court terme et le long terme.
Pour la Technique, c'est du code qui sent mauvais et un design dépassé.
Au final, j'avais décidé de bannir le terme de mon usage personnel. La dette technique, ce n'est pas de la dette, et ce n'est pas technique.
Ça peut se comparer à de la dette, parce que cela s'accumule, et finit par grever nos budgets.
Ça parle de technique, parce que cela concerne la résolution de problèmes au moyen de technologies.
Le contraire de la DT, c'est quoi ? Je cherche une définition non seulement positive mais fédératrice, qui aide à améliorer l'art de résoudre des problèmes ensemble à l'aide de la technologie.
Il est à mon sens impossible de s'intéresser à cet art sans porter son attention sur les notions d'Etat de l'Art (State Of The Art ou SOTA) et d'heuristiques analysées par Bill Koen.
La dette technique est une conséquence du réalignement permanent de notre état de l'art :
- nous initialisons un projet, et définissons son état de l'art en regard de nos objectifs et contraintes
- au cours du temps nous adaptons l'état de l'art, changeons les objectifs, déplaçons les contraintes
- lorsque (et tant que) cette adaptation fonctionne, nous produisons de l'excellence
- lorsque notre état de l'art se désaligne, nous produisons de la DT.
Stay Tuned !
posté sur Linked In le 8/02/2023
État de l'Art et Cohérence
Dans mon post précédent, je propose une nouvelle définition :
La dette technique, c'est un état de l'art qui se désaligne.
C'est à dire ?
Voici un exemple
Vers la fin des années 80 une application est née qui rassemble trois acteurs :
- Métier : une enseigne commerciale
- Management : une société de service spécialisée dans les réseaux à valeur ajoutée
- Technique : des développeurs spécialistes de ce type de systèmes
Elle a pour vocation la vente de produits sur le réseau Minitel
L'état de l'art :
- un serveur videotex PC servant les pages accessibles aux usagers
- une liaison PC / Unix
- une machine unix accueillant l'application spécifique de gestion de la vente
- l'application, écrite en C, utilisant une librairie de gestion de fichiers en accés séquentiel indexé (ISAM)
- gestion des sources, tests et déploiement par procédures manuelles
Juin 94 : l'application est un succès, à la fois pour le client et la SSII. Depuis déjà plusieurs comités mensuels, l'équipe technique attire l'attention du groupe sur une action de maintenance évolutive importante qu'elle a analysée et chiffrée : remplacer la librairie ISAM par un SGBDR afin de rationaliser la gestion des données.
Le débat est animé :
Pour le Métier, cette évolution coûte trop cher et ne présente pas de valeur ajoutée. Pour ce qu'il en perçoit la gestion des données de l'application est satisfaisante.
Pour le Management, la gestion des données pose un problème de sécurité et de fiabilité. Elle est prise en charge par les développeurs, via un mode opératoire fragile et sujet à erreur :
- export des fichiers ISAM concernés vers des fichiers "plats"
- création/modification/suppression à l'aide d'un éditeur de texte
- import à nouveau des fichiers texte vers les fichiers ISAM
Pour l'acteur Technique, le projet a une technologie de retard. Il stagne, alors que le fournisseur de la librairie qu'ils utilisent distribue commercialement depuis déjà 5 ans un SGBDR complet. Cela les pousse à rechercher des missions dans lesquelles ils pourront à la fois disposer d'outils plus efficaces et étendre leur compétence en SQL, un langage d'avenir.
Pour le Management, ces départs potentiels ajoutent à l'insécurité de la solution actuelle.
Pour le Métier, il y a là une sorte de chantage à la technologie.
Comme on le voit, la dette technique nous parle "technique" et nous invite à penser en termes financiers, mais le creuset où elle se forme n'est pas seulement technique ou financier, loin de là. Tout l'enjeu réside dans la réponse à ces questions :
Quel problème voulons nous résoudre ensemble ?
Quels sont nos objectifs et nos contraintes ?
Comment doit évoluer notre état de l'art ?
La difficulté, la complexité même de l'entreprise, ce n'est pas tant de faire marcher la technologie, ou bien d'aller plus vite : c'est de préserver la cohérence de l'état de l'art qui guide la résolution du problème.
Stay Tuned !
publié sur Linked In le 09/02/2023
Outillage
Notre difficulté principale, ce n'est pas de mettre en œuvre une application basée sur la technologie, c'est plutôt de maintenir la cohérence de l'état de l'art qui guide son évolution.
La technologie change constamment, et nous nous employons à la faire marcher. Nous y consacrons pas mal de temps, d'argent, d'énergie et de motivation, souvent trop, mais on s'en sort. Nous adorons, au sens religieux du terme, les nouvelles technologies. Or celles-ci s'empilent, mais ne s'emboîtent pas.
Toute équipe qui réalise du logiciel doit faire évoluer simultanément a) le produit b) la conception et c) son état de l'art.
Au siècle dernier ces évolutions étaient plutôt lentes (comparativement) du fait que les outils étaient moins puissants, moins accessibles, et moins bon marché. Nous ne sommes pas devenus de meilleurs ingénieurs : nous avons plus facilement accès à plus d'outils plus puissants.
Nous vivons donc dans une abondance technologique quasi-miraculeuse. Les outils, les langages, les modèles, les frameworks, les "solutions" se multiplient. Au sein de cette abondance, comme en présence de tout phénomène d'agrégation, l'entropie gouverne : il est plus simple de laisser l'accumulation se produire que de la réguler.
Voici quelques tâches incombant à l'équipe, classées par ordre croissant d'énergie requise en vue de préserver la cohérence :
🙂 copier/coller un bout de code
🤨 factoriser le code
😛 commenter du code devenu inutile (on ne sait jamais)
😅 supprimer le code
😎 travailler en solo
😒 aborder le code en revue ou en binôme
🤗 ajouter des fonctionnalités
😬 faire patienter une direction métier
🤓 faire confiance au leader
🤔 douter ensemble de notre solution
Pour s'organiser, pour améliorer en continu notre produit, notre conception et notre état de l'art, il faut se parler. Cela représente un travail considérable, souvent inconfortable.
Actes de naissance d'une dette technique :
🖋 On est en retard parce qu'on a sous estimé la complexité de la story; par conséquent je propose qu'on saute la revue et qu'on fasse moins de tests.
🖋 Le CV de Victor mentionne TDD, mais il avoue que dans "son TDD", le cycle Test/Code/Refactor est tout à fait optionnel. De plus il trouve qu'on est un peu des "puristes du TDD".
🖋 L'équipe passe la moitié du planning game à discuter d'une implémentation. Lorsque le PO s'impatiente on lui dit : tu veux une estimation oui ou non ?
🖋 Il est décidé qu'on produira des APIs. Qui les documentera, qui aidera les projets client à tester : cela reste à déterminer.
Non seulement nous ne sommes pas très versés dans ces conversations, mais nous sommes réticents à les tenir.
🖋 Je hais les réunions !
🖋 Fais plutôt un ticket
🖋 Mes remarques en bleu dans le mail
Nous avons tellement le sens des outils, et si peu celui des échanges, que d'après nos pronostics, le babil d'une intelligence mécanique colossale pourra bientôt nous dispenser d'employer des développeurs !
Stay Tuned !
publié sur Linked In le 10/02/2023
État de l'Art, Cohérence et Dette Technique
L'état de l'art d'un projet perd inéluctablement de sa cohérence au cours du temps, car celle-ci est fortement liée au contexte.
L'application de vente en ligne mentionnée précédemment en est un exemple. Un projet aux objectifs relativement modestes, dans un contexte incertain, met en œuvre une gestion de données simple basée sur la technologie ISAM. 5 ans plus tard, l'application est en succès; ses fonctionnalités évoluent, ainsi que son modèle de données. Il est plus que temps de remplacer cette technologie par un SGBDR, lequel offrirait :
- de meilleures abstractions pour traduire le domaine métier vers le modèle relationnel
- un langage de consultation et de mise à jour puissant et robuste : SQL
- des contraintes d'intégrité fonctionnelle gérées en quelques déclarations (plutôt qu'en dizaines de pages de code)
- des performances d'accès similaires à celles du séquentiel indexé
Ce changement, évident pour les acteurs Techniques, représente un coût inacceptable pour le Métier. Quand au Management, il est devant un choix :
- imposer au Métier de revoir ses objectifs à la baisse
- négocier la transition vers le SGBDR, en présentant au Métier les avantages à en retirer
- temporiser, c'est à dire attendre de voir si ce désalignement pourrait se dissiper de lui-même
Avec l'option 3, l'organisation crée de la dette sans rien faire : celle-ci augmente naturellement avec le nombre de fonctionnalités et de données nouvelles créées pendant que la technologie reste inchangée.
Quelques fois le temps n'y est pour rien : l'état de l'art initial d'un projet peut être incohérent dès le départ. C'est le cas lorsqu'une équipe se donne pour objectif de coder et de mettre en production un design complexe sans l'aide d'aucun procédé de prévention des défauts tels que la relecture de code, ou les tests automatisés, et décide de s'appuyer seulement sur un procédé de type essai / erreur, lequel convient assez bien pour des projets simples.
Une équipe qui, interrogée sur son processus, met en avant des dispositions aussi douteuses que "on fait super attention", ou "notre tech lead est un génie du code", possède un état de l'art probablement inadapté au challenge qu'elle se propose de relever. Là encore, le désalignement appelle le désalignement, et la dégradation s'accélère :
- l'état de l'art n'étant pas adapté, les résultats s'en ressentent : écarts de budget et retards
- comme on n'a plus le temps de "bien faire", on dégrade encore un peu l'état de l'art
- etc.
comme cette équipe qui, constatant que ses tests de non-régression allaient bientôt prendre plus de temps que la durée d'un sprint, décida de faire moins de tests de non-regression à chaque incrément de fonctionnalités livrées.
La "dette" n'est pas un phénomène émergeant du code, comme une sorte de brouillard technique : elle n'est que le reflet des changements de contexte et des décisions prises sur l'état de l'art.
Stay Tuned !
publié sur Linked In le 11/02/2023
Cohérence Perdue
Le projet de développement sur lequel vous travaillez actuellement produit subrepticement ou ouvertement ce que tout le monde convient d'appeler de la "dette technique".
Comment est-ce que je le sais ? Toutes les personnes de ma connaissance qui travaillent dans le développement me parlent de la DT. Tous les projets que j'ai pu approcher, accoster ou prendre en charge dans ma carrière comportaient de la DT.
Ces 20 dernières années, nous avons peaufiné la définition de ce qui se situe à l'ARRIVÉE de la dette technique : une liste de préconisations de corrections à effectuer sur le code, surmontée d'une (grosse) somme en euros.
Nous avons encore beaucoup de mal à décrire ce qui se situe à la SOURCE de la dette technique : un état de l'art qui a perdu peu à peu (ou parfois brutalement) de sa cohérence.
Un ancien collègue me pose cette question :
— Qu'est-ce que tu veux dire par état de l'art ? Dans mon projet, j'ai des user stories, un document d'architecture, quelques diagrammes, je n'ai aucun document qui décrirait notre état de l'art. Ça n'existe pas.
— Est-ce que vous relisez le code ensemble avant de le déployer ?
— Non. On a des pull requests sur le repo directement. Et on ne lit pas ensemble, c'est de la revue asynchrone.
— Vous avez donc un état de l'art.
— Peut être, mais en tout cas on n'a rien d'écrit sur le sujet.
— Ça n'empêche. Est-ce que vous indentez votre code ?
— Bien sûr. En fait, on n'en a jamais parlé.
— C'est inutile : indenter son code fait partie de l'état de l'art quasi-universel des développeurs.
L'état de l'art est l'ensemble des procédés qu'utilisent une personne, une équipe, ou une entreprise, en vue de résoudre un problème imparfaitement défini, dans un contexte incertain. C'est un guide de navigation, qui n'a rien d'absolu. Il n'existe certainement pas un État de l'Art unique, étant donné le nombre de contextes différents dans lesquels on conçoit du logiciel.
Le travail d'une équipe porte simultanément sur le produit qu'elle réalise, sa conception et sur l'état de l'art qui guide cette conception. Au siècle dernier, beaucoup d'entreprises définissaient l'état de l'art des projets une fois pour toutes, avec une faible tolérance pour les initiatives. Aujourd'hui l'entreprise favorise plus volontiers une évolution rapide de l'état de l'art, au risque de perdre en cohérence ce qu'elle a gagné en vitesse d'adaptation.
À moins de travailler tout seul sur un produit très simple, la conception suppose une conversation régulière entre les acteurs à propos de l'état de l'art qui les guide. C'est une exigence à la fois triviale et cruciale, difficile à remplir dans une organisation en silos ou en "factory".
Lorsque les conversations manquent la dette s'installe.
Imaginez un orchestre de chambre, qui ne se donne plus le la, qui n'est plus en rythme, ne lit plus la même partition, et qui continue à jouer, vaille que vaille.
Quelqu'un dit :
— on reprend ?
— Non, on continue !
publié sur Linked In le 14/02/2023
Métaphores
La dette technique est une métaphore utile, mais ce n'est pas un indicateur. Elle indique vaguement qu'un certain nombre d'évènements qualitatifs sont survenus sur le projet. On ne peut pas réellement compter ce qu'on a accumulé ou retiré de ce sac là.
Imaginez que dans notre équipe, depuis toujours on aime employer l'expression "c'est tiré par les cheveux" (comme cet exemple). On emploie aussi sa forme latinisée : c'est capillotracté ! Un jour, l'équipe, dans un moment de pataphysique, en fait un indicateur : …en considérant un nombre de cheveux, une certaine extensibilité du cheveu, son élasticité, la charge appliquée et la distance… 🤔
La Dette Technique est une grandeur métaphorique qui indique du non-quantifiable. "Volume" est aussi une grandeur métaphorique, mais cette fois-ci appliquée à une autre grandeur très réelle : le nombre total d'octets représentant des informations à conserver pour nos besoins applicatifs.
Comme pseudo-indicateur, la DT est une sorte d'appel à l'action, mais qui reste vague, parce que c'est un faux agrégat. Par comparaison, "volume des données gérées" est un réel agrégat, dont l'évolution déclenche des décisions possibles :
< 10 Go : notre solution de stockage est surdimensionnée → on pourrait faire des économies
> 4 To : on va bientôt manquer d'espace → il faut investir
Au delà de quel seuil la dette technique entraîne t'elle une décision dans votre projet ? Comment avez-vous déterminé ce seuil ?
Qu'est-ce que nous voulons dire, lorsque nous disons "cette solution comporte une dette technique considérable" ?
Que le temps a passé, et que notre état de l'art a perdu de sa cohérence. C'est à dire ?
- une contrainte a changé, qui rend certains de nos procédés caducs, inopérants
- ou bien un objectif a changé, qui rend certains de nos procédés insuffisants ou au contraire superflus
- ou bien certains procédés n'ont plus cours, alors que nos objectifs et nos contraintes n'ont pas changé
- ou bien certains procédés sont en contradiction avec d'autres
- ou bien un peu de tout cela à la fois.
Un projet et son état de l'art sont des affaire incertaines. Avec la pression, la tentation est forte pour tous les acteurs de changer l'état de l'art afin de gagner du temps.
Exemple d'un état de l'art en évolution :
➡️ On utilise [User Story].
🔀 Plot twist : au lieu d'avoir les conversations autour d'un écran, on s'envoie les US par écrit, comme une [Spécification], mais sans les détails (bref, un titre).
🔀 Puisqu'avec notre [Backlog de US] on peut piloter et tracer l'activité de l'équipe, on y mettra aussi les [Tâches Techniques] sous-jacentes à la réalisation. Des [User Story Techniques] en quelque sorte.
🔀 On avait initialement [Refactoring en continu] mais on a négligé cette pratique, et maintenant on doit poser des [Story de Refactoring] sur le backlog.
la dette technique fait une sorte de bilan de cette évolution.
Stay Tuned !
publié sur Linked In le 15/02/2023
Factory
Il y a 25 ans, j'ai travaillé pour un temps dans une société qui réalisait des développements au forfait. Cette société comprenait une Direction de la Qualité, laquelle avait mis en place une méthodologie de développement dont l'essentiel tenait à peu près dans 5 gros classeurs. L'un d'eux contenait la prescription suivante :
En C, l'ordre d'évaluation des paramètres d'une fonction
n'est pas garanti par l'éditeur du compilateur,
et n'est donc pas portable d'un sytème à l'autre.
Par conséquent les expressions logiques telles que :
if ( exprA && exprB && exprC ) {
sont interdites et doivent être remplacées par des IFs imbriqués :
if (exprA) {
if (exprB) {
if (exprC) {
Ça m'a laissé perplexe. Sur le moment je me suis posé plusieurs questions :
- d'où vient cette règle de programmation erronée ? (son auteur semble confondre l'ordre d'évaluation des paramètres à l'appel d'une fonction, et l'ordre d'évaluation d'une expression logique en court-circuit, qui se fait par définition de la gauche vers la droite.)
- est-ce que l'auteur de ce guide à lu au moins un document de référence sur le C ?
- est-ce que les documents auquels je me réfère sont dans le faux, et l'auteur de la prescription dans le vrai ?
- est-ce que son équipe est tombée sur un compilateur C buggué sur une machine particulière ?
- combien de projets existants ont été affectés par cette règle ?
- que se passe t'il si j'intègre un projet de développement en C ?
- que se passe t'il si je décide de me conformer à cette règle dans mon code ?
- est-ce que je ne devrais pas plutôt suggérer un amendement au classeur no 3 "Méthodologie des développements en C" ?
- comment va se passer cet amendement ?
- de quoi la direction de la qualité va avoir l'air si ça se sait ?
- de quoi est-ce que j'aurai l'air ?
- est-ce que j'ai choisi la bonne entreprise et combien de temps vais-je y travailler ?
Aujourd'hui je me pose de nouvelles questions :
- Si chaque projet contient des instances de dette technique, est-ce que cette page de la méthodo ne constituait pas en elle-même une factory de dette technique ?
- On pense la DT comme un passif qui concerne la qualité interne d'un logiciel, mais dans ce cas précis, n'est-ce pas plutôt un passif lié au processus de l'entreprise ?
- Dans cette situation, la Direction de la Qualité disposait d'un certain effet de levier. Comment aurait-elle pu remédier à la dette ainsi générée ? La prévenir ?
- C'était il y a 25 ans. Qu'est-ce qui a remplacé les classeurs méthodologiques dans les entreprises aujourd'hui ?
- Est-ce qu'il revient à chaque équipe projet de rétablir tant bien que mal la cohérence de l'état de l'art de l'entreprise ?
- Quelles marges de manœuvres permettraient de préserver un état de l'art non pas figé, mais cohérent en regard des objectifs et des contraintes changeantes de l'entreprise ?
Stay Tuned !
publié sur Linked In le 16/02/2023
Conversations, Observations
La scène se passe au restaurant de l'entreprise où je suis en mission. La conversation avec mes coéquipiers porte sur le prix du mètre carré, et sur l'épargne. Je m'apprête à donner mon opinion, mais je me rappelle que je viens juste de contracter un prêt afin de combler un découvert, et je me ravise.
Finalement, j'avoue :
— Oh moi, je n'arrive pas à économiser. Je sais que je pourrais, mais c'est plus fort que moi.
Dominique, contrôleur de gestion de son état, et notre maître d'ouvrage, répond :
— ça peut être assez facile, quand tu as un plan.
— des plans j'en ai fait, mais on dirait qu'ils échouent l'un après l'autre.
— hmm.
Avec l'immaturité qui me caractérisait vers 1989, je lance :
— en fait je serais même prêt à payer quelqu'un qui m'aiderait à économiser !
— pffft, inutile, c'est plus simple que ça.
— pour toi, peut être…
— il suffit d'observer ce que tu fais.
— là en m'observant, tu vois comment je pourrais faire des économies ?
— oui.
— tu vois quoi exactement ?
— je regarde ton plateau : tu as choisi le dessert plus cher.
Si la métaphore de la dette est si répandue, c'est peut être parce qu'elle nous parle de toutes ces situations inconfortables dans lesquelles nous avons conscience de ce qu'il faudrait faire tout en décidant de ne pas le faire.
Pour économiser et dépenser moins, il m'a fallu m'observer, me discipliner, me priver, remettre à plus tard des gratifications, et croire en ma stratégie sur le long terme.
Peut-on rapprocher endettement personnel et dette technique ? Oui et non.
Non, car ici il n'est pas question de discipline personnelle, de privation, ni de gratification.
Oui, car il s'agit bien de cohérence, d'observation, et de stratégie.
Activée de manière cohérente c'est à dire provisoirement, la dette technique est un levier tactique qui permet d'acheter du temps. Mais toute personne ayant travaillé à la maintenance d'un logiciel sait bien que dans l'entreprise on aime le provisoire qui dure.
Or nous n'arrivons pas le matin au travail en proposant : "Vous savez quoi ? Aujourd'hui nous allons augmenter la DT de 25%. Ça va améliorer nos résultats."
Le sujet n'est pas la dette technique mais notre état de l'art. Ce guide imparfait et incertain est toujours ouvert aux améliorations. Il est donc, par nature, en discussion continuelle. La pression et les tentations pour le modifier sont constantes.
Chaque conversation sur l'état de l'art pourrait commencer par une hypothèse : Si ça se trouve…
‥on pourrait se passer de revues de code…
‥ce Proof of Concept peut tourner en production…
‥le Métier va ajouter du budget supplémentaire d'ici Juin…
‥on aura réellement besoin de ce socle technique par la suite…
‥tu pourrais coder la story sans les TU et elle marcherait aussi bien…
‥on a le meilleur modèle possible, et le peaufiner encore serait une perte de temps…
‥vous pouvez vous auto-former à TDD (J., qui devait vous former, a quitté l'entreprise)…
Stay Tuned !
publié sur Linked In le 17/02/2023
Sortir Des Ronces
- Contre-Effet de Levier
- Qualité, Coûts, Délais
- Sortir des Ronces
- Prérequis
- Pro Tips
- Construction de Théorie
- Lit de Procuste
- Boule de Cristal
- Crise de Croissance
- Sens Partagé
Contre-Effet de Levier
Bienvenue Mauko Quiroga Alvarado dans cette conversation ! Merci pour cette réflexion :
Pour moi la dette technique c'est une CAPEX, c'est un choix volontaire et rationnel avec un engagement de remboursement. Soit tu la paies, soit c'est un/e autre qui le fait. L'exemple classique du client à forfait qui ne veut pas de tests : il paie moins cher en échange de dette technique. Si on sait bien ce qu'on fait (presque jamais), cela peut être même un choix justifié.
et ces questions :
A quoi fais-tu référence par dette technique ?
Je fais référence à la métaphore inventée par W. Cunningham, qui signifie dégrader la conception temporairement afin d'atteindre un objectif intermédiaire. Dans le cas mentionné dans mon post comme une "factory" de dette :
remplacer les expressions logiques en court-circuit par des ifs imbriqués
la direction Qualité dégrade localement l'état de l'art [Programmation en C] dans ses standards en vue (croit-elle) de prévenir des situations de comportement non spécifié.
Qu'est-ce que la Direction de la Qualité achetait en échange de cette dette?
Elle achète, mais sur la base d'un diagnostic erroné, de la prévention de défauts.
Quel aurait-pu être le choix ?
Il est possible que la DQ ait considéré un maintien de la restriction tant que l'état de l'art des compilateurs C ne serait pas "amélioré" par les éditeurs. J'ai souvent attendu que le monde remédie à des problèmes qui existaient seulement dans mon jugement, aussi je ne leur jetterai pas la pierre.
En général, une équipe, un service, ou une organisation qui pose une limite sur les constructions disponibles dans un langage ou une technologie donnée, comme par ex :
- les appels de fonction récursifs sont interdit
- les vues SQL sont interdites
- la programmation orientée objet est interdite
crée une dette technique en échange d'une simplification de ses objectifs.
Elle dégrade un état de l'art : par exemple elle proclame (ou plutôt écrit) :
- goto est interdit
afin d'éviter à l'entreprise des situations dans lesquelles une conception reposant sur des gotos manque de clarté ou de fiabilité.
Comme aime à le rappeler Laurent Bossavit, abusus non tollit usum (nous n'avons pas proscrit l'usage du latin dans notre état de l'art chez CodeWorks, mais nous pourrions considérer de le faire :-). L'abus n'empêche pas l'usage. Mais une direction de la Qualité a besoin de régulateurs. Son objectif est d'institutionnaliser autant que possible les états de l'art ayant cours dans l'entreprise, afin de pallier à deux problèmes massifs en informatique :
-
la volatilité des technologies
-
le déséquilibre entre la demande en personnes compétentes en technologie comme en savoir-faire et les capacités de notre système d'enseignement supérieur.
L'ironie rattrappe la DQ quand son propre état de l'art, lequel inclut la veille technologique, est lui-même dégradé. L'effet de levier se retourne alors contre l'entreprise.
Stay Tuned !
Qualité, Coûts, Délais
Je viens de lire avec beaucoup d'intérêt le post d'Anthony Cyrille qui commence par cette malicieuse accroche :
"Mon développeur est très compétent, il a développé tout le projet en une semaine."
👀
Qualité, Coûts, Délais…
tout le monde a fait (ou devrait avoir fait) l'expérience au moins une fois de
○●● livrer rapidement une appli qui ne marche pas
●○● faire de la surqualité (je traduis : lorsque vous livrez rapidement du code fiable et maintenable, quelqu'un va vous dire: "c'est bien mais attention à la surqualité". Surqualité = c'est trop cher).
●●○ livrer enfin le bon produit, et du code maintenable, mais avec des mois de retard.
Quand j'étais jeune, il y a longtemps, dès que ça parlait budget ou délai, quelqu'un sortait le triangle de fer :
🔺 GOOD, FAST, CHEAP: PICK TWO 🔻
Et à l'époque, je me disais : c'est sagesse !
Mais depuis, j'ai eu quelques occasions de rencontrer et de contribuer moi-même à des projets dans lesquels on croyait dur comme fer à l'hypothèse de Crosby :
Quality is free. It's not a gift, but it's free. The 'unquality' things are what cost money.
et je me rappelle aussi Brian Foote (coautheur de l'excellent papier Big Ball of Mud) :
Si vous trouvez qu'une bonne architecture coûte cher, essayez une mauvaise.
Clairement ces deux propositions nous invitent à démonter le triangle de fer, plier en deux chacun de ses côtés, et le jeter dans la première benne disponible.
Nous revoilà avec d'un côté la Dette Technique :
- Dette Technique : procédé consistant à dégrader votre conception temporairement afin de satisfaire un objectif intermédiaire
qui nous permettra, utilisé sciemment, de faire moins bien mais plus vite → 🔻 Iron Triangle FTW! 🔺
et de l'autre côté la dette technique :
- dette technique : terme utilisé pour caractériser la qualité interne d'une solution dont l'état de l'art (procédés, objectifs, contraintes) n'est plus cohérent
qui comme on le sait bien peut entraîner une équipe, voire une entreprise, dans la spirale infernale de la non-qualité :
😡 les problèmes de qualité mettent le projet en retard et les clients en colère
↓
🤷 on est en retard ⇒ on sacrifie les activités superflues (tests, documentation, revues)
↓
💣 moins de prévention des défauts ⇒ plus de défauts; c'est mécanique, personne n'y échappe à moins d'être un∙e Ninja du Code (well are you, punk ?)
↓
🔁 rinse & repeat…
On a tous connu une équipe qui dégradait en continu son état de l'art et obtenait en contrepartie 0 résultat : seulement des bugs, du code inhabitable, et des délais explosés.
L'envers de la dette technique, c'est l'excellence : adapter continuellement son état de l'art afin de résoudre au mieux, dans les meilleurs délais, un problème complexe dans un contexte incertain.
Vous savez, quand vous vous dites : on pourrait faire moins bien, mais ça reviendrait plus cher…
Stay Tuned !
Sortir des Ronces
Le temps a passé. La conception de notre application a perdu en élégance et en cohérence. Certaines parties du système sont sanctuarisées : on n'ose plus y toucher. On cherche des développeurs·ses expérimenté·es, si possible des expert·es de cette technologie qui était tellement hype il y a cinq ans. Mais sur le marché de l'emploi et du service, tout le monde est passé à autre chose. La solution est devenue un problème.
Le "cœur métier" de l'application, qui est une des clés de son succès, fait l'objet de toutes les discussions dans l'équipe et au delà. Les avis sont partagés :
— il faut le rétro-analyser et y poser des tests automatisés
— les tests ça aurait dû être fait dès le départ, maintenant c'est trop tard, autant refondre
— il faut refondre l'application mais garder ce module
— il n'y a pas assez de sous; il faut refondre ce module, et garder tout le reste
— il faudrait surtout un deuxième Arnaud ! Depuis qu'il est parti plus rien ne marche
— il faut confier tout ça à une société extérieure, ce n'est pas notre métier
— …
Nos trois acteurs apprécient la situation chacun à leur manière.
Le Métier : "Tout ça est devenu trop cher. La moindre évolution prend des semaines à livrer, alors que le nombre de clients augmente et que le produit doit s'enrichir en nouvelles fonctionnalités."
La Technique : "Ce projet c'est déjà de l'histoire ancienne. La techno n'a pas évolué depuis 5 ans, et on ne nous donne pas de moyens. Et les meilleurs partent toujours les premiers si tu vois ce que je veux dire…"
Le Management : "C'est la quadrature du cercle. J'ai accepté de reprendre le truc il y a seulement deux ans, mais franchement on est sur une longue suite de promesses impossibles à tenir, depuis le début."
Le Métier faisant pression, l'entreprise a commandé un audit. La conclusion des consultants rejoint, en le détaillant et en l'étayant, le point de vue de l'équipe de développement : l'application est sujette à la dette technique. En Consultanais, ça donne :
"Le système présente un passif technologique et méthodologique accumulé qui a pour conséquence une stagnation du backlog, un taux de défaut en augmentation au lieu d'être constant, ainsi qu'une démobilisation des ressources."
Traduction : nous sommes dans les ronces.
Ça pique.
C'est compliqué.
Ça nous barre le chemin.
Silence dans la salle du Conseil. C'est le moment où un deus ex machina va nous présenter un outil miraculeux, ou bien poser une grosse somme d'argent sur la table ?
Ou bien (cf Anthony Cyrille) c'est le moment où un dév qui vient de faire une suggestion frappée au coin du bon sens (technique) se fait défenestrer ?
Ou bien (cf l'excellent article de Jérémy 🧑🏽Buget à propos d'un désendettement-déminage de haut vol) quelqu'un va dire :
"- Courage, méthodologie, rigueur et patience."
Vous me direz que c'est bien vague, c'est pas très technique, pourtant c'est exactement ce qu'il nous faut. C'est le plan. C'est le programme.
Stay Tuned !
Prérequis
Dans mon post précédent je mentionnais l'article captivant de Jérémy 🧑🏽🦱 Buget qui relate une action de fusion de versions particulièrement intéressante, et je notais un des points importants qu'il retient de cette expérience et qui ont fonctionné :
- Courage, méthodologie, rigueur et patience.
Pour ce qui est du courage, on le trouve en abondance dans les entreprises, et pas seulement celles qui s'occupent des problèmes de qualité à temps.
Pour les 3 autres dispositions, elles me paraissent très importantes car elles peuvent nous servir de boussole pour se sortir des ronces.
Quelles ronces ? La dette technique, of course.
Non pas la Dette Technique comme dans "j'ai une idée : on n'a qu'à persister vers du json le temps de la démo et lundi on se remet au travail sur l'ORM cible".
Non je parle de la dette technique comme dans "euh... la dernière personne qui a touché à ce code est partie fin 2018… et je ne vois pas de tests."
"dette technique" signifie : l'état de l'art de votre projet est désaligné. Des changements de contexte, d'objectifs, ou bien de vos pratiques font qu'il a perdu en cohérence. C'est inéluctable, dans toute activité de développement logiciel. La question est de savoir comment limiter et réguler cette dette avant qu'elle ne prenne les commandes du projet.
Pour identifier, réguler et limiter la dette, il faut de la méthodologie, de la rigueur et de la patience.
On peut le formuler autrement : afin de limiter la dette, votre état de l'art doit présenter 3 propriétés essentielles :
🪜 croissance par incréments
🗺️ sens partagé
🧯 prévention des défauts
Lorsque ces propriétés sont remises en question, la dette augmente, lorsqu'elles sont maintenues ou rétablies, la dette reste sous contrôle.
Exemple : "Après une semaine ou deux d'essai, on a reconnu que le pair programming n'était pas pour nous, vu qu'on ne s'entendait jamais à propos du code, du design etc. et donc on a décidé de travailler chacun dans son coin, rendez-vous en fin de sprint pour intégrer."
🅀: si aucune autre mesure n'est prise, quelle propriétés essentielles de l'état de l'art vont être impactées par ce changement ?
🅁: les trois :
🪜 l'équipe vient de décider d'intégrer moins souvent des parties de code plus longues
🗺️ les échanges (questions, compléments d'information, corrections, décisions) seront moins nombreux, et plus difficiles
🧯 moins de relecture de code ⇒ plus grande probabilité de défauts (à moins d'être un·e ninja du code)
Croissance par incréments, sens partagé, prévention des défauts : ces 3 propriétés clés peuvent donc nous guider dans la lutte contre la dette technique.
Stay Tuned !
Pro Tips
La dette technique, c'est le bilan qui sort comme d'une enveloppe lorsque l'équipe (au sens large, c'est à dire incluant la Technique, le Métier et le Management) fait le point sur l'état de l'art du projet.
C'est une facture théorique dont le montant, s'il pouvait se calculer, indiquerait la distance entre cet état de l'art et l'état de l'art requis par votre feuille de route.
Il n'y a pas d'outil miracle pour limiter à coup sûr la dette technique, mais il existe une heuristique générale qui peut être d'un grand secours à savoir, diviser pour régner :
pro tip ☞ Pour limiter la dette technique constatée lors de vos points sur l'état de l'art, faites plus souvent le point sur votre état de l'art
Cela permettrait a minima de calibrer la "capacité d'endettement" de l'équipe, et de maintenir ou rétablir la cohérence dans les discussions concernant la feuille de route.
Une application ayant 10 ans de bons et loyaux services à son actif, dont le périmètre fonctionnel s'est multiplié par 5 et le parc d'usagers par 1000, mais dont la stratégie de prévention des défauts n'a pas évolué depuis ses débuts héroïques, ce n'est pas un défi technique, c'est plutôt une énigme organisationnelle : comment en arrive t'on à un tel décalage ? La vitesse à laquelle évolue (au moins en surface) la technologie nous pousse à un rééxamen continuel de notre état de l'art. Comment se fait-il que la question des tests ou de la relecture du code soit restée tout ce temps en arrière plan, comme hors-sujet ? Ça tient du prodige.
Quoi qu'il en soit, nous avons toujours à notre disposition 3 propriétés relativement simples qui permettent de savoir si notre état de l'art va dans le bon sens, c'est à dire perd ou gagne en cohérence :
🪜 croissance par incréments : est-ce que notre état de l'art contient des processus et des pratiques permettant de construire une solution petit à petit, plutôt qu'en longues phases ? Est-ce que cela est vrai à tous les niveaux du projet ?
🗺️ sens partagé : est-ce que les acteurs partagent un vocabulaire commun ? Est-ce que ce qui a du sens et de l'importance pour l'un en a aussi pour les autres ? Est-ce que les conflits sont traités via la compréhension mutuelle et la négociation plutôt que la coercition ? Est-ce que cela est vrai à tous les niveaux du projet ?
🧯 prévention des défauts : est-ce qu'au fur et à mesure que la taille et la complexité du système augmentent, l'équipe élimine les conditions d'apparition des défauts au lieu d'éliminer seulement les défauts ? Est-ce que cela est vrai pour toutes les activités de conception comme de livraison ?
pro tip ☞ Pour limiter la dette technique, faites régulièrement un point sur l'état de l'art dans lequel sont évalués :
🪜 croissance par incréments
🗺️ sens partagé
🧯 prévention des défauts
Stay Tuned !
Construction de Théorie
Merci Arnaud pour ta contribution éclairante à cette conversation !
🎤 Est-ce que la "dette technique" n'est pas aussi, et même souvent, une situation analogue à celle du changement de paradigme décrit par Kuhn ?
🎤 Un logiciel ou système croît en fonction d'une certaine vision du monde, d'une certaine théorie sur comment il doit fonctionner, à qui il s'adresse, quels problèmes il doit résoudre, dans quel environnement il s'insère… Cette "théorie" initiale s'avère adéquate au début et permet de produire de la valeur, de donner satisfaction aux utilisateurs. Mais petit à petit, des failles apparaissent, des "faits" deviennent difficile à réconcilier avec la théorie. Les ingénieurs y parviennent avec de plus en plus de difficulté, ils prennent de plus en plus de temps pour chaque changement requis, et chacun introduit de nouveaux problèmes.
🎤 Pour réconcilier tous ces faits, il faut une nouvelle théorie (un nouveau cadre technique ou "état de l'art" comme tu le désignes) qui peut être plus ou moins différente, plus ou moins difficile à accepter (eg. passer d'un système centralisé écrit avec un 4GL et un SGBDR à des micro-services dans le cloud est certainement un changement de paradigme trop brutal).
🎤 Dans cette hypothèse, la dette technique est inévitable si le système doit s'adapter à son environnement.
Si je ne me trompe pas, tu empruntes à Peter Naur, autre lecteur de Kuhn, sa vision de la programmation comme construction de théorie. La conclusion de son essai peut éclairer notre lanterne sur la DT :
📖 Si l'on accepte qu'une part essentielle de la programmation consiste à apporter au programme les modifications requises par un changement des circonstances extérieures, alors il faut admettre que le but primordial en programmation est de faire en sorte que les programmeurs construisent une théorie du problème à résoudre tel qu'il est supporté par l'exécution du programme. De cette considération découle la notion que la vie d'un programme dépend des programmeurs qui possèdent la théorie de ce programme. […]
📖 Une autre conséquence de ce point de vue est que les programmeurs doivent se voir accorder le statut de développeurs responsables et managers perpétuels de l'activité dans laquelle l'ordinateur joue une part, et que leur éducation doit mettre en avant l'exercice de la construction de théories, à côté de l'acquisition des connaissances du traitement de l'information et des notations.
Cette prescription émise en 1985 (!) n'a pas été entendue, loin de là : notre activité est gérée non par 1 mais 3 acteurs (Métier, Tech, Management), et le drame qui se joue naturellement entre eux représente une source indirecte mais permanente de dette technique.
Je voudrais donc compléter ta conclusion : la dette technique est inévitable si le système doit s'adapter à son environnement sans le support continu d'une équipe intégrale qui en construit et étend la théorie.
Lit de Procuste
Il y a environ 25 ans, une de mes toutes premières missions de conseil a consisté à auditer la conception d'une application Visual Basic installée dans des agences, et qui permettait entre autre d'imprimer l'organigramme de l'agence : une simple arborescence de rectangles contenant chacun un nom de service et un nom de responsable.
Toutes les agences n'avaient pas la même organisation. Détail curieux : pour certaines d'entre elles le programme traçait juste en dessous de la position la plus élevée, un rectangle anonyme contenant la mention :
Responsable Fictif —
J'enquêtai auprès du Maître d'Ouvrage :
— Ça consiste en quoi, le travail d'un Responsable Fictif ?
— Oh ça n'existe pas. Ce n'est pas un vrai poste.
— Ah ?
— Oui : on a deux types d'agences dans le groupe : les grandes, qui ont 5 niveaux hiérarchiques, et les petites qui en ont seulement 4.
— Je vois… (Je ne voyais pas).
— Au début l'appli n'en tenait pas compte. Quand on l'a signalé en recette, le prestataire a pris acte de l'information, puis après quelques jours nous a dit que pour des raisons techniques il était préférable que toutes les agences comportent 5 niveaux, et que le modèle serait trop complexe s'il fallait gérer un nombre variable de niveaux.
— Je vois.
— Par trop complexe, ils voulaient dire "qui coûte plus cher à réaliser", tu vois ce que veux dire.
— Je vois.
— On a donc décidé de suivre leur suggestion et de créer un niveau intermédiaire exprès pour les petites agences. On l'a appelé Responsable Fictif, et on a émis une note d'instruction à ce sujet.
Après un examen du code et du modèle de données, j'élucidai l'origine du Responsable Fictif : les concepteurs de l'application ne savaient pas ou ne voulaient pas représenter des liens hiérarchiques au moyens de relations. Ils avaient donc opté pour une simple table :
IdtAgc : CHAR(10)
Niv : Numeric(5)
NomSce : CHAR(50)
NomRspSce : CHAR(50)
Une requête simple également ramenait pour une agence identifiée l'ensemble de ses responsables, ordonné par niveau. Le nombre de niveaux distincts n'était jamais inférieur ni supérieur à 5 : toutes les "petites" agences comportaient une ligne comme celle-ci :
"CHARENTON",2,"Responsable Fictif","-"
Fort de cette simplicité, et dans la plus pure tradition du lit de Procuste, le programme VB imprimait benoîtement 5 niveaux quelque soit l'agence.
Cette décision de conception représente t'elle un cas d'endettement technique ? Oui et Non.
❌ elle concerne la qualité externe et non la qualité interne
❌ elle impacte le système et l'organisation présents, non l'évolution future
✅ elle dégrade l'état de l'art de l'application, notamment sous l'aspect du Sens Partagé
✅ elle a été prise parce qu'il n'y avait plus le temps de bien faire
✅ une solution à la fois plus élégante et plus adaptée au problème existe
❌ cette solution n'est pas vraiment à la portée de l'équipe
Stay Tuned !
Boule de Cristal
Une équipe de 5 développeurs, un product owner et un manager, ajustent leur état de l'art : on passe de Trelli à Jora. (Jora permet de requêter les tickets, ce qui permet de produire toutes sortes de rapports intéressants, ce qui améliore la communication du projet).
4 semaines plus tard, elle décide de faire le chemin inverse.
Impact aller :
- conversion tickets : 0.5j
- prise en main : 0.5j
- communication : 0.5j
Impact retour à t + 4 semaines :
- ressaisie tickets : 0.1j
- communication : 0.5j
À 4 semaines, le changement Trelli → Jora → Jora → Trelli aura coûté 2j d'effort et rapporté une leçon : l'ergonomie de Jora présente des défauts incontournables et insurmontables.
La même équipe, avec son PO et son Manager, décide de remplacer la stratégie
[Tests Automatisés Unitaires]
par une stratégie de
[Campagne de Tests de Non-Régression Manuels]
4 semaines plus tard, elle décide qu'elle a pris une bonne décision : davantage de stories développées, des développeurs épanouis qui écrivent du code utile.
Impact aller, à t+16j
- TU automatisés sur le code : 0j * 5 DEV x 4 sprints (zéro!)
- stories supplémentaires réalisées : 4 x 4 sprints
- tests de non-rég. manuels : 2j * 1 QA x 4 sprints
20 semaines plus tard, elle décide de revenir à une stratégie de tests automatisés à grain fin, si possible à mesure qu'on écrit ou modifie le code.
Impact aller, à t + 100j
- interventions sur incidents en production : 1j * 5 DEV x 16 sprints
- corrections de défauts trouvé en non-rég. : 1.5j x 5 DEV x 16 sprints
- corrections de défauts insérés lors de corrections de défauts : 0.5 j x DEV x 16 sprints
- tests de non-régression manuels : 4j * 1 QA x 16 sprints
- communication de crise : 8j
📖 Leçons apprises :
- assurer systématiquement la non-régression requiert 1) d'automatiser les vérifications 2) au plus près du code concerné 3) au fur et à mesure qu'on l'écrit
- les tests manuels sont du "best effort", i.e à hauteur du temps imparti, ils ne sont donc jamais couvrants
- le travail d'un testeur est de trouver des problèmes et non de vérifier du code
Impact retour :
- estimation des efforts de rétro-engineering : 5j
- ajustements et communication : 2j
- acquisition des techniques de TU automatisés sur du code existant : 1.5j * 5 DEV x 4 sprints
- retro-engineering du code des stories pour ajout de TU : 2j * 5 DEV x 4 sprints
🚪 Conclusion 🚪
Tout au long de son activité, l'équipe ajuste son état de l'art.
Certains ajustements sont faciles à annuler : ceux dont l'impact est faible et observable rapidement. 🔎
Certains ajustements sont coûteux voire impossibles à annuler : ceux dont l'impact est important ET observable seulement après un long délai. 🔭
❓ en l'absence de boule de cristal, comment savoir si un ajustement de notre état de l'art impacte négativement le projet ?
🧯🧯🧯 si l'ajustement limite au lieu d'étendre votre stratégie de prévention des défauts, ne le faites pas 🧯🧯🧯
#qa #etatdelart #dettetechnique
Crise de Croissance
Toutes les fois où un Tech Lead m'a annoncé "cette application, c'est la vache à lait de l'entreprise" il m'a ensuite montré du code legacy.
☕️🥐🗞
Un système contenant de la technologie croît de manière non-linéaire. C'est même sa raison d'être.
Un éditeur logiciel investit dans un système relativement simple basé sur une idée innovante, et vend quelques licences.
🦻 Ses premiers clients sont agréablement surpris, et de bouche à oreille, lui amènent de nouveaux clients.
💶 Cela permet à l'éditeur non seulement de rembourser ses prêts mais aussi d'investir : faire plus de logiciel, vendre plus de logiciel !
Qu'est-ce exactement que cette croissance non-linéaire ?
On peut choisir de la définir ainsi : le nombre d'interactions concrètes possibles entre les éléments de ce système. Ce nombre croît comme le produit du nombre d'utilisateurs par le nombre de chemins d'interactions possibles avec le programme.
⏰ Par exemple un logiciel très simple, appelons-le 𝗗𝗲𝗯𝗼𝗼!, contient 6 fonctionnalités :
- afficher l'heure
- définir l'heure d'alarme
- modifier l'heure d'alarme
- annuler le mode alarme
- restaurer le mode alarme
- stopper l'alarme déclenchée
et son éditeur l'a distribué à 250 clients.
Nous pourrions convenir que la complexité du système 𝗗𝗲𝗯𝗼𝗼! = 250 x 6
Notre éditeur ajoute 4 features :
- réglage du volume de l'alarme
- définir une alarme exceptionnelle
- annuler une alarme exceptionnelle
- définir la sonnerie d'alarme (parmi 28 possibilités!)
ce qui lui amène 200 nouveaux clients.
𝗗𝗲𝗯𝗼𝗼! croît en complexité : 550 x 10
Certains clients demandent : est-ce que vous pouvez aussi reporter une alarme à dans 9 minutes ?
Des prospects : est-ce que vous sauriez diffuser de la musique au lieu de la sonnerie ? 🛒
Nouvelles features → nouveaux clients → nouvelles features 🔄
Le logiciel s'enrichit, l'éditeur s'enrichit, le code se complexifie.
📈🤑🤖
Côté Technique, "tout est prioritaire" :
- coder de nouvelles fonctionnalités
- répondre aux utilisateurs réveillés à des heures non programmées à cause d'un bug (voir tickets 4807 à 4822 -- le même défaut à causé plusieurs incidents similaires).
- gérer les demandes du marketing, de la vente, du help-desk, des intégrateurs partenaires…
🥀 Le temps où on avait le temps de prendre le temps de bien faire les choses est révolu. Sous pression, l'équipe commence à sacrifier quelques procédés de son état de l'art :
✂️ est-ce qu'on a vraiment besoin de relire le code ? SVP moins de réunions !
🗑 j'ai arrêté de mettre à jour la doc (en plus j'aimais pas ça)
🪚 ces tests, là, sont cassés depuis 1 an. Je propose qu'on les débranche
Et notre éditeur se retrouve avec ce paradoxe :
🤔 un business florissant, soutenu par une base de code "legacy"
🚪 Conclusion 🚪
Notre solution croît : utilisateurs: ↗️ features: ↗️ complexité: ↗️ ↗️
Est-ce maintenant le moment de RETIRER des procédés de notre état de l'art ?
🪜🪜🪜 Réfléchissons 🪜🪜🪜
#etatdelart #dettetechnique
Sens Partagé
Bienvenue dans cette conversation Sami Hadhri! Tu évoques un chemin peu fréquenté pour se sortir des ronces de la dette technique :
ça me rappelle une décision contre intuitive et critiquée de notre CTO quand j'étais chez Reuters. Il a décidé d'arrêter les features et de passer quelques mois sur l'absorption de la dette et la réarchitecture du produit.
Décision courageuse : elle implique de répondre aux besoins de la Technique et du Management avant ceux du Métier. Or la Technique et le Management sont au service du Métier. C'est un objectif métier qui est la raison d'être de ce projet et de sa complexité, y compris la complexité accidentelle que nous avons devant nous et qui nous empêche d'avancer.
C'est comme un vaisseau qui serait immobilisé au milieu de nulle part. Tout mouvement pour le faire avancer dans la direction souhaitée par le Métier est assujetti à une friction devenue inpondérable, et à dire vrai, ingérable.
Les acteurs Techniques se désolidarisent du projet. Leur savoir faire peut être utile dans un autre vaisseau. On cherche à les remplacer par d'autres techniciens, à qui on demandera de s'adapter à l'état du projet plutôt que de chercher à l'améliorer.
On commence à parler de refonte. À trois ans du projet initial ?! Le projet perd tout sens. Ce n'est pas normal, mais c'est compréhensible si l'on admet que son état de l'art fait partie des instruments qui lui donnaient du sens.
La quantité ou la densité de la dette technique d'un projet dépend de l'avenir que ses acteurs projettent en lui. Si on destine l'application au décomissionnement, DT = 0. Mais si on la prépare à une seconde vie, alors DT = €€€€€
La nature de la dette technique du projet dépend de son histoire. C'est en quoi l'idée de quantifier la dette technique, d'en faire une addition (salée) qu'il faut maintenant payer, comme un coût caché qui serait maintenant révélé, n'est pas si utile que ça.
Imaginons la discussion sur le vaisseau. Les 3 acteurs sont sur le pont avant. Selon le vaisseau, le mode de voyage et la destination, la nature de la dette technique peut être fort différente :
🕳 Pour aller plus vite, nous avons cassé nos instruments, et maintenant nous sommes perdus.
💰 Nous n'avions pas les bons instruments pour ce voyage, et maintenant nous devons les acquérir.
🪛 Nous voyageons depuis longtemps : nos instruments ont besoin d'entretien.
Le point commun à toutes ces situations, c'est qu'il faut sortir des ronces, c'est à dire réaligner l'état de l'art du projet avec son objectif initial. Il est possible de revoir cet objectif, ou de changer les contraintes. Tout est possible à vrai dire, mais le mouvement du vaisseau ne peut reprendre qu'à condition de commencer par la question de l'état de l'art :
🗺 Quel problème voulons nous résoudre ensemble ? 🗺
#etatdelart #dettetechnique
Product Owning
- Nouveau! 📯
- Jonglerie
- conflit d'idées
- Zombies
- 🏷 Patterns et Conflits ⚔️
- Horizons Bouchés, Nuages de Conflits
- Expressions de Besoins
- Examiner des conflits 🪑 🕳 🔦
- Scrum à la Rescousse 🕳 🚑
- Ce n'est pas une question de rôle
Nouveau! 📯
Le développement de logiciel est essentiellement une activité de traduction, de conception et de construction. Les modèles d'organisation qui ont cours depuis plusieurs décennies dans l'entreprise ne reflètent pas cette réalité. Dans l'entreprise, on met plutôt l'accent sur le produit (comme dans "product owner"), sa livraison ("delivery"), et sa fabrication ("software factory").
🏭
Or même si l'industrie du développement se porte très bien (merci pour elle), tout le monde s'accorde à reconnaître qu'il est possible de mieux faire. Ce n'est pas faire preuve d'une exigence hors de propos que de militer pour une base de code un peu plus facile à comprendre, une batterie de tests auto-vérifiants qui sécurise chaque changement, des backlogs qui laissent du temps pour retravailler la conception, bref, un peu moins de ce code "legacy" que l'on trouve partout. Un directeur de département à qui j'expliquais en quoi consistent mes missions en général, à savoir, aider des équipes à résoudre des problèmes posés par du code devenu trop difficile à maintenir, m'a fait cette remarque : "vous avez du boulot jusqu'à la retraite !".
🕸
Nous "fabriquons" essentiellement du code legacy. Face à ce problème global la réponse toute indiquée, et la plus populaire, c'est d'améliorer nos compétences techniques. Il faut devenir de meilleur·es développeur·euse·s, se former (pas durant le "sprint" cependant), être intransigeant sur la qualité, refuser de "livrer de la m…", et travailler son art ("craft").
🎖
Se former, apprendre, lire (la littérature informatique est riche, vaste, et accessible) est une excellente idée, mais cela ne peut pas constituer un remède structurel au problème. L'entreprise dans laquelle on entend des phrases du type "les former pour qu'ensuite ils démissionnent, non merci." n'a pas tout à fait tort de s'inquiéter : après tout notre industrie organise sa compétition sur les promesses de la nouveauté technologique.
🛍
Ah, la nouveauté ! Avec quelques photos d'espaces ouverts décontractés ou de centres de données immaculés, on peut créer pour une minute l'illusion d'un monde de la tech propre, ordonné, et pas trop rigide, mais nous savons tous qu'il n'en est rien : le monde de la tech empile des solutions sans les emboîter dans un désordre généralisé et coriace.
🌱
"L'herbe est toujours plus verte dans le pré d'en face", bien sûr, nous évitons de tomber dans ce piège. Mais il semble malgré tout que partout où l'on regarde, quelque soit la "stack" ou le domaine métier auxquels on s'intéresse, chez nous l'herbe jaunit vite.
🛠
Mais la nouveauté, tout de même ! Il suffirait d'un nouvel outil ! Certes, les outils font parfois une grande différence, mais aucun outil ne peut compenser le fait que nous sommes plus prompts à créer du code neuf qu'à réparer le code existant. Il nous faut changer de modèle.
Stay Tuned !
publié sur LinkedIn le 06/03/2023
Jonglerie
— Qu'est-ce qui pourrait te convaincre de rester ? demande le manager au développeur démissionnaire.
— A minima, pouvoir travailler avec du code maintenable.
— Qu'est-ce qui vous empêche d'écrire du code maintenable ?
— Sérieusement ? Viens au prochain sprint planning, et tu verras.
— Justement, votre P.O. me dit que vous passez trop de temps sur le refacto.
— Tu n'as qu'à lui dire que la qualité du code, c'est important.
— Tout est important…
🤹
Trois acteurs aux objectifs complémentaires mais distincts s'impliquent dans ce projet. Aucun d'eux ne peut avoir seul le dernier mot sur sa direction.
📲
Le Métier vise une solution qui réalise de la valeur, dans les meilleurs délais et pour pas trop cher. Le code ? C'est un moyen : si l'on pouvait se passer d'en écrire, le projet s'en porterait très bien. Pourquoi pas ? Le monde de la technologie nous raconte une épopée miraculeuse faite de miniaturisation, d'intégration, d'automatisation, d'industrialisation, de transformation… C'est pour bientôt !
👩🏽💻
La Technique veut maximiser l'apprentissage. Non pas l'apprentissage en général — quoique la généralisation soit une seconde nature chez les développeurs — mais celui nécessaire à la résolution de ce problème particulier décrit par le Métier, qui est un problème ouvert. Le Métier formule le souhait d'une solution, mais ce qui va voir le jour c'est un flot d'activités (informatique, cognitive, financière, logistique, etc.) en constante évolution, et non pas une solution figée. Le contexte, les objectifs, les contraintes de ce problème vont changer, avant même la première "livraison".
📝
La Technique doit donc, en plus de résoudre le problème, tracer et documenter, souvent dans le code lui-même, ses intentions et ses limites face aux évolutions possibles du problème. Pour reprendre Peter Naur, il faut non seulement un programme, mais également une théorie qui sous-tend ce programme. Les outils modernes pour décrire cette théorie s'appellent Refactoring, Architecture Decision Record, Ubiquitous Language, Test Driven Development…
🎛
Le Management voudrait rendre ce problème (le problème de créer de la valeur à l'aide de la technologie, et dont les frontières vont se déplacer) manageable. C'est essentiel. Un manager pose souvent les questions "Combien ?", "Qui ?", "Quand ?", "Avec quelles garanties ?". Sans ces questions, et sans l'insistance du Management, le Métier se bercerait d'illusions, et la Technique exploserait son budget en recherche, plutôt qu'en développement.
Pour revenir au projet dont il est question en introduction, nos 3 acteurs ont chacun joué une carte :
🏭 Le Management a normalisé toute l'activité dans un modèle de type "production" simple, clair, hiérarchisé
🗜 Le P.O. fait pression pour qu'on sacrifie la maintenabilité de demain aux résultats d'aujourd'hui
🚪 Le Tech Lead a trouvé un contexte plus favorable à ses aspirations quitte à déstabiliser le projet
Qui va gagner ?
Stay Tuned !
publié sur LinkedIn le 07/03/2023
Conflit d'Idées
Merci Laurent Prost et Mauko Quiroga Alvarado pour vos contributions à ma réflexion d'hier sur ce système à 3 acteurs qui modélise pour moi le developpement.
Si cette conversation tendue entre un Tech Lead et son Manager à propos du pilotage fonctionnel et technique du projet nous évoque un Mexican Stand-off plutôt qu'une saine relation de collaboration, c'est parce qu'il y a conflit.
🛡 ⚔️ 🏳️
Précisons : il y a un conflit qu'il s'agit de résoudre, et non pas un conflit au sens d'une agression ou même d'une animosité.
C'est un conflit d'idées (techniques, fonctionnelles, pratiques, méthodologiques, stratégiques, voire déontologiques) qui s'appuie lui-même sur un conflit de ressources. Ce n'est pas un conflit de personnes.
Dans un projet d'ingénierie complexe,
💬 les conflits d'idées sont indispensables, car ils sont la voie la plus rapide vers la meilleure solution. (Si vous me dites ici que vous n'êtes pas d'accord, vous allez prouver mon point).
💶 les conflits de ressources sont inévitables, comme nous savons depuis que nous sommes en âge de réaliser nos rêves en utilisant de l'argent (ou des branches d'arbres, ou des legos).
😥 les conflits de personnes ou de territoire n'ont pas leur place. C'est déjà assez compliqué comme ça.
Qui doit "gagner" dans ce conflit ? Il faut réaliser un logiciel, c'est à dire résoudre un problème mal compris à l'aide d'informations incomplètes, dans un contexte incertain.
Chacun joue son rôle :
Le pilote fonctionnel précise la nature du problème, la portée de la solution, et l'ampleur de l'investissement.
La technique cherche la meilleure conception, ce qui inclut également le meilleur état de l'art pour faire vivre cette conception. (Aucun·e ingénieur·e n'a passé 5 ans sur des bancs d'école en vue d'apprendre comment faire du logiciel jetable ou du legacy).
Le management répond des connections nécessaires à l'initialisation du projet, et de la continuité des moyens de le réaliser.
Une chose est établie : si l'un des 3 gagne "sa" bataille, l'entreprise perd. C'est comme un problème du prisonnier, mais à trois prisonniers, et dont le prix serait un logiciel et non une remise de peine (OK, ce n'est pas comme le problème du prisonnier 😅).
🌫
Oublions le conflit pour un moment, et considérons un logiciel réussi : c'est un succès (commercial, ou autre). Son code est habitable. Sa conception évolue depuis 15 ans. Les tentatives de le "simplifier", de le refondre, de l'outsourcer (pardon pour le barbarisme) ont été sagement reportées sine die. Ce logiciel est une pièce essentielle du SI de ses utilisateurs. Son code, son architecture et sa méthodologie font école.
🗺
La conversation initiale qui a mené à ce projet a grandi de façon arborescente. Le cercle s'est élargi, sans perte de cohérence. C'est peut être "culturel". En tout cas c'est très fort !
Une telle réussite suscite toujours la même question : mais comment font ils ?
Stay Tuned !
🌁
publié sur LinkedIn le 08/03/2023
Zombies
Une application qui contribue pleinement à la création de valeur dans l'entreprise mais dont la conception n'est plus vivante, est ce qu'on appelle dans notre jargon technique une application "legacy".
La définition élégante proposée par Nicolas Carlo va dans ce sens :
Legacy Code is valuable code you're afraid to change.
Cette situation n'est pas nécessairement un problème. Certaines solutions peuvent durer longtemps sans qu'il soit nécessaire pour l'entreprise d'y apporter des changements. Elles peuvent même finir par "migrer" vers la droite dans une carte de Wardley c'est à dire devenir des commodités. Lorsque la complexité essentielle d'une application peut être absorbée par un acteur extérieur et faire l'objet d'une fourniture industrielle, cela indique que la solution a été "rationalisée" et que l'évolution de sa conception ne constitue plus un enjeu stratégique.
En revanche, lorsqu'une solution apporte une valeur stratégique à l'entreprise, alors selon toute probabilité, des changements importants touchant sa conception vont être projetés, négociés, parfois plus ou moins imposés. Sa conception a besoin de vivre. 🩺
C'est la raison pour laquelle une équipe de développement écrit des tests, des commentaires et de la documentation. 📐📝ℹ️
C'est aussi la raison pour laquelle elle remanie le code : si elle peut donner à son code une expressivité suffisante, alors le code sera plus facile à changer, même si on n'écrit pas de commentaire ni de documentation ! 😎
Voici un exemple trivial :
Supposons que dans la conception d'une application, partout où la TVA doit être calculée, des programmeurs (inconscients) ont écrit :
prixTTC = prixHT * 1.20
Pour que ce code soit facile à changer, deux tactiques possibles.
Tactique A :
✅ chaque chemin d'exécution du code où une TVA est calculée fait l'objet d'un test auto-vérifiant
🔬 l'emplacement du code où se situent ces calculs peut être retrouvé dans une liste ou par extraction
🤓 note explicative sur ce qui peut arriver lorsqu'on fouille du code à l'aide de l'expression régulière * 1.20
Tactique B :
📦 le calcul de la TVA fait l'objet d'un module TauxTva
✅ ce module est équipé de ses propres tests auto-vérifiants
🧐 les contraventions à son usage sont détectées et discutées lors de la relecture du code
Supposons que ces programmeurs, extraits de leur léthargie au beau milieu du sprint par la remarque d'un stagiaire, réalisent qu'ils ont besoin d'appliquer la tactique A ou B. Ils en touchent un mot au PO qui leur tient à peu près ce langage :
_ Foin des refactorings ! Vous vous ferez plaisir après la mise en prod.
L'équipe referme ce dossier. Le logiciel est livré en prod. Après la mise en prod, il y a tellement de choses nouvelles à faire…
Dans 5 ans une équipe va ouvrir le capot : whaaaat ?
🕸🧟♀️🧟🧟🕸
En fait, c'était le refacto de la dernière chance. 🪦
publié sur LinkedIn le 09/03/2023
🏷 Patterns et Conflits ⚔️
À propos de mon exemple d'hier :
prixTTC = prixHT * 1.20
partout dans le code,
j'ai un peu simplifié le "technical debt item", parce que le propos n'est pas de faire de la technique.
En revanche :
"Pas de refactorings dans ce sprint : vous vous ferez plaisir après la mise en prod."
est une phrase qu'a réellement prononcé un PO dans un projet. Lorsque je l'ai entendue ma première réaction était de revenir à mes définitions. C'est une réaction typique que j'ai lorsque je détecte un conflit. J'ai beau dire, comme tous les agilistes :
📜
Les individus et leurs interactions, de préférence aux processus et aux outils
📜
il reste qu'en cas de conflit, je refais toujours un petit tour du côté des processus et des outils, en mode "qu'est-ce qu'on s'était dit, déjà". Détail intéressant : la plupart du temps "ce qu'on s'était dit", on ne se l'était pas dit, ces définitions ne sont pas partagées, et je fais des projections. C'est à dire que je navigue dans le monde, et en l'occurrence dans ce conflit, avec ma propre carte, qui n'est pas nécessairement la même que celles de mes interlocuteurs.
Où ça, un conflit ?
C'est un conflit d'idées (ouf!) et aussi un conflit d'objectifs (mais je classe les objectifs et les intérêts comme des idées ici) :
🏷 Merciless Refactoring : règle de travail consistant à modifier le code d'un programme afin d'en améliorer la facilité d'évolution, sans modifier son comportement, dès que le besoin s'en fait sentir
⚔️
🏷 Product Owner : rôle définissant les responsabilités et prérogatives liées à la traduction en application, des idées élaborées avec le Métier
NB: dans le Guide Scrum la définition du PO est légèrement différente :
🔖 Le Product Owner est redevable de maximiser la valeur du produit résultant du travail de la Scrum Team.
cependant je préfère ma définition car cette dernière fait référence à une activité de traduction et non de production. (Comme je l'ai dit, je navigue avec mes cartes 🤓)
La règle Merciless Refactoring sert à lutter efficacement contre une forme de dette technique, par détection et résolution rapide des "Code Smells". 💩
Bien sûr et comme toujours, le conflit d'idées repose sur un conflit de ressources fondamental auquel pas un projet n'échappe :
Quantité de tâches à réaliser
⚔️
Temps alloué pour les tâches à réaliser
La Tech voudrait améliorer la maintenabilité du code pendant qu'il en est encore temps, mais aussi respecter les prérogatives de l'acteur Métier. Elle fait une brèche à l'état de l'art, en passant de "Merciless Refactoring" à "Permission to Refactor".
Le Métier voudrait atteindre l'objectif de livraison, en sacrifiant temporairement la maintenabilité. Il fait une brèche à l'état de l'art en décidant à la place de la Technique de ce qui est bon pour le code à l'instant t.
Que décider ?
publié sur LinkedIn le 10/03/2023
Horizons Bouchés, Nuages de Conflits
À l'ordre du jour du "sprint planning" du lundi matin, figure une "User Story Technique" :
Les développeurs, à la suite d'une revue de la conception, proposent une tâche importante de remaniement, qui devrait occuper une partie de l'équipe pour plusieurs heures. Faire ce refactoring, c'est renoncer à livrer une voire deux stories à la fin du sprint.
Le Product Owner écarte la proposition pratiquement d'un revers de la main : en regard des enjeux de la prochaine démo, et vu l'allure générale à laquelle avance ce projet (une allure jugée inquiétante par le Métier) l'amélioration proposée est considérée comme secondaire, et les efforts dans ce sens comme dispendieux ("Vous vous faites plaisir").
🔺 Revoilà notre triangle de fer. Rapide, bon marché, de qualité : choisis en deux.
La Technique et le Métier se retrouvent à négocier une fonctionnalité. (Ou bien négocier un refactoring, c'est pareil). L'une renvoie l'autre dans ses filets, et réciproquement :
— Pour des raisons techniques, il va falloir temporairement sacrifier une feature ou deux. Nous te laissons choisir lesquelles.
— La modularité du code, c'est bien gentil, mais ce n'est pas le problème. Vous ferez ça plus tard.
😰😡😣
Bien sûr, comme ces acteurs sont humains, et la culture de l'entreprise où ils travaillent étant ce qu'elle est, la meilleure manière pour chacun de traverser ce conflit passe plutôt par le "drame" d'abord avant de passer à la réflexion posée. Ce n'est pas facile de se poser pour réfléchir ensemble quand les fins de non-recevoir et les sous-entendus même subtils, ainsi que nos propres réactions abîment notre estime de soi. 💬💭🗯
Si elle pouvait lever le brouillard du "drame" (qui fait certes le délice des amateurs de bonnes séries mais complique diablement les choses dans l'entreprise), l'équipe procéderait probablement plus efficacement, ou en tout cas avec une certaine méthode : elle verrait alors que le conflit n'est qu'apparent (c'est un conflit d'idées en vue de réaliser un objectif commun) et qu'il peut être résolu.
Par exemple en utilisant un diagrame de résolution de conflit (Evaporating Cloud) :
A : l'objectif est de livrer sur le marché un produit supérieur, maintenant et dans le futur
B : besoin : offrir des features inédites avant la concurrence
C : besoin : changer facilement la conception du produit
D : objectif respectif : inclure le maximum de stories dans ce sprint
D' : objectif respectif : améliorer la modularité du code dans ce sprint
↙️ B ⬅️ D
A ⚡️
↖️ C ⬅️ D'
Chaque flèche symbolise une hypothèse de nécessité. En analysant chacune des hypothèses, le groupe va pouvoir
- séparer les conditions réelles des conditions seulement présupposées
- injecter des solutions possibles qui rendraient une ou plusieurs conditions caduques
- effectivement résoudre le conflit
tout en se posant la question de l'état de l'art : Quel problème voulons nous résoudre ensemble ?
publié sur LinkedIn le 13/03/2023
Expressions de Besoins
🚉🏗🏭🏦🧪📺🏢 → 👨💻
Dans mon travail, depuis des années je traite des besoins Métier. Certes avec l'arrivée des approches agiles il y a 25 ans, la démarche de "recueil des besoins" s'est métamorphosée (et heureusement). Mais la direction de "l'expression de besoins" n'a pas changé :
≃ 1990 : Expression de Besoins → Analyse → Réalisation
≃ 1998 : Client sur Site → Scénarios Utilisateurs → Réalisation
≃ 2005 : Story Mapping → Scénarios Utilisateurs → Réalisation
≃ 2013 : Event Storming → Scénarios Utilisateurs → Réalisation
Ce flot d'information du Métier vers la Technique est cohérent avec le modèle "Développement = Production" : d'abord on conçoit, puis on réalise.
Il y a eu dans le passé des méthodes entièrement câblées sur ce schéma, comme Merise par exemple :
≃ 1985 : Modèle Conceptuel → Modèle Organisationnel → Modèle Logique → Modèle Physique → Système Informatique
Vu depuis un modèle de type production, cette cascade tombe sous le sens : le système informatique (en gros, l'infrastructure, les liaisons, les données, et le code) met en œuvre une logique qui est au service de l'organisation telle qu'elle est conçue au niveau fonctionnel Métier.
(Dans ce modèle, on pourrait voir aussi le conceptuel Métier qui vient informer la matière Technique. Quand nous avons "l'idéation" d'un côté et de l'autre les "mains dans le cambouis", nous nous faisons les dignes héritiers d'Aristote…) 🏺
Adoptons pour un temps un modèle de traduction : développer c'est traduire des idées formant un système pour certains acteurs en idées qui en forment un autre pour d'autres acteurs. Ces traductions relèvent de processus imbriqués, multiples et réciproques. Le système ainsi créé restera utile, fiable et stable tant que les traductions peuvent avoir lieu.
Dit plus simplement : un logiciel garde (ou augmente) sa valeur tant que sa conception reste vivante.
Dans ce modèle, la notion de besoin a toujours un sens, mais à condition de l'appliquer dans tous les sens, justement : il y a les besoins de l'acteur Métier, et ceux de la Technique, ainsi que ceux du Management.
Par conséquent, notre PO qui déclarait lundi matin :
— Les features d'abord, pas de refactoring. Vous vous ferez plaisir après la mise en prod.
se trompait d'interlocuteur : si les fonctionnalités émanent bien de son besoin Métier, en revanche le refactoring répond aux besoins du Management et non de la Technique.
En effet le Management a pour objectif de préserver les conditions optimales dans lesquelles le système peut évoluer. Les refactorings (un renommage, une extraction de méthode par ex.), ont justement pour but de faciliter un changement de la conception.
Et le besoin de la Technique au fait ? C'est d'abord d'apprendre. Le refactoring est certes lié à ce besoin également, mais pas de façon indissociable. Le monde est rempli de code pas ou très peu refactoré, et la Technique s'en porte très bien.
publié sur LinkedIn le 14/03/2023
Examiner des conflits 🪑 🕳 🔦
Merci Anaël Ichane de te joindre à notre conversation !
La discussion (vécue) que je mets en exergue comme un exemple de conflits d'objectifs possède juste ce qu'il faut de drame pour attirer notre attention. Les projets heureux n'ont pas "d'histoires".
Cela ne veut pas dire qu'ils n'ont pas de conflits. Mais que leurs acteurs ont un sens aigu de la cohérence dans la conception ainsi que des frictions dans l'exécution. Un ami à moi, chef de projet, agiliste, devenu expert dans l'art du Lean, disait :
— Dans mon équipe on a 20 conflits par jour.
— C'est l'enfer ! Comment faites vous pour avancer ?
— Je veux dire : on résout 20 conflits par jour. En moyenne un conflit prend 10 minutes à résoudre.
— N'empêche sans ces conflits…
— Oh, on serait nulle part à l'heure actuelle. Notre produit ne serait même pas sur le marché.
Si le mot "conflit" vous évoque uniquement les scuds sur slack ou bien les relations de travail qui moisissent, il nous faut peut être ouvrir la fenêtre et rafraîchir un peu cette notion.
-
Dans une algarade entre deux députés éméchés, l'un veut éliminer la présence de l'autre et réciproquement. (Conflit de personnes ou de territoires)
-
Dans un jeu de chaises musicales, deux joueurs ne peuvent pas s'assoir ensemble sur la dernière chaise restée libre. (Conflit de ressources)
-
Dans tel développement, on veut choisir entre les stratégies : "trunk based" ou "feature branch". (Conflit d'idées).
Le point commun entre ces 3 exemples ? C'est la mise en regard de deux parties qui vise une résolution exclusive de l'une sur l'autre.
Le conflit d'idées n'est pas la seule manière d'avancer dans une conception (l'équilibre entre plusieurs forces en est une autre, par exemple) mais il est indispensable à une solution cohérente. Un projet ne peut pas accueillir des procédés mutuellement exclusifs, sous peine de finir au musée des curiosités plutôt qu'en production.
La discussion que tu cites, Anaël, n'est pas mal non plus dans le genre drama :
🍿
— Ok très bien. Elle est où? Elle concerne quoi? Comment peut-on l'approcher ? Et quel objectif peut-on se fixer ?
— Ah mais la dette ça se matérialise pas comme ça. On est trop endetté, il faut tout réécrire
— Ok donc pdt 2 ans on arrête tout et on réécrit tout?
— Oui voilà.
— Bon bah on passe les stories en attendant que vous trouviez une approche moins radicale et plus valorisable pour le produit.
— Ah le produit ne veux pas qu'on travaille sur la dette
Chacun semble vouloir saboter sa propre solution :
La Technique veut changer de problème en déclarant celui qu'elle a sous la main totalement insoluble (et ce n'est pas faute de perches tendues par son interlocuteur).
Le Métier veut mobiliser l'effort sur les stories dans l'attente qu'une approche de désendettement (mais trouvée au moyen de quels efforts ?) apparaisse.
Et si comme le suggère Laurent Bossavit, on apprenait à négocier ?
publié sur LinkedIn le 15/03/2023
Scrum à la Rescousse 🕳 🚑
Merci Cédric Crevier pour ta contribution à cette conversation sur DT et PO !
Face au faux-dilemme "livrer des stories vs résorber de la dette" tu suggères (et je suis 💯 👍) de suivre Scrum, notamment les prérogatives propres à chaque rôle.
Un PO n'a pas à dire s'il faut refactorer ou non 🔑
Scrum ne définit pas précisément ce que les développeurs doivent faire dans le détail (rien sur le refactoring dans le guide Scrum, à ma connaissance) mais leurs responsabilités incluent le fait d'instiller la qualité en adhérant à une "Definition of Done", et de se rendre mutuellement des comptes en tant que professionnels.
Ce n'est pas dans le rôle du PO de fixer ou d'altérer les standards de qualité interne que les développeurs appliquent, et donc pas dans son rôle non plus de dire s'il faut refactorer ou non.
Il doit fixer le Cap, si les devs estiment qu'il y a besoin de refactorer pour atteindre l'objectif du Sprint alors il faut refactorer 🔑
💯 D'accord ! Comme dit Kent Beck : First make the change easy, then make the easy change.
💯 Le PO doit fixer le cap : il a pour responsabilités de maximiser la valeur du produit réalisé, de définir et prioriser ce qui doit y être ajouté, et de diffuser le backlog.
Les règles de Scrum sont simples, et c'est peut être pour cela qu'elles sont parfois difficiles à appliquer dans les entreprises compliquées. Elles sont basées sur les principes de transparence, d'inspection et d'adaptation.
La présence de dette dans le code de l'entreprise montre que ces principes n'ont pas toujours été appliqués, au moins jusqu'à aujourd'hui, jour du sprint planning, où le besoin de désendetter se trouve en butte au pilotage fonctionnel du projet.
En effet, si on appliquait toujours au mieux la transparence, l'inspection et l'adaptation, la DT se résorberait presqu'aussitôt créée, à mesure de la progression de l'équipe sur les stories : il suffirait d'ajouter des règles de qualité de code à la DoD, puis de relire ensemble le code, pour se prémunir contre la DT — au moins pour ce qui concerne les gros emprunts.
🚯 Sans jeter Scrum aux orties, ni même le mettre de côté pour toujours, je propose qu'on lise la situation dans l'entreprise telle qu'elle est et non telle que le guide Scrum la voit.
L'entreprise compliquée tire sa culture de modèles qui ont précédé Scrum et qui à mon avis pourraient lui survivre. 🏭 🧬
Dans l'entreprise compliquée :
- le PO ne fait pas partie de l'équipe, il est en face de l'équipe (de développeurs)
- la lecture de code ensemble (afin d'appliquer la DoD) est vue par beaucoup comme une perte de temps
- le Backlog Produit devient la liste des tâches des développeurs; leur activité y est est consignée et tracée (yes, why ? 🤷♂️)
- le PO fixe le cap et s'il estime qu'il y a besoin de ne pas refactorer afin d'atteindre l'objectif du Sprint alors il ne va pas se priver de le dire.
Scrum 🪄 …not.
publié sur LinkedIn le 16/03/2023
Ce n'est pas une question de rôle
La dette, ce n'est pas une question de rôles usurpés.
Un projet = des Développeurs (au sens large que Scrum donne à ce mot), leur Manager, ainsi qu'un P.O. vont pendant plusieurs mois, porter leur attention et concentrer leurs efforts sur 4 systèmes d'idées.
🏛 Le 1er est conceptuel et généralement informel. Les idées y changent rapidement, bien qu'elles soient ancrées dans un langage et des processus souvent éloignés de la Technique. C'est le Domaine Métier.
📱 Le 2d est extrêmement formel, rigide et complexe. C'est une arborescence d'interactions possibles entre des machines et des personnes : le Logiciel.
📐 Le 3ème est un système d'idées techniques très formel, étayé par de nombreux supports : code, tests, scripts, schémas, documents etc. et que nous appellerons : la Conception.
📝 Le 4ème est un ensemble nébuleux, une sorte de "manuel" (mais non documenté) de procédés heuristiques, règles, patterns, ou pratiques que l'équipe adopte et adapte en vue d'atteindre son but. Il est fait de réunions et d'intersections avec d'autres manuels : celui des individus qui composent l'équipe, celui de l'entreprise qui les emploie et/ou celle qui les accueille, et celui de l'Industrie en général. C'est l'État de l'Art du projet.
Domaine Métier, Logiciel, Conception, État de l'Art : tout le travail de l'équipe consiste à opérer, en permanence, entre ces 4 systèmes d'idées, des traductions.
La traduction Domaine ↔ Conception ↔ Logiciel rythme l'activité. L'équipe élabore des traductions qu'elle déploie, ce qui produit des résultats qu'elle réinterprète pour ses traductions suivantes.
🎉 Succès ! On a livré la v.1 ! Le DG a pu acheter un produit ! (Il a des remarques)
→ C'est le résultat de centaines de traductions.
Le terme à la mode pour désigner cette activité est "delivery".
🏛 ↔ 📐 ↔📱 = 📦
Lorsque l'équipe fait évoluer son état de l'art, en empruntant et adaptant de nouveaux procédés, ou bien en le délestant de ceux qu'elle juge inutiles, elle modifie, souvent en profondeur, la façon dont elle va opérer son "delivery".
Dans un projet agile, cette modification se décide souvent à la légère : au détour d'une rétro ou d'un planning meeting, voire devant l'écran.
🙀 On n'aurait pas dû arrêter les revues alors qu'on doublait la taille de l'équipe. Regarde l'état du code ! 💩
→ c'est le résultat d'une décision funeste ayant affecté un grand nombre de traductions.
☞ changement dans la conception = le "delivery" avance 🚚
☞ changement dans l'état de l'art = l'équipe modifie ses procédés 📝 🧯 🪜 🗺
Lorsqu'un changement incohérent affecte la conception, les conséquences sont immédiates (merci l'agile!) : bad smells, bugs, adhérences, questions, retours. 🕳 🚧 🚚
Lorsqu'un changement concerne l'état de l'art, les conséquences se feront sentir… plus tard. 🤸 🕳
Faute de conséquences immédiates, au lieu de raisonner, l'équipe fait des rationalisations. 🙃 C'est là que la dette s'installe.
Ce n'est pas une question de rôle.
publié sur LinkedIn le 17/03/2023
Plateaux
- Le Projet de Dorian Gray
- L'idéal ?
- Fatalités ?
- Ralentir : Crise
- Nouveaux Plateaux 🌄
- Sens Partagé
- État de l'Art
- Plateformes
- Amélioration Continue
- Engagements
Le Projet de Dorian Gray
Une personne utilise une cafetière moka pour la première fois, rate son café, comprend son erreur, et recommence, avec succès. Ensuite, elle ne rate plus un seul café réalisé à l'aide de cette technique. ☕️
Une organisation lance un projet, rate le projet, comprend son erreur, et recommence, sans succès. Ensuite elle continue de rater et de recommencer projet après projet. 🚧🕳
☕️ D'un côté un problème particulièrement simple impliquant l'usage d'un état de l'art stabilisé depuis 90 ans dans un contexte routinier.
🚧🕳 De l'autre une situation complexe et récurrente impliquant un état de l'art nébuleux, pour partie en évolution, pour partie controversé, des objectifs ouverts à la discussion, un contexte incertain.
Le point commun à ces deux activités ? (Si, si il y en a un 😅) : elles possèdent un état de l'art. Le barista génial et l'organisation apprenante peuvent, si vous leur accordez 1 heure d'un côté et quelques jours de l'autre, présenter au moins de manière synthétique les procédés heuristiques, les principes, les technologies et les pratiques qu'ils utilisent.
Parmi les nombreuses différences (de nature, de finalité, de dimension) entre ces deux situations, certaines méritent peut être une mise en exergue. Après tout je ne serai ni le premier ni le dernier dans ce métier à fouler aux pieds le proverbe "Comparaison n'est pas raison". En méthodologie de projet comme en toutes choses, il faut un peu flâner, non ?🚶🏻♂️
La première chose que l'équipe de développement pourrait envier au barista, c'est l'unité de lieu, de temps et d'action, c'est à dire en somme l'autonomie. Si on lui demandait ce qui fait l'excellence d'un café, il pourrait commencer sa réponse (et sa carrière de consultant caféologue) par "ça dépend…", mais on finirait par obtenir une liste de critères univoques. Même alors que le goût est affaire de subjectivité.
Dans l'entreprise, où règnent pourtant la mesure objective et les résultats chiffrés, si on demande à un groupe ce qui fait (ou ferait) l'excellence de leur projet, les réponses ont de grandes chance de varier selon qu'on considère
- la phase du projet
- le rôle des acteurs interrogés
- leur parcours individuel
- le niveau d'information à leur portée
- le degré de consensus établi lors du cadrage initial
- la continuité de ce consensus au fur et à mesure que le projet traverse les épreuves
À ce titre, il est surprenant qu'un projet qui a finalisé son cadrage le 15 Janvier dans un état de cohérence sans accroc se retrouve le 15 Juin en rétro à énumérer tout ce qui a dérivé, divergé, s'est dégradé.
Le retard est le symptôme universel des problèmes de qualité : c'est un marqueur simple et facile d'accès. Si en plus de le tracer, on pouvait tirer la photo de l'état de l'art du projet jour après jour, on comprendrait sans doute mieux ce phénomène de perte de cohérence.
Si ça se trouve, certains projets nous réserveraient des surprises édifiantes !
😱
publié sur LinkedIn le 20/03/2023
L'idéal ?
Dans un processus de développement idéal, chacun piocherait une user story dans la pile des US à réaliser, réaliserait toutes les tâches attachées à cette US dans les temps estimés, poserait cette US sur la pile des US à valider, piocherait la story suivante etc.
L'idéal ? Peut-être. Le rêve, non. Le cauchemar, oui.
À moins que votre projet ne consiste à poser aux développeurs des exercices pédagogiques ou des puzzles de type Advent of Code, s'il se déroule de cette manière il court à sa perte.
Un modèle de processus, c'est un diagramme. Un dessin schématique dont le sens peut se résumer à : "tu vois ce que je veux dire". Un tel diagramme existe peut-être pour votre projet. Si ce diagramme a été tracé après 2005, il contient probablement une boucle, sous la forme d'une flèche qui remonte le temps, de la droite vers la gauche, en "sautant" au dessus de la flèche qui achemine des boites de la gauche vers la droite.
Non seulement aucun·e développeur·se n'a besoin d'un tel diagramme pour comprendre l'essentiel de ce qui va se dérouler durant le projet, mais en plus l'idée qu'on cherche à défendre ici est erronée. Certes le processus se déroule et pousse ses stories vers la production comme un fleuve charrie des boites vers la mer, mais nous ne nous baignons jamais dans le même fleuve.
🏞
Puisque le projet consiste à réaliser un système, il faut bien que le diagramme s'efface pour laisser place au réel.
Entre parenthèses, c'est là que le rôle du coach prend tout son sens. Le coach est justement la personne susceptible d'aider l'équipe à traiter le réel pendant qu'elle apprend à faire …du Scrum. (D'où le nom "Scrum Master"… 🤔 oui, bon, bref).
Quand au réel, il se charge de former l'équipe (et de la déformer aussi).
— la story qu'on a validé il y a 2 semaines ? Elle buggue.
— la story qu'on avait estimé à 3 points ? C'est plutôt 21.
— le système de points au fait ? On s'en passerait bien.
— oui bien sûr, le nouveau "fait des tests". À coup de System.out.println
— binômer ? Si ça vous amuse. Quand à moi j'aimerais mieux pas.
— oui mais en binômant on produit du code plus propre.
— et plus fiable aussi. Mais le PO dit qu'on crame deux fois plus de budget…
— depuis qu'on fait cela, on résoud plus vite nos différends sur le code
— au moins il y a un standard, avant ce n'était pas le cas
— c'est clair : il faut changer de binôme souvent. C'est mieux.
— le Sponsor nous a félicité dis donc ! Vive le pair programming ?
— pas dit qu'en codant chacun en solo on aurait pas mieux fait.
À mesure que l'équipe se coltine le réel, son état de l'art, ce recueil théorique de recettes et de principes qui ne prend forme concrète que lorsqu'une discussion y fait appel, suit la longue pente descendante de la dette. Une pente entrecoupée — si l'équipe prend le réel par les cornes au lieu de s'en cacher ou de le maudire — de changements de plateau spectaculaires.
🧗🏼♀️
publié sur LinkedIn le 21/03/2023
Fatalités ?
Merci Cédric Crevier pour ta contribution à cette conversation ! Le paradoxe d'un projet correctement cadré qui perd de sa cohérence en cours de réalisation peut en effet s'expliquer facilement si l'on prend ton hypothèse (fréquemment observée) des incitations perverses (c'est à dire au fond des politiques détournées de leur but) :
👉 prendre des décisions hâtives ou irresponsables dont on fera porter la responsabilité aux prestataires
🪣 créer de la dette technique que l'on n'aura jamais à "nettoyer"
🐔 ne jamais être le premier partenaire à annoncer un retard (a.k.a "Chicken Planning")
🧳 quitter ses responsabilités pour un salaire moins ingrat…
Si ces comportements se vérifiaient toujours (je ne le crois pas), cela signifierait que tout projet de développement perd nécessairement de sa cohérence au fur et à mesure de sa réalisation, pour des raisons extrinsèques au projet lui-même : à savoir qu'une entreprise ne constitue pas un environnement suffisamment stable et intègre pour mener des développements complexes.
🏢🧩🤔
Cela signifierait également que la perspective de réussir un projet (en termes de retombées sonnantes et trébuchantes, mais aussi en termes d'image, ou de fierté personnelle et interpersonnelle) n'est jamais suffisante pour contrer les incitations perverses. Nous retrouvons à nouveau le problème du prisonnier. Les règles apparentes ainsi que la connaissance du projet (établie lors du cadrage) suggèrent de ne jamais jouer "collectif", ou du moins pas jusqu'au bout : au fur et à mesure que le projet se réalise, qu'il gagne en complexité, donc en difficulté, les différents acteurs cèdent à l'incitation, et se "désistent" du collectif.
Pour répondre à ce problème il faudrait alors expérimenter des contre-mesures qui rendent ces incitations caduques :
✋ décourager le blâme (et la tolérance au blâme) en pratiquant une communication congruente à tous les niveaux du projet sinon de l'entreprise
📝 faire de l'état de l'art du projet une responsabilité partagée et créer les rituels permettant de l'expliciter, et donc de maintenir sa cohérence
🍐 éliminer le chicken planning en dotant l'ensemble des partenaires d'un buffer collectif partagé, permettant d'encaisser les aléas au lieu de se couvrir en mentant par omission
🏷 établir une grille de salaires attractive et cohérente avec le marché
Tout un programme ! C'est très ambitieux, mais au moins nous savons ce que nous pourrions essayer s'il était avéré que tout projet subit nécessairement la loi des incitations perverses.
Or je crois que ce phénomène n'est pas une fatalité.
Pour ce qui concerne l'acteur Technique, je sais d'expérience que dans ce domaine que chacun·e vient au travail avec le désir d'apprendre, de partager du sens, et de réussir des projets. Ce n'est certes pas suffisant, mais c'est un bon début !
publié sur LinkedIn le 22/03/2023
Ralentir : Crise
🔥 Dans un projet en crise on a généralement très peu de marges de manœuvre. 🚒
Il faut parer au plus pressé, "sauver les meubles" comme on dit.
Il arrive souvent qu'on annule certains rituels, qu'on oublie temporairement une ou deux pratiques. Et si vous étiez en phase d'acquisition d'une nouvelle technique (peut-être justement celle qu'on avait décidé d'essayer afin d'éviter la crise), vous pouvez oublier l'idée.
🔌
Au fait qu'est-ce qu'un projet en crise ? C'est un projet dont l'existence est menacée. Le Métier parle de le débrancher. Ou bien des personnes clés démissionnent. La menace n'a pas besoin d'être réelle pour installer la crise. Il suffit déjà qu'elle pointe seulement, pour que les acteurs, qui s'étaient jusque là aventurés sur une glace somme toute assez fine, retournent rapidement à des positions de sécurité.
Le développement de logiciel est un processus de traduction. Il repose en grande partie sur la capacité et la motivation de chaque membre de l'équipe à apprendre.
Rappelez-vous un moment de votre carrière où votre responsable, votre collègue ou votre mentor, constatant votre difficulté face à des notions ou des tâches nouvelles pour vous, vous a dit :
— Bon eh bien c'est pas grave, tu vas apprendre… 🪑
Cet encouragement élémentaire, c'était une tentative de rétablir ou de créer autour de vous et en vous la capacité et la motivation pour apprendre. En temps normal, ça marche plutôt bien.
En temps de crise, le mentor, le collègue ou le responsable ne sont plus là. Ils sont occupés à une autre voie d'eau que celle que vous gérez. 🪣
Alors le projet, ou la situation, le réel enfin, vous chuchote à l'oreille :
— C'est grave. Et tu as l'air complètement perdu. Ce n'est pourtant pas le moment. 🚪
Quand la crise menace, ce qu'il faudrait c'est que l'équipe ralentisse, et qu'elle procède avec prudence, patience et respect mutuel, au désarmoçage de cette crise. 💣
Comment ? En examinant et en réajustant son état de l'art. Car en fait un développement en crise, c'est bien évidemment un développement dont l'état de l'art est en crise. C'est à dire :
🗺 dont les objectifs ou le contexte ont soudain changé
et/ou
🪜 qui n'était simplement pas adapté à la complexité du projet
et/ou
🧯 que l'on a délesté de certaines pratiques essentielles à la réussite de ce projet
Or bien souvent que fait une équipe dont le projet est en crise ? Elle déleste encore son état de l'art. Elle prend ce livre de recette incomplet et controversé, et elle en arrache quelques pages supplémentaires.
Après tout les seules activités que vous ne pouvez pas ne pas faire dans un développement, c'est écrire le code, et corriger les défauts. Tout le reste est dispensable.
🗑
NB: par "équipe" il faut entendre un groupe cohérent formé par 3 acteurs : Métier, Technique, et Management. Si l'un des acteurs décline ou se désiste, vous n'avez pas une équipe. (Mais vous aurez sans doute bientôt une crise).
publié sur LinkedIn le 23/03/2023
Nouveaux Plateaux 🌄
J'ai utilisé TDD pour la 1ère fois en 2001, sur un projet en crise. 🤸
Le chef de projet, un consultant indépendant dont le contrat avait pris fin à l'avant-veille de la recette, avait fait un fait un bon travail de coordination, de négociation (c'était un projet réalisé au forfait) et de reporting.
Il s'agissait de la "refonte iso-fonctionnelle" d'une application de gestion, dont le code FoxPro devait être converti en Delphi. Aucun projet dit de "refonte iso-fonctionnelle" ne tient réellement debout, mais celui-ci était particulièrement acrobatique :
🌞🌚 Windows et Dos, c'est le jour et la nuit
😛 volume de la documentation fonctionnelle : ∅
😨 pas de phase de rétro-analyse, ni de spécification
Dixit le client 6 mois plus tôt : pourquoi spécifier, quand on dispose du code ?
Il avait ajouté : en fait on va même la réécrire ISO-bug.😉
C'est à dire : mot pour mot, feature pour feature, au bug près.
Une prédiction pour le moins optimiste. La recette dura 12 semaines (au lieu des 2 prévues dans le "Plan d'Assurance Qualité" du projet) durant lesquelles le Maître d'Ouvrage identifia environ 450 anomalies.
Bien sûr, beaucoup de défauts prenaient leur source dans l'absence de spécification des fonctionnalités concernées, et ma société ne manquait pas de le souligner en comité de projet.
🤺 Pendant que les commerciaux croisaient le fer à propos des pénalités de retard, les développeurs luttaient avec le monstre qu'ils avaient créé. 🤺
À mon arrivée, je leur demandai :
— Vous faites des tests unitaires ?
— Jamais entendu parler. C'est quoi ?
Ensuite l'état de l'art évolua :
➕ débogage en binômes
➕ assertions dans le code pour valider des hypothèses de débogage
➖ fin des system.print
dans le code
➕ isolement des assertions dans leur propre modules a.k.a "suites de tests"
➕ refactoring du code une fois celui-ci couvert
➕ réécriture de certains modules en TDD le cas échéant
➕ Maître d'Ouvrage présent dans l'espace de travail 3 jours sur 5
➖ fin du remplissage des PV de tests unitaires
Ce dernier point mérite une explication. La méthodologie des forfaits incluait la production de nombreux documents, dont un formulaire papier sur lequel on devait consigner tous nos TUs:
nom du TU | date de passage du TU | résultat (OK/KO) | signature du développeur
✍︎
Un jour le responsable de la Direction Qualité (la même DQ qui avait émis le fameux Guide des Projets en C), passe inspecter notre "qualité structurelle".
— Je peux voir les PVs de tests unitaires signés ?
Je lui montrai notre suite de tests dUnit. Un clic et la barre verte dévalait 150 tests en 5 secondes. Je lui expliquai en quoi ça consistait.
— OK. Mais je vois pas vos feuilles de TU signées.
— Si on imprime une copie de cet écran, ça passe ?
— Bah non.
Signe que votre état de l'art évolue vers un nouveau plateau : certains de ses procédés deviennent obsolètes.
publié sur LinkedIn le 24/03/2023
Sens Partagé
— Je ne sais pas vraiment quoi penser de ton travail, dit ce manager à ce développeur.
— Je traite les demandes dans les temps…
— Oui, bien sûr. Mais je vois aussi qu'à 17h30 tu n'es plus à ton poste. Tu ne prends plus de message.
— …
— Prends le reste de l'équipe : à 19h ils sont encore là pour la plupart. Parfois 20h. La dernière fois je leur ai même commandé des pizzas.
— Peut être que s'ils utilisaient la même méthode que moi ils ne feraient pas ces horaires…
— Ce n'est pas une question de méthode. J'attends de l'engagement de la part des développeurs, tu comprends. Avec toi je ne vois pas d'engagement. Tu fais ta journée, oui, bon d'accord. Ça ne va pas plus loin.
⏹
☞ Une équipe peut faire progresser son état de l'art jusqu'à un nouveau plateau si elle fait équipe, justement. À cette condition, c'est déjà remarquable. En dehors, c'est quasi impossible.
Le contexte de cette conversation (qui a eu lieu il y a 20 ans) est le suivant :
Un développeur — appelons-le Victor — a récemment adopté une démarche de développement "piloté par les tests" qui lui permet de construire avec confiance les stories dont il a la charge.👨💻
L'équipe dont il fait partie est aux prises avec un projet moyennement complexe, qui prend du retard, et des retours du Client.🌩
Victor a tenté de persuader l'équipe d'essayer sa démarche. Il est nouveau dans cette entreprise, où la règle quand on est en retard, c'est de mettre les bouchées doubles, pas d'essayer des nouvelles démarches. 🚑🚒🚓🚨
Victor a essuyé un refus, et il en a pris son parti. Pas facile, une fois que l'on a optimisé un tant soit peu son état de l'art, d'accepter de sacrifier de son temps personnel au nom d'un état de l'art sub-optimal. 🤷♂️
Bref, on est en retard, le Client fulmine, et le Manager semble à deux pas de commettre une erreur de jugement critique pour Victor, pour l'équipe, et pour le projet.
Cette équipe aurait besoin de porter un regard lucide sur son état de l'art, et de commencer à chercher de quoi l'améliorer. 🗺🪜🧯
Mais de quelle équipe parle t'on ? De l'équipe formée par la Technique, le Métier et le Management, bien sûr. Un groupe d'acteurs aux objectifs distincts mais complémentaires :
🧑🏻🏫 La Technique veut apprendre : le Métier lui en donne occasion sur occasion. Le Management fournit les moyens.
💶 Le Métier veut réaliser de la valeur : la Technique et le Management se mettent au service de cette valeur.
👨💼 La Technique et le Client épousent volontiers le processus mis en place par le Management.
Ces 3 acteurs doivent former une équipe afin de traduire au mieux un système d'idées vers une solution informatique.
Dans la situation de Victor cependant, il n'y avait pas une telle équipe.
Il y avait des développeurs, un manager, un client, séparés par des barrières de communication. Il manquait par conséquent l'élément sans lequel tout état de l'art stagne ou régresse, et grâce auquel il peut évoluer : le sens partagé. 🗺
publié sur LinkedIn le 27/03/2023
État de l'Art
Pour documenter l'état de l'art complet d'une équipe à un instant t, il faudrait produire :
-
la base de code ainsi que l'ensemble des modèles de données et de flux et leur historique
-
une référence des librairies, frameworks, langages, algorithmes, paradigmes, processus, et stratégies utilisés par l'équipe
-
une transcription des conversations qui ont structuré jusqu'ici l'état de l'art et son évolution
Il faudrait ajouter à cela les objectifs ainsi que le contexte du projet, sans lesquels la liste qui précède perd une partie de son intelligibilité.
Se poserait également la question d'inclure ou non des éléments de l'état de l'art du Métier pour lequel le projet existe.
🗺🪜🧯
C'est une tâche ingrate et coûteuse. Aucune équipe ne décrit son état de l'art de manière exhaustive : ce serait comme lancer un deuxième projet à côté du premier.
À la place de la Documentation Idéale de son état de l'art, c'est la Documentation Réelle que l'équipe utilise : c'est à dire une documentation fragmentaire, imparfaite, vivante (au sens de Living Documentation si l'on veut), adéquate à l'instant t pour la décision qui est à prendre.
Même si l'état de l'art n'est pas matérialisable à l'instant t, sa réalité est absolument indiscutable pour l'équipe. Toute équipe travaille simultanément sur la conception de son système et sur l'état de l'art qui la guide.
Voici un exemple.
Equipe A :
— Est-ce que je peux te demander où est-ce que le code nous emmène avec ces if
imbriqués et ces compteurs ?
— Bien sûr. Tu te rappelles que le formulaire d'inscription inclut des contrôles tarabiscotés sur la composition du mot de passe. Attends, je cherche la règle précise…
— Il doit y avoir un meilleur moyen de faire ça…
🤔
Equipe B :
— Le formulaire d'inscription inclut des contrôles tarabiscotés sur la composition du mot de passe, dis-donc.
— Je sais. Utilise une Expression Régulière. Il y a une fonction match
qui devrait faire l'affaire.
— Tu connais le proverbe : j'ai un problème; je décide je prendre une RegExp…
— …maintenant j'ai deux problèmes, je sais. Mais là, il y a pas de question.
😎
L'équipe A est en passe de découvrir une nouvelle recette qu'elle va discuter puis ajouter à son état de l'art.
L'équipe B applique une vieille recette, puisée mécaniquement dans son état de l'art. Elle va aussi discuter afin d'améliorer celui-ci, mais sur d'autres sujets que les Expressions Régulières.
Chaque équipe alimente son état de l'art parce que sa vocation est d'apprendre, et que son travail consiste précisément à conquérir des complexités jusque là inconnues pour elle. 📈
Pourquoi partir à la conquête des complexités inconnues ? Parce que si vous ne le faites pas, votre projet sera en retard. Un projet, pour la Technique, c'est un pari contre de la complexité inconnue.
Stay Tuned !
publié sur LinkedIn le 28/03/2023
Plateformes
Il est impossible de vraiment "représenter" un état de l'art. Au prix d'une réduction de ses multiples dimensions cependant, on peut tenter de le mettre en diagrammes, un peu comme on le mettrait en boite. 🔲
Par exemple une carte de Wardley représente partiellement l'état de l'art d'une solution technologique sur 2 axes : nécessité fin/moyens et industrialisation.
Une autre carte pourrait classer les procédés qui composent un état de l'art selon leur efficience, avec en abscisse le coût d'acquisition du procédé par l'équipe, en ordonnée le temps moyen entre deux défaillances du système en production.
Presque tout en bas à gauche de ce diagramme on trouverait les tests de non régression déroulés manuellement. Très loin en haut à droite, les méthodes formelles.
Lorsqu'une équipe ajoute à son état de l'art des procédés qui lui permettent d'améliorer la fiabilité et la facilité de changement de sa conception, on peut dire que cette équipe "change de plateau" de qualité, bien que cette notion d'altitude implique une réduction dans la représentation. 📈
Lorsqu'une équipe améliore continuellement et avec cohérence son état de l'art, celui-ci devient une "plateforme", c'est à dire un plateau duquel il est moins facile de redescendre.
Exemple :
Une équipe adopte TDD. Pour un temps (et au prix d'un effort d'acquisition) elle passe à un nouveau plateau :
🄰 des tests qui décrivent le comportement du code vu depuis ses appelants
🄱 une détection et un diagnostic rapide des régressions
🄰 ×🄱 l'équipe accroît sa capacité de refactoring
Une autre équipe adopte le pair programming (avec rotation fréquente). Après un effort d'acquisition elle passe également à un nouveau plateau :
🄲 en binôme on détecte plus rapidement les défauts (de logique ou de conception)
🄳 chaque idée doit être exprimée à mon binôme pour être implémentée
🄲 ×🄳 l'équipe obtient une conception plus cohérente et un code plus expressif plus rapidement
Si une équipe adopte seulement TDD ou seulement PP, le risque d'abandon est plus élevé. (Ces pratiques demandent …de la pratique 🤓). La retombée du plateau n'est pas loin. 📉
Quand une équipe adopte à la fois TDD et PP son état de l'art devient une plateforme :
🄰 ×🄲 mon binôme détecte mes "rechutes" et m'aide à revenir au cycle TDD 🔺✅🔷
🄰 ×🄳 j'exprime une idée à mon binôme sous la forme d'un test
🄱 ×🄲 mon binôme détecte les défauts subtils, les tests détectent les bourdes
🄱 ×🄳 l'équipe passe moins de temps sur les bourdes et plus de temps sur le design
Après 6 semaines d'un tel régime, toute l'équipe connaît, comprend et s'aligne sur l'ensemble du code du projet (et ses membres peuvent alors revendiquer l'appellation "full stack".)
Kent Beck fait remarquer à propos des pratiques XP qu'elles se renforcent mutuellement. C'est en quoi l'état de l'art XP constitue une plateforme particulièrement solide. 🗺🪜🧯
publié sur LinkedIn le 29/03/2023
Amélioration Continue
Merci Andrea Chiou pour ta contribution à cette conversation ainsi que pour ces questions concrètes à propos d'améliorations de l'état de l'art d'une équipe.
❓ Qu'est-ce qu'une entreprise perdrait en essayant de construire sa plateforme ? Nous pouvons clairement voir dans tes posts ce qu'elles gagneraient. Quel serait l'investissement ?
En un mot : du temps.
À objectif et contexte constants, toute amélioration de l'état de l'art a pour effet de réduire le temps de résolution d'un problème. Cette évolution requiert cependant un temps d'arrêt dans l'activité en vue d'acquérir et d'ancrer l'amélioration en question.
Exemple :
L'achat d'une visseuse électrique m'aidera à monter mes prochains meubles plus vite. 🪛
➕ temps gagné par vis : 30 secondes ⏱
➕ temps moyen gagné par meuble : 10 minutes ⏲
➖ temps investi à essayer les fonctions de la visseuse : 5 minutes 🎛
➖ temps investi à maîtriser la puissance de la visseuse en ratant 1 ou 2 vissages : 2 minutes. 🗑
❓ Tu mentionnes un délai de six semaines pour obtenir des résultats. Qu'est-ce qu'ils font ou ne font pas pendant ces six semaines qui empêcherait une entreprise d'essayer ces améliorations ?
DO's
✅ expérimenter les pratiques en vue de les valider, de les adapter s'il le faut, et de les ancrer dans l'état de l'art
DON'Ts
❌ "tâter l'eau" par ci par là en essayant les pratiques sur du temps hors projet
❌ s'imposer une pratique nouvelle sans l'avoir préalablement expérimentée
❌ expérimenter la pratique sur autre chose que le projet en cours
Reprenons l'exemple d'une équipe qui considère TDD et Pair Programming : elle souhaite déterminer si ces pratiques très éloignées de son état de l'art actuel sont applicables sur son projet, et avec quels avantages.📐🔍⏱
Il ne s'agit pas ici de flâner sur le Net ou les livres et de "regarder si ça convient". Cette approche là, qui nous permet d'essayer une technique pour quelques minutes pendant la pause déjeuner ou sur notre temps de repos, est tout à fait valide pour faire sa veille personnelle, mais elle ne peut pas conduire à un changement de pratique dans l'équipe.
Essayer par soi-même une pratique sur du temps personnel, cela ne revient pas à expérimenter. Or sans expérimentation, une équipe, et a fortiori une entreprise, ne peut pas valider un changement de pratique, quelqu'il soit. 🕳🚶🏻♂️
✅ Pour expérimenter, il faut procéder en 4 étapes :
1️⃣ faire un plan, c'est à dire une hypothèse (on pourra dire que la pratique améliore la situation si on constate … à la date du …) 📃
2️⃣ réaliser le plan, en l'adaptant à la réalité du terrain 👩🏽💻
3️⃣ valider ou infirmer l'hypothèse 🔍
4️⃣ documenter la décision, la pratique, et ses adaptations 📝
La réponse à ta question suivante dépend énormément du contexte. Elle nécessite un post à part !
Stay Tuned !
(…)
publié sur LinkedIn le 30/03/2023
Engagements
Il arrive qu'une équipe (Technique + Métier + Management) améliore son état de l'art au point qu'elle en fait une "plateforme". 🌉
Une plateforme s'obtient par une série (parfois longue) de changements de "plateau".
Un changement de plateau s'opère lorsqu'une pratique (ou procédé, ou recette, ou pattern) permet de réduire un obstacle au point de le rendre insignifiant.
Les erreurs de logique que j'insère sans m'en rendre compte dans du code que je ne testerai qu'en fin de sprint pourraient fort bien demander entre 1h et 4h à corriger au sprint suivant. 🔥
Dans du code que je construit en TDD, mon erreur de logique est détectée au prochain passage des tests, dans 5 minutes.🧯
Appliquée à bon escient dans le bon contexte, TDD constitue un plateau.
Une "plateforme" apparaît lorsque plusieurs pratiques se renforcent mutuellement dans un état de l'art, i.e une pratique élimine un obstacle qui empêchait le renforcement d'une autre pratique, et vice versa. 🔄
Par exemple le pair programming (ou à défaut la relecture de code) renforce ma pratique naissante de TDD dans la mesure où mon binôme peut m'aider à détecter et reprendre les gestes qui me sortent du cycle red-green-refactor 🚦
En retour TDD aide à produire du code fiable, ce qui rend les sessions de PP plus intéressantes : on y travaille le design au lieu de corriger des bugs. 📐
TDD + PP forment une plateforme. 🌉
Andrea Chiou à propos d'une équipe se créant une plateforme, tu posais cette question très directe :
❓ Si l'on te demandait de l'aide, quel serait ton engagement ?
Chaque contexte est différent. Une promesse très réaliste dans un contexte, peut devenir déraisonnable dans un autre contexte, et dans un autre, insignifiante. 😅
Néanmoins, pour aider une équipe à se créer des plateformes, je pense qu'il faut chercher à s'engager comme suit :
-
avant tout enquêter sur l'état de l'art existant pour l'équipe dans son contexte 🎤
-
aider l'équipe à identifier des procédés standards qu'elle a pu adapter et/ou renommer 🔎
-
ne pas injecter dans cette enquête nos propres standards, nos préférences ou nos dogmes 🤫
-
apprendre de l'équipe ce qui fonctionne pour elle, et ce qu'elle souhaiterait améliorer en priorité 🪜
-
ne pas passer sous silence une incohérence, une contradiction ou un conflit possible dans l'état de l'art 🤔
-
évaluer et aider à évaluer des décisions passées sans juger leurs auteurs 🚯
-
faire une appréciation critique de la situation, et une appréciation généreuse des personnes qui vivent cette situation 🦒
-
ne pas douter de l'équipe ni de sa capacité à améliorer son état de l'art 💪
-
proposer des expérimentations et non des changements ou des transformations 🗺🪜🧯
-
se rappeler que l'équipe = [Technique + Métier + Management] 🤝 🤝 🤝
-
cultiver une curiosité insatiable pour la façon dont les personnes peuvent résoudre des problèmes complexes ensemble 🌃🛰🌉
publié sur LinkedIn le 31/03/2023
Producteurs
- Cavalcade
- Travailler tard avant d'être remplacé
- J'ai un mystère
- Producteurs de Code
- Software Factory
- Etat de l'Art et Nouveauté
- Nouvelles Conversations
- Productivité
- Amélioration Continue
- Soirée Meetup
Cavalcade
♔♕♟♗ Jusqu'à la fin de la partie, les observateurs se sont tus. Puis ils commentent :
— Cet échange de fous, c'était une erreur. Il valait mieux tenir le centre.
— J'avais un pion d'avance. J'aurais pu gagner !
— Avec quel plan ?
— Justement ! Je n'avais pas de plan. Et pas de temps non plus. C'est pour cela qu'il fallait simplifier.
Les échecs et le développement de logiciel ont au moins ceci en commun : ils nous mettent face à une montagne de complexité, à appréhender en un temps limité. Souvent cette limite de temps fait de la montagne un véritable mur. D'où l'expression : "aller dans le mur".
⛰
Un état de l'art inadapté ou désaligné, c'est un projet de développement qui va bientôt se trouver en retard, et qui pourrait bien aller dans le mur.
Par définition l'état de l'art rassemble les procédés, recettes, patterns, pratiques qui permettent de résoudre un problème dans un contexte donné en un minimum de temps. Par exemple si une équipe a dans son état de l'art la pratique des tests d'intégration automatisés, c'est parce qu'elle sait que cette pratique est le moyen le plus rapide d'atteindre certains objectifs de qualité, toutes choses égales par ailleurs. Supprimez les TIs autos, tout en maintenant l'objectif, et l'équipe vous opposera un délai supplémentaire. 🗓
protip ☞ lorsqu'une équipe retire de son état de l'art une pratique de prévention des défauts tout en se promettant de tenir ses délais, c'est qu'elle vient subrepticement et implicitement de changer les objectifs du projet.
De même qu'il est impossible à un joueur de se mettre à étudier les problèmes de milieu de partie alors qu'une partie est en cours et que la pendule tourne, il est très difficile pour une équipe en retard d'acquérir de nouvelles pratiques en vue de les ajouter à son état de l'art. L'état de l'art est certes rempli de recettes pour aller plus vite, mais l'acquisition de ces recettes demande du temps.
Au début du projet, l'équipe n'a pas le temps d'améliorer ses pratiques :
- celles ci ne sont pas (encore) remises en question
- sa roadmap chiffrée au plus juste lui permet tout juste de caser les fonctions demandées
Au milieu du projet, l'équipe n'a pas plus le temps d'améliorer ses pratiques :
- sa stratégie l'a mise en retard
- elle "sauve les meubles" : apprendre est devenu un luxe
Au lieu d'évoluer de plateau en plateau, l'équipe dévale une pente fatale. Pour peu qu'elle remplace une date manquée par une date tout aussi intenable, elle court sans répit. Ses chances d'améliorer son état de l'art sont donc battues en brêche.
protip ☞ le cadrage d'un projet est le meilleur moment pour inventorier l'état de l'art de l'équipe.
PS: Chez CodeWorks nous avons même un atelier qui permet de faire cet inventaire.
publié sur Linked In le 04/04/2023
Travailler tard avant d'être remplacé
Dans certaines entreprises, en l'absence d'extincteurs, on promulgue l'interdiction des incendies.
On déclare : L'échec n'est pas une option !
📜📯
Si l'on met de côté quelques incendies spectaculaires, cet état de fait n'empêche pas ces entreprises de bien se porter. L'informatique, pardon, le digital, est une manne prodigieuse. Lorsque le traitement en masse de données simples s'effectue 60 millions de fois plus vite avec un ordinateur qu'avec des personnes, l'industrie peut tolérer une grande marge d'erreurs, de défauts, de projets en échec, et d'entreprises en recul.
La fameuse "crise du logiciel" (qu'il faudrait renommer "la crise de l'idée que nous nous faisions du logiciel") n'en était pas une, dans le sens où l'existence de cette activité n'a jamais été menacée par les problèmes de qualité.
En développement de logiciel, il y a du travail. Beaucoup de travail. Un enfant de 6 ans pourrait demander à ses parents informaticiens : si l'ordinateur fait tellement de choses à notre place et tellement plus rapidement, comment se fait-il que vous travailliez si tard ? Et ses parents pourraient dire :
— Je travaille tard, parce qu'il y a plein de bugs.
— Je travaille tard, parce qu'il y a tellement à apprendre.
— Je travaille tard, parce que je suis passionné·e.
Pour être plus justes ils devraient dire :
— Je travaille tard, parce que je me situe du mauvais côté d'un transfert de risques.
🧯🔥
À l'instant même où nous discutons des heures magiques assumées par les développeurs·es qui éteignent des incendies pourtant interdits, une Nème alerte de marketing m'annonce qu'un produit populaire de LLM (par ailleurs génial, et très utile dans son contexte) va provoquer sous peu des suppressions de postes dans le développement de logiciel. 🤖
🪑 Puisqu'on peut se permettre de flâner un peu, à mon tour de monter une minute sur ma chaise pour pérorer : je pense que la seule chose qui va réellement supprimer des postes de développeurs, c'est le réchauffement climatique.
Ce qu'on ferait bien de demander à une IA capable d'écrire (et elle écrit tellement bien, c'est à s'y méprendre) ce n'est pas de produire du code. Du code on en a déjà plein le cloud, merci. On ne sait plus quoi en faire. Il manque du temps pour le relire, et le tester.
💡 Hé, mais… C'est ça qui nous aiderait ! Si ça se trouve…
ToF: j'ai écrit un programme qui calcule les scores au bowling. Quels seraient de bons tests automatisés pour ce programme ?
chatGPT: Félicitations etc, (je vous épargne le babil)… Testez avec un cas de base: Vérifiez que votre programme calcule correctement le score pour une partie complète de bowling, où chaque joueur a lancé 12 boules. … 🤔 Un doute m'a saisi. J'ai demandé : peux-tu écrire un programme en C qui calcule les scores de bowling.
Le résultat va vous couper le souffle.
publié sur Linked In le 05/04/2023
J'ai un mystère
Une équipe de développement modifie un logiciel et lui ajoute des comportements possibles.📲
Certains de ces comportements sont indésirables : l'équipe s'efforce de les extirper du logiciel.🗑
Tout en faisant cela, elle instruit son état de l'art, c'est à dire l'ensemble des recettes qui rendent son activité plus facile dans le contexte qui est le sien.📝
Le tout à l'aide de ressources limitées, avec une information incomplète, et en présence d'incertitudes.
De plus en plus fréquemment maintenant, cette équipe sera interrompue par des observateurs, certains très sérieux, qui lui tiendront à peu près ce langage :
— J'observe que dans votre activité, on écrit du code. Il existe des systèmes LLM qui eux aussi écrivent du code. Bientôt ces systèmes vous remplaceront. 🧐
Parfois ils ajouteront, s'inventant sur-le-champ un diplôme de Licence en Psychologie :
— C'est normal de réagir comme vous le faites pour défendre votre travail. Mais c'est inéluctable.🥸
Le tout à la plus grande joie des chaînes de télévision, des fournisseurs de contenus et autres publicitaires en général.
Dans les années 50, un observateur distrait cherchant son chemin dans les couloirs d'IBM ou bien d'une université aurait pu dire :
— J'observe que dans votre activité, on assemble des instructions en langage machine. Il existe des compilateurs, qui eux aussi assemblent des instructions en langage machine. Bientôt ces systèmes vous remplaceront. 🤖
À quoi on lui aurait répondu, merci pour cette prédiction, tiens, viens voir à t'occupper par là…
La grande différence entre les années 50 et maintenant, c'est que les observateurs distraits se comptent par centaines vu que les réseaux sociaux ont remplacé les couloirs des entreprises et des universités.
🤷♂️
Pour récapituler :
- ajouter des comportements à un logiciel
- en retirer les comportements indésirables
- améliorer l'état de l'art de leur équipe
👩🏽💻
C'est ce que font, si l'on s'abstient de parler technique et de sortir le jargon, les équipes de développement. Certaines de ces équipes ont déjà recours à des outils de type LLM et améliorent ainsi leur efficacité.
Mais qu'est-ce qui dans ces trois activités telles que nous les connaissons, peut nous laisser croire qu'un ordinateur pourra bientôt les réaliser au pied levé, au point de rendre le travail des développeurs obsolète ?
À partir d'un problème (très simple) que je lui décris, une IA peut produire du code plus ou moins proche d'une solution. En raffinant ma description, je peux arriver à lui faire produire un code solide pour un composant (très simple) en peu de temps. C'est fascinant.
Qu'est-ce qui, aussi fascinés soient-ils, pousse des gens — qui ne développent probablement pas — à s'adresser aux développeurs pour leur dire : "pour vous, c'est bientôt fini. La machine va vous remplacer". 🤔🧩❓
publié sur Linked In le 06/04/2023
Producteurs de Code
Merci Amael BERTEAU d'avoir cité Sandro Mancuso :
🎙 Les développeurs qui ne comptent que sur leurs entreprises pour leur fournir des connaissances ne sont pas des développeurs de logiciels professionnels. Ce ne sont que des ouvriers d'usine déguisés.
Merci Stéphane M. d'avoir cité un manager anonyme :
🎤 "Mes développeurs sont là pour produire du code". C'est ce que j'ai entendu d'un manager il y a peu. Un peu comme l'éleveur qui dit "Mes vaches sont là pour produire du lait".
Ces assertions m'intéressent car elles montrent à quel point le modèle mental "développer = produire" est coriace.
Mon propos n'est pas de considérer ici le déclassement des développeurs vers le statut d'ouvrier ( 🤫 🚨 développeur ≠ ouvrier)
mais plutôt l'intention derrière ce cliché, qui est d'envoyer un appel à l'action "Craftsmanship" :
📯 Prenez votre éducation et votre carrière en main
📣 Développez votre savoir-faire vous-même
📡 N'attendez pas que votre entreprise vous aide pour commencer à le faire
Cet appel à l'action, je le trouve…
-
biaisé, spécifiquement, du biais du survivant. A ce type de message il serait bon de toujours ajouter par souci de justesse, un codicille: "En tout cas, c'est ce que moi j'ai fait, et ça a marché pour moi."
-
moralisateur, notamment parce qu'il fait du développement personnel une source de la valeur professionnelle. Celles et ceux qui travaillent tard sur les incendies du boulot, qui aiment se reposer complètement après le travail, ou qui ont simplement une vie chargée d'enfants, de tâches et de soucis tout aussi réels que le problème de la qualité du code n'auront pas la chance de figurer au tableau d'honneur.
-
futile, puisqu'on ne peut acquérir des connaissances que volontairement, que l'entreprise a le devoir de former ses employés, et que la plupart des managers sont parfaitement conscients de la nécessité de fournir des connaissances aux développeurs.
Nous pouvons certes juger que les connaissances fournies sont insuffisantes, obsolètes, inadéquates. En tout état de cause, ça ne signifie pas qu'il nous faut devenir des crafters autodidactes éclairés, codant tard le soir (détrompez-vous, j'adore ça aussi). Il nous faut peut être seulement des managers plus clairvoyants.
Peut être P. Drucker va t'il m'aider à mieux comprendre ce que S. Mancuso voulait dire (si maladroitement) :
📖 the most valuable asset of a 21st-century institution, whether business or non-business, will be its knowledge workers and their productivity.
📖 The knowledge worker cannot be supervised closely or in detail. He can only be helped. But he must direct himself, and he must direct himself towards performance and contribution, that is toward effectiveness.
Pour en revenir à mon point initial :
Même les plus isolés des développeurs les moins éclairés par la lumière du craft (c'est ironique) ne peuvent pas se contenter de "produire du code", car développer ce n'est pas produire, c'est traduire.
Stay Tuned !
publié sur Linked In le 07/04/2023
Software Factory
Dans le vocabulaire des ESN et de leur clients, le mythe de la "software factory" est étrangement tenace. 🏭
Dans une usine, les ouvriers transforment de la matière. Ils fabriquent des pièces, les assemblent. La part d'initiative qui leur revient porte sur l'amélioration de leur efficacité à produire ainsi qu'à détecter et résoudre des problèmes d'exécution. Ces initiatives peuvent servir en retour aux acteurs qui déterminent en amont les objectifs et le processus de fabrication, et de loin en loin la conception du produit. Mais la conception et la valeur du produit ne sont pas ce sur quoi les ouvriers travaillent.
Dans un projet logiciel, les acteurs ne transforment pas de la matière, mais des idées, idées que l'on peut ranger dans 4 groupes distincts :
𝕄 le domaine Métier ℂ la conception 🄾 l'exécutable d'un ordinateur 𝓐 l'état de l'art
Si on n'y regarde pas de près, par ex. si on se contente du journal de 20h ou de twitter pour s'informer, il pourrait sembler que les dévs. travaillent uniquement à la traduction d'idées de ℂ vers 🄾 c'est à dire à produire du code.
🚨 Faux
Ils traduisent aussi des idées de ℂ et 🄾 vers 𝕄, afin de mieux répondre au besoin du Métier, lequel — qui l'eût cru — découvre ses besoins à mesure que ℂ et 🄾 grandissent.
Ils traduisent enfin des idées de ℂ vers 𝓐, de manière à faire de 𝓐 un meilleur guide de travail, plus à même de répondre aux besoins du Management.
Si l'on ne tenait pas compte des considérations Métier (valeur du logiciel) et Management (pérennité du processus) dans le travail des développeurs alors :
- oui, le travail du développeur consisterait seulement à produire du code
- l'entreprise aurait le plus grand mal à tirer de la valeur de ce travail
Le modèle de la software factory, vision mécanique dans laquelle chaque "poste" exécute à son niveau le geste de production qui va bien est naïf et obsolète.
💡 ⇒ ⚙️ ⇒ 📲
Ce modèle "tourne" peut être dans une animation pptx, mais la réalité est différente.
Certaines organisations peuvent déployer en 6 semaines avec 5 personnes le logiciel qui demanderait à d'autres organisation 6 mois et 20 personnes. Si une telle différence est possible, c'est parce que le travail de développeur ne se cantonne pas à produire du code.
Non seulement les développeurs le savent, mais également les responsables Métier, ainsi que le Management de toutes les entreprises qui ont amélioré leur agilité ces 20 dernières années. À moins que cette poursuite de l'agilité ne soit le fruit d'une hallucination collective, elle montre que l'on confie aux développeurs bien plus que la tâche de produire du code.
Pourquoi le mythe de la "software factory" est-il si tenace ? Parce qu'il exprime un désir : celui d'encadrer ce travail complexe qu'est le développement afin de le rendre totalement manageable.
Stay Tuned !
publié sur Linked In le 10/04/2023
Etat de l'Art et Nouveauté
Notre capacité à documenter, améliorer, transmettre, en un mot faire vivre un état de l'art quel qu'il soit n'a jamais été aussi grande.
Elle ne semble dépassée que par notre motivation à remplacer ce que nous construisons le plus rapidement possible.
🏁 🏎 🔥 🚒
10/04/23, 15h40 : Je cherche un exemple qui illustrerait mon assertion nº1. L'exemple qui me vient en tête : les tables de hachage.
10/04/23, 15h42 : J'ai sous les yeux la section References de la page wikipedia "Hash Table". Elle contient 54 liens. 📚🔑💡
Si je choisis mes sources avec discernement, que j'éloigne les distractions, et que je me définis une feuille de route même sommaire…
- en 3 heures je peux savoir de quoi il en retourne
- en 3 jours, je peux savoir d'expérience comment ça fonctionne
- en 3 mois, je peux écrire ma propre librairie
- en 3 ans, je peux développer une expertise exceptionnelle sur le sujet
⌚️ 🕰 🗓
Lors d'une récente présentation à la fin de laquelle je recommandais de lire ces livres :
- Pragmatic Programmers -- D. Thomas et A. Hunt
- Becoming a Technical Leader -- G. Weinberg
- Legacy Code: First Aid Kit -- Nicolas Carlo
un des partipants a lancé :
— excuse moi, mais est-ce qu'il y a encore des gens qui lisent des livres ?
Sur le moment j'ai bafouillé une blague. Mais maintenant que j'y réfléchis : le monde dans lequel nous vivons est basé sur l'écrit comme tu n'as pas idée.
📚📖📓
Mais lire ou écrire des livres : le logiciel en entreprise n'en demande pas tant. Simplement, documenter, améliorer et transmettre un état de l'art serait déjà très bien.
🗺🪜🧯
Toi qui a disons 5 ans d'expérience : combien de temps as-tu passé dans un projet où les pratiques suivantes avaient cours :
- CR des décisions de Cadrage de Projet
- Architecture Decision Record (à jour)
- Document Général d'Architecture (à jour)
- Diagrammes de données, de conception (à jour)
- Documentation d'Exploitation (à jour)
- Tests Fonctionnels autovérifiants (lisibles, à jour)
- Tests autovérifiants (à jour)
- Rapports de Tests exploratoires
- Rapports de Rétro-analyse des incidents
Avant de rejoindre le chœur des récriminations sur l'air de "Ah là là ces développeurs", j'aimerais poser 4 autres questions à propos de ces projets :
- Qui en a construit l'argumentaire technologique ?
- Qui en a défini le calendrier et le budget ?
- Qui s'est assuré que l'état de l'art survivrait après la 1ère livraison ?
- Est-ce que ces 3 acteurs formaient d'après toi une équipe ?
Pour résoudre les problèmes que posent le développement de logiciel en entreprise, il faut des équipes compétentes et résilientes, capables de réparer une conception et de la faire vivre.
Ce que propose avant tout notre industrie c'est de la nouveauté technologique.
"Nouveau ! Dans un monde où la seule constante est le changement… bla, bla, bla…"
🎇🎢🎪
Pas complètement en dehors de la plaque, mais pas loin.🤸🕳
publié sur Linked In le 11/04/2023
Nouvelles Conversations
Il a fallu 2 décennies, et l'amélioration constante des outils d'intégration et de déploiement en continu, pour faire du dialogue entre le Métier et la Technique une réalité quotidienne (ou au moins hebdomadaire) du développement de logiciel dans l'entreprise.
Jadis, entre la "Maîtrise d'Ouvrage" et la "Maîtrise d'Œuvre", on s'écrivait. De l'éclosion d'une idée en réunion de recueil des besoins, à son aboutissement concret dans le comportement d'un ordinateur il pouvait se passer 2 à 3 ans (si tout allait bien). Souvent l'idée était devenue méconnaissable. Parfois c'était une bonne chose. Il fallait s'armer de patience, et de rames de papier A4.
🖨📚🚚
Est-ce la paresse à écrire (spécifier ces cathédrales conceptuelles que sont les logiciels exige du temps, de la rigueur et un sens démesuré du détail), ou bien l'appel de la vitesse, ou simplement une sorte de pragmatisme, toujours est-il que les entreprises, après quelques années de réticences (certaines d'entre elles justifiées, d'autres infondées) ont fini par acquérir, avec des succès éclatants, raisonnables ou mitigés, une forme d'agilité.🧗🏼♀️
Mais voici où le bât blesse : l'agilité règne dans les entreprises (à tout le moins le vocabulaire agile règne), mais la maintenabilité pas encore.
🚧🕳🚧
Il faut la coopération de 3 acteurs pour créer un logiciel utile, fiable et pérenne : le Métier, la Technique, et le Management.
Sans l'acteur Technique, le Métier et le Management s'en sortent avec les logiciels déjà développés (solutions, suites bureautiques). N'oublions pas que le mieux est l'ennemi du bien.
Sans l'acteur Métier (et son aiguillon: la valeur métier), le Management et la Technique créent une expérience, un socle, théoriquement utile dans le futur.
Sans l'acteur Management, la Technique et le Métier créent, parfois à des vitesses vertigineuses, quelque chose qui marche aujourd'hui peut-être, mais qui ne marchera plus demain, lorsqu'il faudra maintenir la chose en question.
Produire du logiciel maintenable demande une discipline et une constance certaines. C'est là que le management intervient. (Par discipline j'entends l'application cohérente d'un ensemble de règles, pas le fait de discipliner les gens avec des fouets managériaux). Maintenir la maintenabilité, cela ne peut être confié à la Technique seule, car la vocation de cet acteur est d'apprendre, pas de maintenir.
C'est là que le dialogue entre la Technique et le Management doit s'installer et s'étendre, afin de créer plus d'environnements où on excelle à créer du logiciel, mais aussi à le réparer. 🗺🪜🧯
Les sujets de conversation qui s'imposent :
- la "dette technique", c'est à dire en fait la place des tests et des revues 🔍
- le turn-over et la culture évanescente de l'entreprise 🎈
- (a contrario) la persistence des choix technologiques dans l'entreprise 🏛
- le marché de la nouveauté technologique et ses chimères 🌠
Stay tuned!
publié sur Linked In le 12/04/2023
Productivité
Victor — appelons-le Victor — est développeur. 🤓
Dans son travail, il trouve toujours des moyens d'aller un peu plus vite. ⏱
Le moyen le plus simple d'aller un peu plus vite consiste à remettre la lenteur à plus tard : reporter à une date ultérieure la résolution d'un problème, au besoin en transférant la responsabilité ou le risque vers un acteur distant ou futur. 🌀
Exemples :
Victor voit qu'il pourrait factoriser son code, ça prendrait 10 minutes et supposerait de lancer les tests… qu'on a pas sur ce module… Un copié-collé, ça passe. 😇
Victor vient de terminer une tâche un peu longue, un morceau de bravoure en vérité, qui optimise la gestion de la persistence. Idéalement, il faudrait qu'il demande une revue, mais les revues, ça prend du temps. Imaginez que ses coéquipiers lui disent qu'il faut tout revoir ! Sans compter les débats interminables sur le design… 🤺
Victor a reçu une demande de changement, à traiter si possible avant la fin du sprint, qui concerne une règle métier à laquelle on n'a pas fait tellement attention jusqu'à présent. À la lecture du ticket, il n'est pas sûr de bien comprendre la règle en question. L'émetteur du ticket n'étant pas disponible au téléphone, Victor a décidé d'implémenter la règle dans son interprétation la plus simple. Après tout c'est un travail supplémentaire, et ce n'est pas comme si le projet était en avance. 🚚
Lorsque Victor et son équipe ont remis la lenteur à plus tard pendant des semaines, voire des mois, ils se retrouvent face à un trop-plein de "lenteur à devoir" accumulée.
La façon dont ce trop-plein se matérialise varie selon les situations, mais en règle générale, on peut dire que la lenteur accumulée devient manifeste lorsque les stratégies habituelles pour l'évacuer, la repousser à plus tard, échouent.
🔥
En adoptant le programme à une demande de changement, l'équipe a oublié un des copiés/collés. La régression ne s'est manifestée que 3 mois après la mise à jour. Il a fallu 2 jours entiers pour corriger le problème.
🔥 🪣
Après des semaines à gérer des urgences, l'équipe a enfin pris le temps de s'intéresser au module réécrit par Victor. Le verdict est sans appel : le code est incompréhensible, non-standard, à réécrire. Compter un mois de travail.
🔥 🚒
Pour ce qui est de la demande de changement implémentée sans consulter le demandeur, ça n'a pas raté : la règle ne convient pas. Un examen complet de la demande aurait montré que celle-ci comportait des incohérences. Maintenant l'application présente un défaut, qu'il faut expliquer, contourner, et corriger en urgence.
🔥 🚒 🚑 🚧 🚓 🎥 📡
Il serait facile, et futile, de blâmer Victor pour son manque de professionalisme. En mode : le problème, c'est Victor. 👻
Autant l'accuser de manquer de chance : Victor n'y peut rien. L'urgence est inscrite dans le process. Les acteurs ne font que s'y adapter.
Comme dit Deming : A bad system will beat a good person every time.
Stay tuned !
publié sur Linked In le 13/04/2023
Amélioration Continue
Hier j'illustrais le fait que pour beaucoup d'équipe de développement, la manière la plus simple et la plus courante de produire plus vite consiste à remettre à plus tard les choses qui prennent du temps. 🐌 🐇
Cette stratégie fonctionne jusqu'au point où l'inévitable arrive : un défaut inattendu s'invite dans votre planning déjà chargé, et immobilise l'équipe pendant un temps considérable.
C'est ce que j'appelle la règle des mauvaises chaussures :
Lorsque vous allez acheter une paire de chaussures, avec l'objectif de dépenser le minimum, il est intéressant de réfléchir au coût que représente le fait de porter de mauvaises chaussures.
🥾🦶
Ou comme le dit le vieux proverbe : Il vaut mieux prévenir que guérir.
Refactoring, Revue de code, Backlog Grooming : ces pratiques sont des exemples de stratégies de prévention des défauts. Les remettre à plus tard, c'est ouvrir tout de suite la porte aux défauts. 🕳
Ce problème étant posé, merci Andrea Chiou pour ton invitation à considérer les alternatives :
🎤 Et oui… c’est le système que beaucoup de développeurs et leurs managers ne voient (ou ne comprennent) pas clairement… si c’était le cas ils rejetteraient cette pression à aller plus vite. Quel serait un autre comportement possible, différent de celui de Victor?
Victor peut toujours prendre son courage à deux mains et essayer de changer ses stratégies personnelles afin d'améliorer son état de l'art et celui de son équipe. Ses chances d'y parvenir sont minimes.
Tout professionnel qu'il soit, Victor ne peut pas changer de lui-même le standard de l'équipe, pour 2 raisons :
-
Ce standard décrit un environnement, un process et des pratiques qui forment un système, et non une sort de bulle qui ne concernerait que Victor
-
Ce système est conçu, aménagé et suivi non par les développeurs seuls mais aussi par leur manager (pour vous en convaincre, essayez pour 10 jours une nouvelle pratique comme TDD, Pair Programming ou Mob Programming et notez ce qui se produit).
Une équipe n'améliore son état de l'art que si le Management joue son rôle au sein de cette équipe : créer, favoriser et supporter une démarche d'amélioration continue.
Le moyen le plus efficace d'aller plus vite, c'est un cycle répété de 4 étapes :
📈 Plan : observer la situation, identifier une contre-mesure, émettre une hypothèse et faire une prédiction à une échéance proche
🚧 Do : mettre en œuvre l'amélioration, en l'ajustant aux imprévus rencontrés
🔍 Check : mesurer le résultat à l'échéance prévue et valider (ou non) la contre-mesure
📝 Act : documenter l'amélioration, et mettre à jour le standard
Hier Anthony Cyrille évoquait la base de code "10x" (et ça donne envie!). Une base de code 10x n'arrive pas par magie, mais par amélioration continue.
C'est à dire grâce au management.
Dans certaines entreprises, le travail du manager consiste uniquement à enseigner cette démarche ! 👀
publié sur Linked In le 14/04/2023
Soirée Meetup
— Non, mais je t'arrête, on a zéro besoin de TDD, DDD, Clean Code pour réussir.
— Non ?
— On est une start-up. C'est pas en pratiquant TDD qu'on va gagner des clients. S'en foutent, les clients, de TDD.
— Quand même : c'est quoi ta stratégie de prévention des défauts ?
— La stratégie, c'est de faire, et vite.
— Et toi tu code plus vite avec les défauts que sans.
— Mais évidemment ! Bien sûr, une fois que j'aurai levé des fonds, mieux, quand le produit fera de l'argent, on aura de quoi refondre en appliquant les bonnes pratiques. On sera stabilisés, tu comprends.
— Ben dans les entreprises bien stables, où on a de quoi, on ne voit pas toujours les bonnes pratiques…
— C'est parce que leur management ne marche pas. Elles n'ont pas l'esprit start-up.
— À mon avis c'est plutôt que là où tu as un petit legacy, si le business marche bien, tu vas avoir en peu de temps un gros legacy.
— Oui mais nous, c'est différent : on aura de quoi embaucher des stars.
— Sur du code legacy ? Elles resteront pas, tes stars. Si je suis au top de mes compétences, qu'est-ce que j'irais mourir sur une colline de legacy, dans une orga dysfonctionnelle ?
— Non mais je te permets pas, notre orga elle sera au top.
— Au top ou pas, corriger un bug urgent en plein week-end, ça va attirer qui ? Des débutants, peut être, pas des devs chevronnés.
— Ça dépend du salaire qu'on leur propose !
— Investir dans des beaux salaires pour gérer du legacy, c'est ton CFO qui va te mettre la pression…
— On leur donnera des marges de manœuvre, qu'est-ce que tu crois.
— Quand ton équipe de stars commencera à ruer dans les brancards, à vouloir mettre le PM sur la touche pour faire plus de prévention des défauts, je crois deviner ce qui va se passer.
— Ah oui ?
— Tu diras : Vous croyez que c'est la prévention des défauts qui nous a emmenés là où on est ?
— …
— Et tu ajouteras : vous êtes cool et tout, mais vous ne comprenez pas la culture ici.
— Eh ben rendez-vous…
— Et sur ce point, tu auras totalement raison.
— J'ai raison ?
— Tu n'as pas besoin d'une bonne stratégie de prévention des défauts, ni de faire du code "propre", du TDD, toussa, pour survivre. Une bonne archi, oui. La scalabilité, à coup sûr. Le reste, non.
— Eh ben voilà, tu commences à comprendre.
— Des devs qui ont envie de rester dans la boîte non plus, ce n'est pas indispensable.
— En vrai, ça non plus.
— Et en plus ça fait marcher l'industrie du service.
— Tu vois bien. Merci qui ?
— Merci les start-ups pour faire marcher l'économie du service sur le code legacy ! C'est quoi ton business au fait ?
— Ça peut encore changer, mais là on met au point un service qu'on a appelé 𝗥𝗲𝘀𝘂𝗺𝗮𝘆! : tu renseignes ton CV, et une liste de références de livres et d'articles. Et le site te fait ta lettre de motivation custom !
— Smart !
— Et en premium, pendant tes interviews, 𝗥𝗲𝘀𝘂𝗺𝗮𝘆! a une IA qui écoute l'interview et t'affiche les réponses à faire basée sur les refs. On va hacker le recrutement !
— À fond !
🚀
publié sur Linked In le 16/04/2023
Régulation
- Interactions
- Prévenir > Guérir
- Crash Fatal
- Cliquets
- Mégapole
- Des usines et du sable
- Apprendre et s'adapter
- Sprints à Rallonges
- Mon Indicateur de Productivité
- Résolution
Interactions
ART (Artful Rhetoric Technics) et BOX (Brave Orators eXpressing) sont deux entreprises en compétition sur le marché du service d'éloquence, i.e la production de discours délivré en présentiel (communication d'entreprise, célébrations, etc.).
Elles ont en commun leur taille (environ 250 collaborateurs) et leur mode de production : ART et BOX travaillent en large groupe, l'une dans un hangar aménagé avec des chaises et des estrades, l'autre dans une salle municipale qu'elle loue.
Les orateurs·ices s'entraînent ensemble, se donnent des feedbacks, et organisent plusieurs fois par jour des présentations internes rapides, dits "intégration".
Une intégration consiste à solliciter l'attention d'un maximum de collègues, délivrer son discours, et collecter des retours qualitatifs et quantitatifs (par exemple au moyen d'un applaudimètre).
ART et BOX se font concurrence, et sont constamment à la recherche d'orateurs·ices présentant les meilleures compétences et dispositions. Le turn-over est élevé, sans parler des problèmes de surmenage (égosillement, perte de créativité, etc.)
ART et BOX se partageaient le gros du marché du service d'éloquence, mais il y a 6 mois une nouvelle venue est arrivée qui est en train de les détrôner, la société REC (Recursively Engaging Communicators). Elle s'est établie dans l'ancien cirque d'hiver, où ses 200 consultants travaillent sans relâche. Ses premiers clients sont unanimes : cet outsider offre des services d'éloquence inouïs, avec un temps de mise au point exceptionnellement court.
En croissance, et recrutant sur les mêmes critères que ses concurrentes, REC met en œuvre le même savoir-faire que BOX et ART, à une différence près : les intégrations.
Chez ART, lorsqu'une personne interpelle le groupe pour présenter un travail, elle doit élever la voix jusqu'à ce que le brouhaha cesse dans le hangar, délivrer sa performance, et collecter des retours. Cela prend du temps, et esquinte les nerfs. (L'usage de sifflets a été prohibé après un bref essai).
Chez BOX, une intégration est organisée chaque demi-heure. Ceci n'empêche pas l'appel à l'attention d'être particulièrement laborieux, tout en limitant l'emploi du temps de chacun.
La société REC procède différement. Chaque nouvelle recrue reçoit ces instructions :
- tu peux parler, chanter, t'entraîner à ta guise
- si tu aperçois une main levée = une intégration est demandée, tu dois :
- arrêter ton activité
- observer le silence
- lever également la main
En appliquant cette règle, les 200 employés de REC obtiennent le silence en 3.35 secondes en moyenne, ce qui leur permet d'intégrer plus de 30 fois par jour, et d'obtenir le maximum de chaque retour, le tout dans le calme.
ART, BOX et REC sont des systèmes. Leur performance n'est pas le fait d'un élément, mais de l'interaction entre les éléments.
REC n'a pas recruté de meilleurs talents. Elle a seulement un meilleur process.
Stay Tuned !
publié sur Linked In le 17/04/2023
Prévenir > Guérir
TDD est une stratégie Diviser pour Régner appliquée aux vérifications et aux refactorings de votre code. Le R.O.I, ce que vous gagnez à acquérir et renforcer cette compétence, dépend de la taille de la base de code sur laquelle vous travaillez.
Comparer une solution dont le code est 90% vérifié à une solution dont le code n'est pratiquement pas vérifié peut être particulièment trompeur. Cela revient à comparer deux choses différentes, et ne considérer que le prix. 🪣 🤓 🧯
Bien sûr quand nous développons du logiciel, nous devons être vigilants sur les coûts, nos ressources sont limitées. Nous avons aussi besoin d'être responsabilisés sur nos décisions (entre autres : celles qui concerne les méthodes qui vont continuer de s'appliquer quand nous serons partis). Notre solution doit aussi être soutenable en termes de coûts, de qualité et de facilité de maintenance.
Quand on adopte une stratégie Code & Fix sur un projet complexe, on proclame :
- on va faire ce projet en Code & Fix, parce que c'est moins cher ! 🪙 💪
Il serait honnête de dévoiler le raisonnement complet, avec ses conséquences :
-
tous les chemins d'exécution possibles du code ne seront pas vérifiés : ni au niveau unitaire, ni au niveau intégration 🕳
-
nous ne savons pas exactement lesquels seulement seront testés 🎰
-
nous ne comptons pas le calculer, mais intuitivement, nous savons que l'alternative TDD serait du gâchis 🔮
🤷♂️
🗺🪜🧯
TDD est une instance de stratégie de prévention des défauts.
La prévention des défauts est elle même une instance d'ingénierie bien comprise, telle que les humains la développent en vue de faire face à la complexité, et à l'irreversibilité du temps.
Il vaut mieux prévenir que guérir :
-
Nous protégeons les biens dont nous savons qu'ils seraient difficiles à remplacer s'ils disparaissaient. 🔐
-
Nous dépensons un peu d'énergie à maintenir de l'ordre dans un système qui marche, pour éviter de dépenser une énergie incommensurable sur un système en désordre qui ne marche plus. 🗃
Le bien que je protège en écrivant un check (ou "test unitaire" 😒) c'est la compréhension précise que j'ai de ce chemin possible d'exécution du code au moment où j'écris le code. 🗺
Le désordre dont je me protège est celui qui serait créé par un chemin d'exécution défectueux enfoui parmi des milliers de chemins d'exécution possibles, eux mêmes liés à des centaines d'états possibles. C'est une forêt épaisse et opaque, une botte de foin numérique dans laquelle je n'ai aucune envie d'avoir à chercher une aiguille. 🤯
Mon avis :
-
ne vous enfermez pas dans un tunnel de code jusqu'à vous trouver au sommet d'une solution ingérable, à vous demander : attends, est-ce que ça marche, au fait ?
-
apprendre une nouvelle technique est plus facile au début d'un projet qu'au milieu d'une crise
-
est-ce qu'il faut vraiment TOUT construire comme si les solutions que nous créons n'avaient aucun avenir ?
Stay Tuned !
publié sur Linked In le 18/04/2023
Crash Fatal
C'est l'histoire d'une fonction qui rencontre une variable.
Alors que la fonction s'est arrêtée au croisement de deux modules, la variable lui fait un signe du pouce.
— Vous allez dans cette direction jusqu'au Back ?
— Non je change de route après le contrôleur, mais je peux peut-être vous avancer.
— Ah, je dis pas non.
Et la variable prend place dans le scope du passager de la fonction.
— Vous allez loin comme ça ?
— Ben jusqu'au Back.
— Hmm, ça m'étonnerait que vous arriviez jusque là.
— Et pourquoi pas ?
— Je sais pas, une intuition… Si je vous demande quel âge vous avez, vous me dites quoi ?
— Que je trouve ça un peu indiscret, mais bon. 10.
— 10 secondes ?
— Millisecondes ! Vous me vexez là…
— Ok. Mettons que je vous dise : le Back, vous y serez pas avant 25 millisecondes, au moins.
— Tout ça !? C'est long ! Je serais vieille une fois arrivée !
— Justement : ça vous fera quel âge ?
— Bah 1025. C'est horriblement vieux !
— Eh mais vous n'êtes pas du tout mon type en fait !
Et la fonction s'étant tournée vers la variable pour l'invectiver, elle manque le feu qui était sur await, et une autre fonction arrivant à fond depuis la voie de droite emplafonne la fonction, la variable, et tout le reste du code.
Fin de l'histoire.
— Allo ? Oui c'est Jade. J'ai un nouveau crash… ligne 4807.
— …
— Oui je t'envoie un ticket, avec la copie d'écran oui. Oui je sais, option développeur, console javascript… À plus.
Jade est testeuse. Elle fait partie du service QA. Sa mission : trouver des problèmes dans le produit, et les communiquer d'une manière qui aide l'équipe à prendre une décision. Pour cela elle s'appuie sur ses outils, son expérience, son intuition, et ses interactions avec l'équipe. Ça c'est les jours avec. Les jours sans — et on dirait que sur ce projet, il y a surtout des jours sans — elle est plutôt occupée à ramasser des carcasses de fonctions.
Un jour, ce même développeur qu'elle vient d'avoir au téléphone lui a demandé :
— Est-ce que tu fais des tests manuels parce que tu ne sais pas coder des scripts ? On peut t'apprendre.
— Je sais coder. Je fais des tests manuels surtout parce que je ne sais pas exactement à l'avance où il faut investir le plus de temps. Ça s'appelle du test exploratoire. Et d'après mes observations, c'est plutôt toi qui ne sait pas coder. (Bon OK cette dernière phrase elle ne l'a pas dite. Mais avouez qu'elle aurait pu).
L'ennui, pour Jade, c'est que son équipe investit trop peu dans la prévention des défauts, i.e identifier les défauts avant que ceux-ci ne créent des problèmes.
Exemples de pratiques de prévention :
- langage fortement typé 🙄
- revues de code
- TDD, vérifications automatisées
- etc.
Toujours ce même développeur :
— Au moins ça te donne du travail.
— Non ! Ça m'empêche de faire mon travail, qui est de trouver les problèmes les plus importants !
— Ah oui… Mais alors, qui les trouve ces problèmes plus importants ?
— À ton avis ?
À votre avis ?
publié sur Linked In le 20/04/2023
Cliquets
Alors que la revue commence, un portable sonne bruyamment.
— Oups, pardon.
Dans la salle de réunion, 4 autres participants vérifient leur portable. 2 d'entre eux le mettent en sourdine.
⚙️
Vers le milieu de la revue :
— C'est intéressant : jusqu'ici sur ce legacy on avait d'un côté le code de production, de l'autre, un word expliquant comment il fonctionne…
— Oui, alors, "expliquant" : très vaguement, et surtout, pas à jour.
— Expliquant vaguement comment il a fonctionné dans le passé.
— Voilà.
— Maintenant, c'est à dire, à partir du moment où tu as réussi à mettre au point ce script de tests, et vu qu'on va l'adjoindre au repository, on a quelque chose de plus.
— Je ne vois pas.
— On a d'un côté, le code de prod, et de l'autre du code de test, précis, à jour, correct, qui nous parle du code de prod. On est mieux !
— Correct ? Ce n'est pas sûr. Excuse-moi, mais si le code de test est faux, on n'est pas mieux.
— On n'est pas mieux qu'avec un pauvre doc word vague et pas à jour ?
— Non. On a juste pris plus de temps à écrire des tests.
— Donc, parce que des tests autovérifiants peuvent à l'occasion comporter une erreur de test, ils valent moins que ce doc ?
— Un test cassé, ça se répare. Un doc pas à jour…
— Faut reconnaître.
⚙️
Fin de revue :
— Donc : module OK pour aller en prod. Et on ajoute le script de test dans le repo.
— Est-ce qu'on pourrait aussi acter le procédé de test dans l'ADR (suivi des décisions) ?
— Qu'est-ce que tu voudrais acter ?
— On reprend ton code de test, et on en fait un exemple simple de script avec le même tooling.
— Pourquoi pas.
— Et je propose qu'on l'ajoute au standard.
— Tu ne veux pas qu'on voie si c'est applicable partout, d'abord ?
— Je propose qu'on l'applique, avec exceptions documentées.
— Plus un.
— Go.
— Ça me va.
— Non.
— Qu'est-ce qu'il faudrait ajouter pour que tu sois d'accord ?
— Il faudrait se former sur l'outil avant de le mettre au standard.
— Ok… Je propose qu'on fasse une session pour s'améliorer sur l'outil, et ensuite on acte.
— Ok.
⚙️
Cette équipe part de loin (premier test auto en 7 ans de production) mais une force l'aide à s'améliorer en continu : elle utilise des cliquets.
Un cliquet est un mécanisme qui maintient un système en l'état, ou plus généralement l'empêche de revenir en arrière et le force à avancer. (Wikipedia)
⚙️ la 1ère sonnerie de portable "vaccine" le groupe contre les futures sonneries durant la réunion
⚙️ chaque nouveau test auto-vérifiant sécurise un peu plus le code existant contre les régressions
⚙️ chaque revue de code améliore le standard
⚙️ le processus de décision de l'équipe consiste à raffiner la décision proposée au lieu de la contrecarrer
La force que cela procure à leur système vient de l'effet cliquet :
- aller dans un sens demande peu de mouvement et donc d'énergie
- pour aller dans le sens contraire, il faut "casser" le cliquet ce qui demande une énergie plus importante.
Quels sont vos "cliquets" ?
publié sur LinkedIn le 20/04/2023
Mégapole
Imaginez une mégapole où on circule de mille façons, tramway, métro, vélo, moto, auto… Il y a dans cette immense agglomération des infrastructures fiables, sûres et pratiquables. Tout est fait pour la circulation : chaque véhicule arrive à sa destination, chaque transporteur, chaque passager atteint son objectif.
🏙🚟🚲🛵🏍🚗🚐🚛🌆
En considérant cette mégapole sous l'angle du déplacement de personnes ou de marchandises, deux indicateurs nous intéressent spécialement :
1 la sécurité pour les personnes et les biens transportés
2 la vitesse à laquelle se font ces déplacements
Imaginez un système d'information, dans lequel des centaines d'applications interagissent ensemble et avec les utilisateurs. Ce système est construit sur des infrastructures fiables. Tout est fait pour que la traduction d'idées, et leur mise en œuvre à des fins commerciales, culturelles, sanitaires, sécuritaires, financières etc., soit possible. Chaque fois qu'idée fait son chemin depuis l'esprit de ses concepteurs, en passant par les développeurs jusqu'à la production et l'interaction avec l'utilisateur, les personnes qui ont créé et soutenu cette idée atteignent leur objectif : communiquer, proposer, vendre, acheter, gérer… En considérant ce SI sous l'angle de la mise en œuvre d'idées, deux indicateurs nous intéressent en particulier :
1 fiabilité : la confiance que l'on peut avoir dans le fonctionnement des programmes traduisant ces idées
2 agilité : la vitesse et la flexibilité avec laquelle on peut implémenter ces idées
🏙🖥📲💻📱📡🌆
Sans quitter cette analogie, imaginez maintenant un changement majeur : les règles de circulations sont abolies. Le code de la route n'existe pas, ni aucune autre convention de circulation. Plus de régulateurs, de priorités, signaux, capteurs, plus de juridiction. Nos deux indicateurs indiquent un désastre économique et humain :
- les accidents de toutes sortes se multiplient
- la vitesse moyenne d'un point à un autre devient minimale
Un système d'information au sein duquel on n'appliquerait aucune mesure de prévention des défauts serait comme cette mégapole sinistrée. Nos 2 indicateurs inqueraient alors un cauchemar informatique :
- dysfonctionnements fréquents, spectaculaires ou insidieux
- rigidité frisant la sclérose : les changements coûtent trop cher, et prennent trop de temps.
Fin de l'analogie.
On est en 2023, et en 2023 le problème en IT c'est qu'on ne code pas assez vite.
On évite autant que possible de créer des équipes, entités contingentes et chronophages.
L'écriture systématique de code de tests concerne une minorité de dévs, laquelle est d'ailleurs divisée sur la question.
Relire du code ensemble est considéré au mieux comme un archaïsme incongru.
Foin de toute cette prévention, ça ralentit nos start-ups.
On va bientôt démultiplier notre célérité et notre promptitude grâce à des LLM.
Foncez, le progrès fait rage.
publié sur Linked In le 21/04/2023
Des usines et du sable
Merci @JohanMartinsson pour ta contribution à cette conversation sur le mythe de la "Software Factory". Tu vois 2 facteurs importants de ténacité de ce mythe :
🎤 1. Le confort d'imaginer que l'on peut rester dans la zone de compétence (dev) plus ou moins entièrement. Ca peut être assez plaisant d'imaginer que l'on va juste réaliser les idées des autres
🎤 2. C'est une façon à peu près efficace de vendre du service. La vente étant visible, on va donc percevoir ceci plus, sur les réseaux, que ce qui est réellement le cas sur le terrain.
Je pense que l'industrie du service joue un rôle important dans la persistence du mythe de la Software Factory. On pourrait même dire qu'elle l'entretient activement. Le renouvellement fréquent du vocabulaire et des compétences techniques, guidé par les radars technologiques des sociétés de conseil, crée l'illusion d'un monde en progrès, dans lequel chacun des trois acteurs joue pleinement son rôle au sein d'une relation "win/win/win" :
-
l'acteur Métier aiguillonne l'entreprise afin qu'elle s'adapte ou change son marché : elle doit penser "produit", parfois en se réinventant. (Voilà au moins une décennie que cette stratégie, nommée "transformation" est devenue la feuille de route officielle de la plupart des entreprises).
-
l'acteur Technique vient remplir son rôle de généraliste multi-spécialiste, il aiguise ses outils, ses patterns, ses frameworks au service du produit. Pur acteur du "comment", il se cantonne au technique (qui est immense). Même ses procédés les plus proches du "fonctionnel" : DDD, BDD, Tests, restent éminemment techniques.
-
le Management pérennise et rationnalise ce circuit entre le Métier et la Technique, en posant des gardes-fous : suivi des performances, gestion des contingences, industrialisation. C'est une tâche difficile, le calendrier du Métier et l'agenda des technologies se disputant la priorité. De son côté l'industrie du service répond à cette difficulté en s'adaptant aux contraintes de l'entreprise. Toutes deux codifient ensemble l'offre, ce qui a pour effet de fluidifier le marché d'une part, et de renforcer les silos d'autre part.
"C'est la compréhension des développeurs qui va en production." Si cette suggestion de Brandolini a une grande valeur, elle reste néanmoins incompatible avec le modèle de la Software Factory, qui met en avant l'efficacité individuelle à produire du code, comme une activité d'étape au sein d'un processus séquentiel descendant de l'idéation "sur le papier" vers l'implémentation "mains dans le cambouis".
Optimiser la production de code, notre industrie s'y occuppe à plein temps, et les résultats sont fulgurants, avec ou sans LLM. C'est fascinant, mais ce n'est pas tout à fait le sujet de l'entreprise. Celle-ci a besoin à la fois d'innover et de maintenir. Sa Software Factory l'aide à construire plus vite, mais elle construit sur du sable. 🏖
publié sur LinkedIn le 24/04/2023
Apprendre et s'adapter
⌚️ 10h09 : Tom démarre sa première mission. Son client et lui finissent le tour du projet. 🏢
— …En tout cas merci d'avoir pu te libérer si vite. On est un peu dans l'urgence en ce moment.
— Pas de souci. Si ça peut aider, pour moi c'est avec plaisir.
— Tant mieux. Comme je te le disais, on a pas mal de régressions sur le projet.
— C'est grave ?
— Non, non, en général ça ne va pas chercher loin. Mais le truc c'est qu'il y en a quand même un paquet. Ça s'accumule.
— Ah.
— Heureusement on arrive à déployer assez vite. Il suffit de cliquer là, tu vois.
— Je vois. Et quand vous déployez comme ça, vous passez des tests, ou bien…?
— Oh là, les tests… On n’a pas trop le temps pour les tests.
— Ah bon ?
— Note qu'on en avait à un moment, mais on a décidé de les débrancher.
— …
— Bah, oui : quand ça bloque le build, et qu'il faut bien qu’on livre, tu vois le problème.
— Hmm.
— Comme je te le disais, le projet a plusieurs mois de retard.
— OK.
— Depuis que Jean-Marc est parti on est un peu sous l’eau.
— C’est qui Jean-Marc ?
— C'était le Tech Lead. C’est lui qui a mené le cadrage, et l’archi, il y a 2 ans. Il devait rester jusqu’à la mise en prod, mais il a dû partir avant, son contrat se terminait.
— OK.
— Bon, ben tu sais tout. Y’a plus qu’à. Faut que je file, je suis déjà en retard.
— Avec qui est-ce que je pourrais binômer pour commencer ?
— Euh, c’est pas vraiment l'esprit chez nous, le binômage. On préfère que les gens soient focus.
— Focus.
— En même temps, t’es plus à l’école, ici. Bienvenue dans la vraie vie !
👨💻
Q: À votre avis, que va apprendre Tom dans cette mission ?
🄰 Rien, ou pas grand chose
🄱 Un tas de choses au contraire !
🄲 Tom n'est pas là pour apprendre.
Q: Est-ce que le système dont Tom fait maintenant partie peut s'améliorer ?
Pour s'en faire une idée, consultons Russell Ackoff, théoricien des organisations :
📖 Apprendre, c'est améliorer ses performances sous des conditions constantes. Nous apprenons de notre propre expérience et de celles des autres. Cette expérience peut être contrôlée, comme dans l'expérimentation, ou non-contrôlée, comme dans l'essai/erreur.
📖 Par exemple, si nous améliorons notre précision au tir sur une cible à l'aide d'essais répétés, nous apprenons. Si, après cela, le vent se lève et nous fait manquer notre cible, c'est l'adaptation qu'il nous faut. Nous pouvons nous adapter soit en ajustant le viseur, soit en tenant compte du vent.
📖 Parce que l'apprentissage et l'adaptation sont des activités intentionnelles (i.e matière à décision) , elles peuvent être elles-mêmes apprises. Apprendre comment apprendre et s'adapter est parfois appelé la double boucle d'apprentissage.
📖 Un système ne peut pas apprendre et s'adapter à moins que son management le puisse. Par conséquent un système cherchant l'idéal doit avoir un système de gestion capable d'apprendre à apprendre et de s'adapter.
(R. Ackoff — On Purposeful Systems)
Bonne chance, Tom !
publié sur LinkedIn le 25/04/2023
Sprints à Rallonges
🗓 T0 + 2 semaines :
— Donc on annule la démo, c'est ça ton idée ?
— On annule la démo, oui : on n'a rien à montrer !
— C'est dommage. Le sponsor attend beaucoup de cette première démo.
— Peut être, mais comme je vous le dis depuis le début : on peut pas mettre en place le socle en si peu de temps. On y a passé 2 semaines et demi, et on n'a toujours que la moitié de la persistence qui fonctionne correctement.
— Comment ça se fait ?
— Il y a 150 tables dans le schéma, ça te dit quelque chose ?
— Bon. Donc on annule aussi notre sprint review ?
— Ça aussi je vous l'ai dit : 3 semaines c'est trop court comme durée de sprint.
— Ok. J'appelle le sponsor.
🗓 T0 + 5 semaines :
— Donc on fait quoi ?
— Je ne sais pas. La story Souscrire un Contrat fonctionne à peu près, mais on ne sait toujours pas persister un Portefeuille.
— Portefeuille, c'est une entité nouvelle, c'est ça ?
— Oui. La base GBD sur le GS ne contient rien de tel. Ça veut dire qu'il y a tout un micmac à mettre en place au niveau de la couche ORM.
— Et ça ne marche pas ?
— Disons que ça ne marche pas dans tous les cas. Et le temps d'écriture va jamais passer.
— Alors on reporte une deuxième fois ?
— Franchement, ça serait le mieux…
— Bon. On va se faire tuer, mais bon.
🗓 T0 + 7 semaines :
— Non mais écoute, on a une solution, mais il nous faut encore, disons 3 jours.
— Tu plaisantes Jérémie ?
— Non, malheureusement. Voilà ce que je propose : Souscrire un Contrat sauve ses agrégats dans une base Memory2, et on rebranche la même base dans Consulter mes Contrats.
— C'est quoi une base Memory2 ?
— C'est une base de données en mémoire, ça permet de faire des tests. Jérémie a raison c'est ce qu'il faut faire. Demande au sponsor s'il est OK pour reporter à mercredi.
📯 T0 + 8 semaines : démo, avec le sponsor.
— Eh ben voilà. Vous y avez mis le temps, mais on a enfin une première démo !
— Encore merci pour votre patience, en tout cas. Alors on va passer sur Souscrire un Contrat… Voilà…
— Très bien.
— Alors il faut qu'on vous explique : en réalité, l'application ne sauve pas sur le vrai SGBD, uniquement en mémoire, du fait d'un inconvénient avec la notion de portefeuille, mais dans le scénario Consulter mes Contrats, on retrouve tout de même les données que vous allez saisir…
— J'ai pas compris, mais allons-y.
🤝 fin de la démo :
— Bon ben merci, c'est pas mal. Là sur ce volet, ce n'est pas la bonne info. Ah oui, aussi, ça j'aime bien. C'est pratique. Ici, sur l'option Portefeuille, vous auriez dû nous consulter, ce n'est pas comme ça que ça devrait se faire…
— OK.
— Bon eh bien à quand la prochaine démo ?
🍻 aprés la démo :
— Pffou. Ça c'est mieux passé que ce que je craignais.
— Il est sympa le sponsor, mais il faudrait savoir ce qu'il veut. Il remet tout en question. Faut revoir toute la persistence, là.
— Ouah. Tu n'y es pas du tout Jérémie.
— Il sait très bien ce qu'il veut. Mais on le lui montre trop tard.
publié sur Linked In le 26/04/2023
Mon Indicateur de Productivité
Ma première rencontre avec la productivité a eu lieu en 1989 :
— Voilà, on a ce projet en dBase IV…
— Et dBase IV ne marche pas. (Facile, il suffisait de lire la presse spécialisée).
— Précisément. Vous connaissez dBase IV ?
— Je connais bien dBase III. Il y a un équivalent qui s'appelle Clipper.
— Et vous connaissez Clipper ?
— Pas très bien, mais si vous avez la documentation…
— Oui, mais nous si on vous prend, ce n'est pas pour lire de la doc !
🤝 J'ai été pris quand même. Ironiquement, ma première tâche a consisté à lire la spécification du projet (3 documents de 150 pages). 📚
L'idée de mesurer la productivité des développeurs en comptant les lignes de code produites a été remise en cause il y a déjà un certain temps. (par ex. dans Capers Jones — Software Assessments, Benchmarks and Best Practices — 2000).
Peu d'entreprises à vrai dire semblent faire attention au nombre de lignes de code des projets. En général, pour jauger la productivité des développeurs on s'appuie plutôt sur l'équation :
temps passé seul devant l'écran / temps passé à d'autres activités
équation basée sur l'idée que les développeurs ont pour mission de produire du code, et qu'il font mieux cela en restant concentrés devant leur écran plutôt qu'en faisant autre chose. 🖥
C'est cette idée qui rend suspectes des pratiques comme pair programming ou ensemble programming. 🧐
Bien sûr, rester seul devant l'écran ne garantit pas en soi la productivité. Mais en l'absence d'une meilleure heuristique, celle qui domine, c'est que dialoguer alors qu'on pourrait se concentrer seul devant l'écran, c'est perdre en productivité.
Mon idée à moi de la productivité est connotée à une métrique malheureusement impossible à mettre en œuvre : la VBD.
La Vitesse de prise des Bonnes Décisions 🤓
C'est une métrique d'équipe, évidemment. C'est même ce qui motive la création d'une équipe. (Au sens complet, i.e incluant Métier, Technique et Management. Sans cette inclusion, votre VBD en prend déjà un coup).
Je ne sais pas mesurer la VBD, mais je peux l'imaginer en train de baisser quand…
- on n'arrive pas à déchiffrer la règle métier parce que le code est trop touffu, trop génial, trop tordu, pas assez clair 🤯
- on ne recevra pas de retour des utilisateurs avant plusieurs semaines et on se contente de présupposer ou de projeter ce qui leur serait utile 🏝
- on prend des décisions structurantes sur la base d'opinions ou de convictions sans mesurer quoi que ce soit de la situation en cours 🔮
- on s'enferre dans les débats d'idées au lieu d'améliorer le code et le standard 🤺
- on pose des verrues ça et là faute de tests pour refactorer le code et étendre la conception 🪣🪠
- on travaille dans l'urgence et le fait accompli au lieu de se poser pour réfléchir 🚨
- on essaie de faire tout seul au lieu de demander de l'aide 🕳
- on bricole une solution faute d'ouvrir les bons livres 🕳📚
- on se réadapte en permanence au lieu d'apprendre en continu 🥵
publié sur Linked In le 27/04/2023
Résolution
🌆 Dimanche, vers 19h :
— Bon eh ben le serveur tourne à nouveau.
— En tout on a été HS… 2 heures 24 minutes.
— Ce qu'il faudrait, c'est revoir ce programme. C'est la troisième fois en 6 mois !
— Ecoute, repose toi bien, et on en reparle plus tard. Demain il fera jour.
🏙 Lundi matin :
— Encore un grand merci à Sophia et Daniel pour hier. Comment avez-vous résolu le problème cette fois-ci ?
— Tu as lu mon rapport d'incident ?
— Oui, mais je pense que ça vaut le coup que tu partages à l'équipe.
— Simple : le dispatch est tombé hier en fin d'après midi, pour cause de plus de mémoire. La raison on s'en doute : des fonctions qui oublient de rendre la mémoire allouée.
— C'est tout bête…
— En effet. J'ai mentionné ce problème en revue il y a 3 mois. La décision ça été : on verra.
— Daniel, j'ai jamais dit "on verra", j'ai dit : on ne sait pas si c'est ce qui impacte le fonctionnement du serveur, est-ce qu'on peut attendre d'y voir un peu plus clair ?
— En tout cas, j'ai corrigé la fonction ce matin, le patch est prêt pour aller en prod.
— On peut savoir ce que tu as fait ?
— Tu vas me détester Sophia : je fais un sysctl
et je log une notification si le serveur manque de mémoire.
— 🤦♀️
— Tu sais comme moi qu'on ne peut pas revoir ce code en profondeur pour l'instant.
— Alors qu'on pourrait instrumenter le code sous MemScan Pro Ultra en quelques jours…
— Je sais…
— Et si on écrivait quelques tests également dans cette maison ça nuirait pas.🤬
— Bon ne nous énervons pas.
— De toutes façons y a pas de débat : on va refondre ce truc archaïque avec un vrai langage, moderne et tout, qui gère la mémoire pour nous.
— Quand ?
— That is the question, quand.
⏸
Russell Ackoff distingue 4 façons de traiter un problème :
- absolve : ignorer le problème en espérant le voir disparaître avec le temps
- resolve : trouver une solution "suffisante", ou bien essayer d'identifier la cause, et supprimer cette cause afin de revenir à un état précédent
- solve : faire ce qui produit le meilleur résultat possible, en s'appuyant sur la recherche et l'expérimentation
- dissolve : éliminer le problème par reconception entière du système ayant le problème
À l'échelle du système pour lequel Sophia et Daniel font des heures sup' le dimanche, les traitements absolve et resolve sont les plus couramment utilisés, car adaptés à l'approche court-termiste qui caractérise le management de ce système. Du fait de cette approche, les traitements solve et dissolve sont remis aux Calendes Grecques, ou restent dans le domaine de l'Impensé.
Court Terme
- on attend 🤸♀️🕳
- ficelle et sparadrap 🧶🩹
Moyen Terme
- on met en œuvre la meilleure solution 💡📐
Long Terme
- on refond 🌌🔭
Un système legacy, ce n'est pas seulement des technos obsolètes, ou une base de code comme une forêt de ronces. C'est aussi un état de déconnection de l'équipe Métier/Technique/Management, qui fait que le système est coupé de son avenir.
publié sur Linked In le 28/04/2023
Prévention
- Quizz
- Provisions
- Double Boucle
- Le Standard
- Breakpoints
- Couloirs
- Détrompeurs
- Patinette
- Rollers et Scooters
- Artisanat
Quizz
🏢 Le lieu : entreprise ARGH (Automated Resource for Global HR)
📅 La date : déploiement plus 1 an, 3 mois et 17 jours
👥👥 Acteurs présents : Arthur (Tech), Bénédicte (Tech), Carla (Métier), David (Management)
▶️
— Donc, est-ce qu'on en sait plus sur ce 🤬 bug des ajustements de congés ?
— Carla ? Est-ce que tout le monde m'entend ?
— On t'entend David. On t'écoute même !
— Carla, laisse moi te présenter Arthur, qui a rejoint l'équipe il y a 2 mois. Je pense que tu connais déjà Bénédicte.
— Bonjour à tous les deux. Donc…
— Je les ai invités parce que figure-toi que le problème des ajustements : eh bien ils l'ont réglé !
— Magnifique. La vie va pouvoir reprendre son cours normal.
— Arthur, est-ce que tu peux nous redire en détail ce dont il s'agissait ?
— Stop. Arthur, c'est Carla ici. En détail, mais n'oublie pas que je ne parle pas la tech !
— Euh… Okay. En fait le problème venait d'un problème de type.
— OK…
— Un problème de type, oui. Dans certains cas d'ajustement, l'ajustement est alimenté via le volet "revenir sur les ajustements standards".
— Exact.
— Et le formulaire passe un paramètre de type String au lieu de la valeur numérique correspondante.
— Hmmm…
— Or Javascript ne vérifie pas le type des arguments.
— Arthur ? Tu m'as perdue à "paramètre de type String".
— C'est Béné : je peux essayer une explication ?
— Je t'en prie Bénédicte !
— Carla : 20 plus 2, ça fait quoi ?
— C'est un jeu ? Je suis pas d'humeur, là…
— 20 plus 2 ?
— 22.
— Correct. Et 20 et 2, ça fait quoi ?
— Bah 22 ?
— Incorrect.
— Attends… Ça me rappelle le message sur un des tickets ta question.
— Oui ?
— 202 ? 20 et 2 ça fait 202 ?
— Voilà, tu y es.
— Sans rire, 🤬
— Je te repasse le micro, Arthur.
— Donc, voilà. C'est juste une erreur de type.
— "Juste" ? "Juste" ? Non mais vous plaisantez j'espère !? 25 tickets en 2 semaines. C'est juste une erreur de type… 🤬
— Carla ? "Don't shoot the messenger !"
⏹
🏢 Le lieu : entreprise BAM (Bulletin Automatique Modulaire)
📅 La date : déploiement moins 42 jours
👥💻 Acteurs présents : Amiel (Tech), Barbara (Tech), ordi A3K9F8G2J1H7 (Tech)
▶️
— Ouah. Il est bientôt 13h. Je te propose qu'on builde et ensuite, pause déjeuner.
— Ça me va.
— ajustement.ts:386:17 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
— Oups.
— Ah oui : on lui passe une chaîne au lieu d'un nombre. Attends je le convertis.
— fais un parseInt…
— Yes.
— …
— C'est compilé. Je pousse dans le repo. On reprend à 2h ?
— Ça marche. Bon app' !
⏹
Jeu Quizz du week end :
À part le fait qu'elles développent du logiciel, tout semble séparer ARGH et BAM. Quelle différence vous paraît la plus cruciale ?
🄰 l'esprit d'équipe et la bienveillance
🄱 la stratégie de prévention des défauts
🄲 la compétence des développeurs
🄳 l'implication du management
publié sur Linked In le 30/04/2023
Provisions
Lorsque j'ai découvert et intégré TDD à mon travail, je disais à qui voulait l'entendre que c'est un moyen efficace et motivant de produire du code propre et qui marche. Et ceux qui voulaient l'entendre de répondre aussitôt :
— Oui, mais :
- ça fonctionne seulement pour les petits projets
- ça fonctionne seulement pour les grands projets
- écrire autant de tests c'est de la sur-qualité
- ça double le volume de code produit sans vraie valeur ajoutée
- d'ailleurs les tests testent le code, mais qui teste les tests ? Ça ne s'arrête plus
- on ne peut pas non plus refactorer à l'infini, à un moment il faut produire
- quelques tests d'intégration ça fait largement l'affaire
- un développeur qui cherche à casser le code qu'il construit risque de devenir schizophrène
- les tests, c'est pour les gens qui ne savent pas coder
C'est de bon aloi : j'essayais de les persuader d'essayer TDD; en retour ils essayaient de trouver des raisons pour ne pas l'essayer.
Mais la meilleure raison de ne pas essayer TDD, on n'a pas besoin de la chercher en examinant mentalement tous les tenants et aboutissants théoriques de la démarche. Cette raison est simple, universelle, imparable : on n'a pas le temps. ⌛️
En général le budget d'un projet de développement logiciel qui démarre est plein comme un œuf. Vous y trouverez à peine de la place pour les aléas. Pour peu que l'estimation soit sujette à des variations selon les hypothèses, on retiendra l'hypothèse la moins chère, pas la plus probable. On sait d'expérience que des problèmes de qualité surviendront, et on les a même provisionnés, parfois en gonflant certaines estimations.
Tous ces systèmes sur lesquels on trouve beaucoup de tickets d'incident et peu de tests, sans même parler de la documentation, ce n'est pas que leur développement était sous financé : il s'est mis en retard et a utilisé toute la provision. 💸
A l'exception peut être de contextes de purs projets de recherche, aucune équipe ne conclut le cadrage d'un projet en déclarant :
"Il se pourrait qu'on découvre chemin faisant des opportunités de mettre en œuvre une démarche qui réduirait les problèmes de qualité tout en nous faisant gagner du temps. Si le cas venait à se présenter, nous n'hésiterons pas à marquer une pause sur l'avancement du projet afin de se donner le temps d'acquérir et d'intégrer une telle démarche."
Non, s'il fallait résumer la conclusion d'un cadrage de projet en passant le micro à chacun des 3 acteurs cela donnerait :
🎤 Métier : J'ai hâte que ça démarre enfin, parce qu'on n'est pas en avance. ⏱
🎤 Tech : Rassurez-vous ! Vous avez pris les meilleurs ! 🎯
🎤 Management : C'est tendu, mais on va voir ce qu'on peut faire. 🧩
Pour améliorer son état de l'art, une entreprise à le choix :
- emprunter un état de l'art qui n'est pas le sien, mais qui fera illusion le temps du projet 🎯
- manager en enseignant, de haut en bas dans l'entreprise, une démarche d'amélioration continue ⌛️
Stay Tuned ! publié sur Linked In le 02/05/2023
Double Boucle
C'est peut être une variante de l'Erreur Fondamentale d'Attribution, qui consiste à juger comme incompétentes des personnes raisonnablement expérimentées et bien disposées mais qui se trouvent aux prises avec un système médiocre.
Moi même, je me dis souvent : Ces deux préhistos ont dû se donner un mal fou pour se fabriquer des roues carrées, les idiots.
Quand on est abonné à Linked In, on sait bien que
- la plupart des développeurs ne savent pas écrire du code propre 🧐
- les managers sont dépassés par l'évolution des technologies 🤓
- le métier n'a pas la moindre idée de ce qu'il veut 😜
🙃
Commençons par enfoncer une porte d'ouverte : c'est très banal, mais si vous travaillez dans le logiciel, alors vous allez très probablement rencontrer des problèmes de retard et/ou de dépassement de budget, ainsi que des problèmes de qualité.
Cela n'a rien à voir avec vos compétences ou vos dispositions, mais vient plutôt de la façon dont l'activité est organisée, c'est à dire du système de développement dans lequel vous intervenez.
Avec un peu de recul, et en mettant de côté les considérations individuelles accidentelles (leadership, passion, courage, focus, bienveillance, assiduité, obstination, sacrifice etc.) on trouve 3 traits essentiels à ce système :
♻️ Turn-over : les entreprises s'adressent à un marché du travail et un marché du service régis par une révolution technologique permanente. Songez donc : InfoQ classe des techniques comme CQRS, Event Sourcing, ou Domain-Driven Design dans son segment "Late Majority" ! C'est à se demander s'il ne leur manque pas un segment "Decrepit Fossil" pour C++ et COBOL.
🤝 Mode de coopération : 3 acteurs aux objectifs distincts mais complémentaires (Métier, Technique, Management) cherchent à réussir ensemble un projet de développement. L'entreprise place entre eux des barrières de communication inextricables : silos, transferts implicites de responsabilités et de risques, drama.
📝 Mode d'apprentissage : on considère le développement de logiciel comme de la fabrication de produit. On cherche donc à optimiser la vitesse de production, en s'appuyant sur la stabilité factice offerte par les outils de CI/CD. Or réaliser du logiciel, c'est traduire des idées en provenance de systèmes vers d'autre systèmes, dont certains comprennent du code. Le code n'est pas le bout de la chaîne : c'est une traduction parmi d'autres.
Pour améliorer l'état de l'art dans une entreprise qui développe du logiciel, il faut apprendre ensemble. Pour apprendre ensemble, il faut pratiquer la double boucle d'apprentissage chère à Argyris :
- boucle #1 : améliorer notre production en fonction de règles de décisions basées sur nos modèles mentaux
- boucle #2 : améliorer la boucle #1 en examinant ses résultats et en changeant nos modèle mentaux
Une entreprise sujette aux modes technologiques, qui travaille en silos, et où 3 ans = long-terme ne peut pas apprendre efficacement.
Stay Tuned!
publié sur Linked In le 03/05/2023
Le Standard
— Salut, moi c'est Victor.
— Bonjour Victor ! Moi c'est Jérémie. Je t'en prie, prend la chaise qui est là. 🪑
— Merci.
— Donc si je comprends bien tu viens d'arriver, ç'est ça ?
— C'est ça. Et Gauthier m'a indiqué…
— Que tu pouvais binômer avec moi histoire de faire connaissance avec la base de code.
— Exactement.
— Eh bien tu tombes bien, tu vas pouvoir m'aider à corriger ce bug.🖥️
— Je veux bien. Ce sera une bonne entrée en matière, je pense.
— Tu ne crois pas si bien dire… Regarde moi ça. C'est n'importe quoi. Ce truc est codé à l'envers. En plus on ne comprend rien.
— Quel est le problème ici ?
— Le problème c'est cet argument passé à la fonction, ce n'est pas comme ça que ça doit s'écrire. On fait de l'objet, oui on non ?🤬
— C'est quoi le standard ?
— Le standard ? Il n'y a pas de standard ici, tu es libre d'utiliser ce que tu veux. Mais bon, là, il y a des limites, quand même. Regarde moi ça ! Qu'est-ce que tu en dis ?
— En effet c'est un problème.😅
— Et c'est pas comme si on le leur disait pas, hein. On le leur dit, mais il n'y rien à faire. C'est même de pire en pire.
— Bah, sans standard…
— Toi et ton standard ! Tu es bien naïf. Tu sors de l'école ?
— Euh, pas exactement. Disons que je cherche à comprendre…
— Y a rien à comprendre. On sait coder ou on ne sait pas. C'est tout.
— OK.
— … 😐
— … 😐
— Et même, en supposant qu'on établisse un standard —— sans compter le fait qu'on ne sait pas qui serait chargé de le définir —— ça changerait quoi ?
— Bah pour les nouveaux comme moi, ça permettrait de faire moins d'erreurs. Et pour les plus expérimentés comme toi, ça permettrait d’améliorer la base de code.
— Non mais qu'est-ce tu crois : j'améliore la base de code ! J'y passe une soirée sur deux en ce moment !
— Je ne dis pas le contraire… 😅
— Donc ça changerait quoi ? Une fois défini un standard, on fait quoi ?
— Eh bien, en revue de code, on pourrait se référer au standard…
— Qu'est-ce que tu entends par revue, tu veux dire les Pull Requests ?
— Euh, non, je veux dire, relire le code ensemble.
— Alors là je t'arrête, on ne fait pas de revue de code ici, et on n'est pas près d'en faire.
— Je me disais aussi… 🙄
— Une revue de code, tu veux dire, la réunion de 3 heures, où on se prend la tête sur le design jusqu'à ce que le PM vienne sonner la fin de la récré ? Merci, j'ai déjà donné.
— Ah, mais… Ah oui mais non, rien. 🫢
— Si vas-y, quoi ?
— J'allais te demander : c'est quoi votre standard de revue de code, mais laisse tomber.
— C'est une obsession ma parole !
— Ah, peut-être, oui. 😅
— Mais bon, ne t'inquiète pas. Tu es nouveau c'est normal, tu ne comprends pas la culture de la boite. Mais tu vas t'y faire.
— Euh, j'espère ! 👀
Si vous pouviez faire une suggestion à Victor, là maintenant, ce serait ?
🄰 Nous aussi on espère. En tout cas amuse-toi bien ! 🦄
🄱 Reprends tes recherches pendant que tu es encore motivé. 😬
🄲 Insiste : ils vont finir par t'écouter. 🤓
publié sur Linked In le 04/05/2023
Breakpoints
Episode 3 (cf Episode 2 par Laurent Bossavit)
🐌🛑🐢
— Victor ! Ticket 915 : ça te dit ? 🪑
— Yes ! Débugguer, ça me familiarise avec la base de code.
— Oui, ben te familiarise pas trop, parce que ce module là on va le refondre.
— Ah bon ? Quand ça ?
— La roadmap n'est pas encore finalisée, mais ce sera fait avant la fin d'année.
— Donc en vrai, on a du temps pour améliorer des trucs ?
— De quoi tu parles ?
— Jérémie, la semaine dernière, j'ai proposé qu'on essaye une technique de test…
— On a du temps pour les trucs absolument indispensables, pas pour explorer des nouvelles techniques.
— Ok, Ok. Vas-y montre-moi ce bug.
— J'arrive. Tu vas comprendre pourquoi on refond cette partie.
…
— 🤬 Je suis encore passé au dessus du bloc. Comment on fait un point d'arrêt conditionnel, déjà…
— 🥱
— T'endors pas Victor, il n'est que 10h10. Tiens bon !
— Mais c'est tellement leeeeent ! Tu réalises qu'à chaque fois qu'on s'arrête à cette ligne, là, 5482, pour observer le contenu de cet objet, on fait la même chose que l'ordi, seulement 60 millions de fois plus lentement ?
— Qu'est-ce que tu proposes ?
— Tu connais assert
?
— Oui je connais assert
. Où est-ce que tu veux en venir ?
— À la place de ton point d'arrêt, mets un assert
dans le code, sur la condition que tu veux.
— C'est pas bête.
— Comme ça on le lance et on arrive plus vite au moment qui nous intéresse.
— Oui, eh bien c'est aussi ce qu'on fait avec un point d'arrêt, je te signale. C'est juste que je ne me souviens plus comment on crée un point d'arrêt conditionnel…
…
— Bon, eh bien c'est réparé. Victor, tu veux mettre à jour le ticket ? De mon côté, je vais effacer ces asserts
.
— Ah bah non !
— Quoi non ?
— On n'a pas fait tout ce chemin pour rien quand même.
— Quel chemin ?
— Hier on avait : du code, un ticket expliquant comment produire le bug, et c'est tout. Ce matin on a ça, plus des assertions, c'est à dire du code qui documente le code. Et toi tu voudrais effacer le peu de documentation qu'on vient de produire.
— Oui mais non : on ne va garder ça, le code est déjà assez 🤬 comme ça !
— On n'a qu'à les sortir…
— Dans un module appelant tu veux dire ? Tu oublies qu'ils interrogent des variables d'instances et des variables locales tes asserts
.
— On n'a qu'à rendre celles-ci publiques… 😬
— Pas question !
— … 😒
— … 😠
— Bon. Cet assert
, là : il nous dit quel est l'invariant de la classe Facture. Tout à l'heure, il cassait sur la facture donnée en exemple dans le ticket.
— Où est-ce que tu veux en venir ?
— Dans le module appelant, on instancie la même facture que dans le ticket, et on lance la méthode de recalcul.
— Ok…
— Et on repart de l'assert
. On dit : "Même avec remises, une facture garde un montant positif".
— Bien vu.
— Tu es d'accord que ce test fait le même job que l'assert
, mais en mieux ?
— Je dis pas non. Mais ajouter du code à propos d'un module qui va mourir, bof !
— Hmm. On peut faire un break ?
— Faudrait savoir !
— Non je veux dire une pause. J'ai besoin d'un café, là.
publié sur Linked In le 05/05/2023
Couloirs
Dans les entreprises la tolérance au désordre est inversement proportionnelle à la taille de l'organisation. Le désordre est un mal nécessaire pour la toute petite entreprise, qui favorise la résilience et la redondance contre la sécurité et la pérennité.
Si Thomas, qui développe des comptes, venait à passer sous un bus (ou disons à gagner au loto), ses trois coaventuriers pourraient reprendre ses dossiers et s'en sortir à peu près. 🍀
Dans la grande entreprise on a grandi, on s'est organisé et on est devenu fidèle à la fable et à son proverbe : chacun son métier, les vaches seront bien gardées. 🏢
L'entreprise évolue, prend des forces, survit, tout en se complexifiant. Ce faisant, il n'est pas rare que tout en affichant vouloir créer des espaces de collaboration, on y crée des couloirs.
▶️
Dans la note de démarrage du projet (au forfait) destinée à la nouvelle équipe de développement :
Pour rappel, il vous est demandé de ne pas communiquer directement avec les utilisateurs ou les responsables métier.
▶️
Le Tech Lead à une nouvelle développeuse durant un point de mission :
— En somme on est assez content de ton travail.
— Merci.
— Est-ce que tu as des questions ou des remarques ?
— Oui : je me demandais si vous avez lu ma suggestion de faire des revues de code croisées ? Ça pourrait te délester d'une partie du travail.
— Ah oui. Mais Arthur et Bérénice ne souhaitent pas que tu relise leur code.
▶️
Le Tech Lead au Product Owner :
— On a pas mal avancé sur le traitement de rapprochement. Ta spécification était assez claire.
— Tant mieux !
— Avec l'équipe on se demandait si tu pourrais nous passer une copie du fichier que tu traites avec la solution actuelle.
— Ah bah non : ce serait de la triche !
Dans un sens, avoir beaucoup d'espace, c'est inquiétant : où est-ce qu'il faut se placer ? Jusqu'où vont mes responsabilités ? Que se passera t'il si l'espace révèle une incohérence ? Non pas un simple trou dans la raquette, mais un vide béant sur le plateau ?
Un couloir, dans un sens, c'est rassurant : ça a une direction. Quand on marche dans un couloir, au moins on va quelque part.
Mais pour la plupart des personnes qui arrivent dans l'entreprise, et qui sans avoir nécessairement fait l'expérience de l'agilité, sont familiarisées avec les manifestes, les programmes de transformation, et les modèles qui libèrent, la présence d'un couloir, là où elles auraient plutôt vu un espace, pose question. Elles voudraient comprendre l'histoire, se faire expliquer la jurisprudence. Pour un temps, elles remontent à contre-couloir; parfois elles émettent un rapport d'étonnement. Et elles finissent par se résigner : l'entreprise, dans sa sagesse, indique toujours la voie de l'effort minimal.
Stay Tuned !
publié sur Linked In le 08/05/2023
Détrompeurs
Dixit Shigeo Shingo :
Il y a 4 objectifs d'amélioration : plus facile, meilleur, plus rapide et moins cher. Ces 4 objectifs apparaissent dans l'ordre de priorité.
Cette maxime, a elle seule, devrait achever de convaincre les équipes qui travaillent en Lean d'adopter Pair Programming ou Ensemble Programming.
Bien sûr, pour adopter ces pratiques il faut les essayer, les expérimenter, et les ajuster. Pour ce faire, il faut en prendre connaissance et les appliquer telles qu'elles sont décrites et en utilisant son bon sens. On m'a souvent demandé :
— Donc, chez toi, c'est OK de payer 2 personnes devant un écran : une qui code, et l'autre qui regarde ?
À quoi je réponds souvent :
— Bien sûr, pourquoi pas. Là où tu travailles, tout le monde est bien OK pour qu'il y ait une seule personne par écran, mais qui navigue sur des sites de carte Yu-Gi-Oh!
— Mais pas du tout, qu'est-ce qui te fait dire ça ?
— Qu'est-ce qui te fait dire qu'il y a en une qui code, et une autre qui regarde ?
— Bah je ne vois pas d'autre possibilité !
— Bah moi non plus.
C'est là la façon dont l'entreprise traditionnelle, celle qui fabrique trop de couloirs et pas assez d'espace, s'active autour du changement : le changement est proposé par un consultant (ou un coach, ou un coachultant), qui le pose sur la table de réunion pour examen critique. Ensuite de quoi le changement est décortiqué, démonté, analysé, examiné en détail, puis rejeté. Au global, cette activité produit plus de chaleur que de lumière.
Shigeo Shingo enseignait l'art d'inventer des détrompeurs, Poka-Yoke (anti-erreur).
(Un détrompeur kézako ? Observez une prise électrique avec terre).
L'activité qui consiste à développer du logiciel fourmille tellement de détrompeurs que même un débutant en découvre au bout de quelques heures de pratique seulement.
Par exemple, Tristan, qui codait depuis 3 jours, jugea qu'il valait mieux remplacer un peu partout dans son programme le nombre 1.1860
par une constante TauxTva
. Pourquoi ?
-
s'il fait une typo sur un des nombres :
1.8160
, son compilateur s'en fiche. Un nombre c'est un nombre. -
s'il fait une typo sur le nom :
TayxTva
, son compilateur l'arrête, lui notifie une remontrance, et refuse de participer à la mise en production de ce programme.
La recherche de détrompeurs est vitale pour améliorer en continu. La suite qui exécute un milliers de tests auto-vérifiants sur votre système est une forêt de détrompeurs qui épargne à votre projet, plusieurs fois par jour, les difficultés, les défauts, les ralentissements, et les surcoûts. C'est ce qui vous permet de travailler à des problèmes intéressants.
La maxime de Shingo est elle même un détrompeur : lorsqu'un membre de l'équipe propose un changement, si vous commencez par en étudier le coût avant de savoir si ce changement rendrait le travail plus facile, meilleur et plus rapide, recommencez : vous prenez le problème par le mauvais bout.
publié sur Linked In le 09/05/2023
Patinette
— Oui, on fait du Pair Programming, depuis au moins 2 mois, mais c'est épuisant.
— Qu'est-ce qui est épuisant dans le Pair Programming ?
— Parler de la conception, du code, à longueur de journée, 9h30 - 18h.
— Vous codez en binôme de 9h30 à 18h ?
— Si on enlève la pause déjeuner, oui.
— En effet ça doit être épuisant !
— Je ne te le fais pas dire.
— Pourquoi faites vous cela ?
— Quelle drôle de question. C'est ce qu'on est sensé faire. Ça s'appelle : le travail.
— Votre travail, c'est de coder de 9h30 à 18h ?
— Pas tout à fait. Notre travail, c'est de développer un logiciel.
— Et Pair Programming vous aide à faire ça ? Vous obtenez de meilleurs résultats seuls ou en binômes ?
— En binômes, sans contestation possible. D'abord le code est tout de suite de meilleure qualité, vu qu'on ne laisse pas traîner les refactos.
— Mais est-ce que vous codez plus rapidement ?
— Là encore, y a pas photo. Pour identifier un bug, ou résoudre un problème nouveau, deux cerveaux valent mieux qu'un.
— Quel est le problème, dans ce cas ?
— Je te l'ai dit : c'est épuisant…
— Je veux dire : si vous développez plus vite en binôme, votre productivité s'est améliorée, non ?
— Oui. Sans doute.
— Si votre productivité s'est améliorée, pourquoi continuer jusqu'à l'épuisement ? Pourquoi ne pas vous arrêter, je ne sais pas moi, vers 16h ?
— Oulah. Ce serait mal vu.
— Mal vu par qui ?
— Le client. Il nous paye pas pour finir la journée à 16h.
— Je croyais que votre travail, ce n'est pas de coder de 9h30 à 18h ?
— C'est juste que je ne sais pas comment ce serait perçu.
— Si je comprends bien vous avez trouvé une amélioration, mais son application pose un problème.
— En quelque sorte.
— Hmm…
— Qu'est-ce que tu en penses ?
— Je pense qu'une amélioration devrait suivre la maxime de Shigeo Shingo : plus facile, meilleur, plus rapide, moins cher, dans cet ordre. Et votre expérience de Pair Programming semble cocher une partie seulement des critères :
❌ plus facile
✅ meilleur
✅ plus rapide
❓ moins cher
— Pour le dernier critère, tu peux mettre une checkmark. Je te disais sans doute, mais en fait notre vélocité a augmenté depuis qu'on travaille en binômes.
— Comment avez vous décidé de travailler en binômes ?
— Un jour on a juste essayé, puis on on décidé de continuer. C'est tout.
— C'est peut être ça le problème ? L'amélioration continue.
— C'est à dire ?
— Suppose que j'en ai assez de marcher, et que je m'équipe d'une patinette électrique. Qu'est-ce qui va changer ?
— Tu vas te déplacer plus vite ?
— Mais avant ça, qu'est-ce qui va changer ?
— Tu vas devoir apprendre à t'en servir… À freiner, par exemple. Où est-ce que tu veux en venir ?
— Voilà. Ah ça : à quel moment avez vous appris à vous servir de Pair Programming ?
— Drôle de question. Comment tu t'y serais pris ?
— À peu près comme vous, mais en suivant en cycle d'expérimentation, plutôt.
— C'est à dire ?
— Plan - Do - Check - Act.
— Ça ne me dit rien.
— Stay Tuned !
publié sur Linked In le 10/05/2023
Rollers et Scooters
— Midi dix : c'était rapide, pour une fois, ta rétro.
— Oui, 2 dévs sont en vacances, donc on a été un peu plus vite.
— En effet.
— Toi qui milites pour les tests, sois content : on vient de prendre une décision importante. À partir de maintenant, tests auto. obligatoires sur chaque story. C'est dans la DoD.
— OK…
— Tu comprends, on a eu trop de 💩 en prod'. JM veut un changement.
— Euh, c'est qui JM déjà ?
— Le sponsor. Il a eu une longue discussion avec la PO et le Tech Lead. Dis tu aurais un tuto à me conseiller sur BDD ?
— BDD ?
— Behavior Driven Development. C'est ce qu'on va utiliser pour les tests.
— Ouais, mais… Vous n'aviez pas déjà décidé en début de projet d'écrire des tests systématiquement sur tout le code de production ?
— Hein ? Ah oui. Tu veux dire les tests unitaires. On laisse tomber les TUs.
— Ah bon ?
— Ça prend trop de temps, ce n'est pas rentable. Et en plus ça remet le design en question. Déjà, dans l'équipe on n'était plus que 3 à en écrire, et encore, pas sur tout le code.
— …
— Quoi ? Tu penses que ça ne va pas marcher ?
— Euh, je ne suis pas devin.
— N'empêche : tu n'as pas l'air convaincu. Tu connais BDD au moins ?
— Ce n'est pas BDD le problème. C'est l'amélioration continue.
— C'est à dire ?
— Tu te rapelles mon exemple de la dernière fois ? La patinette électrique ?
— Vaguement…
— Disons que vous étiez en train d'apprendre à faire du roller. Avec plus ou moins de succès…
— Clairement les TUs ça ne marche pas.
— Alors maintenant vous essayez le scooter.
— Oui ! C'est plus rapide !
— Mais ça ne s'utilise pas dans les mêmes conditions.
— Certes. Mais toi qui est si malin : comment tu ferais avec ton équipe ?
— On ne ferait pas les changements de cette façon. On suit un cycle PDCA.
— Un cycle quoi ?
— Plan → Do → Check → Act :
📐 Plan : observer, comprendre le problème en vue de définir une expérimentation. Qu'est-ce qui varie dans la qualité du produit ? Pourquoi ? D'où vient le problème ? Si une technique permet d'en venir à bout et qu'on décide de l'essayer, à quoi saura-t'on qu'elle fonctionne ? Avec quelle mesure ? Au bout de combien de temps ?
— Rien ne te dit qu'on ne s'est pas posé toutes ces questions, mais admettons.
— Ensuite :
🧑🏽💻 Do : expérimenter la technique, confronter la solution théorique à la réalité du terrain, en notant ce qui marche et ce qui ne marche pas.
— Ok, BDD, on l'a pas encore essayé mais justement, c'est parti : on va essayer.
— En ayant déjà validé le changement avec le Sponsor ? Vous mettez la charrue avant les bœufs…
— Qu'est-ce tu veux, c'est comme ça que ça marche ici.
— 3ème étape :
🔎 Check : débriefer l'expérimentation, en vérifiant si nos prédictions sont justes ou à côté, et de combien.
— Pour ça il y a la prochaine rétro.
— Dans 2 semaines ?
— …
— et enfin :
📝 Act : valider (ou pas) la technique, et l'ajouter au standard. P,D,C,A.
— Bon. C'est ce qu'on fait, en gros.
— Non. En gros vous faites A,C : Act → Check.
— 🤷♂️
publié sur Linked In le 11/05/2023
Artisanat
Dans un système en crise, on n'améliore pas, on réagit.
Le novice ne peut pas apprendre à barrer si la voile est en feu et qu'il y a un homme à la mer. Quelqu'un lui reprend la barre des mains en criant "la bouée ! à l'avant !", puis on vire de bord, on affale la voile, pendant qu'une autre personne sort un extincteur. Une fois au port il fait le bilan de sa sortie : beaucoup d'action, d'émotions fortes, mais d'apprentissage, point. S'il est perspicace, il songe à changer d'école de voile. ⛵️
Dans un projet en crise, on observe du travail tard le soir, des discussions houleuses, des mouvements de personnes, mais de l'apprentissage, point. Il est pas loin de 9 heures, le chef de projet répond aux questions du novice tout en mastiquant un bout de pizza froide. "Ce qu'on fait dans ces cas là ? Eh bien on débuggue jusqu'à pas d'heures, on maquille un peu le planning, on échange un jalon infaisable contre un autre jalon un peu moins infaisable… Et voilà, c'est le métier qui rentre !" 🍕
S'il est perspicace, le novice réalise que le "métier" n'est pas près de rentrer ici, vu qu'ici c'est la maison des portes qui claquent, et non la maison où apprendre à développer.
Dans la mesure où il compte uniquement sur son temps personnel pour acquérir de nouvelles compétences, il réalise son besoin de préserver ce temps contre les crises du boulot, contre les heures passées en douce à corriger le code de la boite ou à ressasser le dernier drame avec le PO. Dans son cœur il remplace peu à peu l'enthousiasme et l'engagement par le détachement. Il se dit que la technologie ne fait pas tout, et qu'à ses prochains entretiens, il posera plus de questions, des questions nouvelles.
🚪
De retour sur le marché du travail, où s'organisent les Championnats du Monde du Code Propre et de l'Architecture Hexagonale, où on pressurise des candidat·es Full Stack avec des questions DevSecOps, il entre à nouveau en compétition avec des centaines de têtes bien pleines — et parfois bien faites — proposant leurs services et leurs compétences aiguisées par les heures passées à apprendre, à pratiquer, à échanger.
Il a lu "The Software Craftsman", "Clean Craftsmanship", "Software Craft", "The Pragmatic Programmer" ou "Software Craftsmanship", et il se demande :
Si mon métier doit être un artisanat, où se fera le compagnonnage, sinon dans l'entreprise ?
Avec un peu de chance, et en posant les bonnes questions, il finira par trouver un système relativement stable dans lequel on peut améliorer en continu.
- Est-ce que le standard de l'équipe a évolué récemment ?
- Pouvez-vous me dire comment cela s'est produit ?
- Est-ce que vous documentez votre standard ?
- Est-ce que je peux en avoir un aperçu ?
Ces questions vont lui fermer les portes des entreprises où l'on n'apprend pas, et lui ouvrir celles des entreprises où on apprend en équipe.
Souhaitons lui bonne chance et bon courage ! 🏞
publié sur Linked In le 12/05/2023
Standard
- Revue et Standard
- Sicob
- Commentaires
- Quinconce
- Plus Moins Intéressant
- Recadrage
- Foire Aux Questions
- Auto-Prescription
Revue et Standard
— Ça va Jérémie ?
— Tu tombes bien, Victor, prend une chaise, et regarde un peu ça. 🪑
— Quoi donc ?
— Je suis sur le code du module de vente. Franchement, le développeur qui a codé ça, j'aimerais bien le rencontrer…
— Et tu lui dirais quoi ?
— Je lui demanderais de reprendre le travail 🤬
— Bah, je suis sûr qu'il a fait de son mieux.
— Toi Victor, tu es profondément naïf.
— Ah bon.
— Attends… Voilà. Regarde, comment il a nommé la variable qui stocke le résultat de la requête : toto !
— Ah ouais quand même.
— "toto" ! Qu'est-ce qu'on pourrait trouver de pire comme nom de variable ?
— "toto2" ? 😜
— Bon sang, si tu ne sais pas comment nommer tes variables, c'est que tu ne sais pas ce que tu fais, c'est tout. 😡
— Ou bien c'est que tu viens juste de mettre au point ton appel de requête, que tu as été interrompu, que tu as mis ce nom là pour que ça compile en te promettant de le revoir juste après l'interruption…
— Interruption, moi je veux bien, mais on relit son code quand même !
— Ça c'est typiquement le truc qui ne serait pas passé, dans une revue.
— Et voila, tu recommences. Je savais que tu allais sauter sur l'occasion de faire cette suggestion. Mais ça ne prend pas avec moi.
— Reconnais qu'il y a quand même un truc bizarre : pour toi nommer une variable "toto" dans du code de production, c'est contraire au standard ?
— C'est ni fait, ni à faire.
— Donc il y a un standard, ici.
— Non, pas au sens où il faudrait vérifier le code qu'écrit chacun de nous. Mais il y a un minimum !
— Comment tu sais que le code respecte le minimum ? Je veux dire, sans le passer en revue ?
— Je le sais parce que je sais avec qui je travaille !
— Donc, la personne qui a écrit "toto", là, tu ne savais pas que tu travaillais avec elle ?
— Je travaillais pas encore ici quand ce code a été écrit, figure-toi… Attends, je regarde l'historique… Ah si. 😠
— … 🙄
— Quand même, tu nous vois faire des réunions pour trouver des trucs aussi idiots ? On aurait l'air de quoi ?
— Hum. D'abord, je te l'ai déjà dit, une revue de code, ce n'est pas une réunion. Ensuite s'il y avait des revues ici, vous n'auriez pas vu cette boulette. L'auteur aurait relu et corrigé son code avant de le soumettre.
— Ha ! Et à quoi servirait la revue dans ce cas ?
— À détecter des problèmes plus intéressants, bien sûr.
Stay Tuned !
publié sur Linked In le 15/05/2023
Sicob
— Bonjour ! On peut se tutoyer. C'est la DSIO qui t'envoie, c'est bien ça ?
— Oui. On m'a dit de me présenter à 9h.
— Parfait. Je pense que tu vas commencer par faire le tour de toutes les applications du service. La personne qui en avait la charge travaille désormais dans une de nos filiales américaines, mais elle a laissé quelques notes.
— Entendu.
— Bon, il faut que je te prévienne, c'est un peu le SICOB ici…
(Wikipedia : À la fin des années 1980, et jusqu'à l'uniformisation qui s'opéra peu à peu avec le décollage de l'IBM PC, le SICOB se caractérisait par un grand foisonnement, très hétérogène, d'ordinateurs et de périphériques. L'expression « c'est le Sicob » reste encore couramment utilisée aujourd'hui pour désigner des ensembles informatiques, logiciels ou matériels, caractérisés par leur manque d'homogénéité.)
L'action se déroule en 1990. Je visite mon premier parc d'applications legacy :
- pas de tests automatisés : (écrire un second programme qui exercerait le code du premier ? Une idée qui semblerait un rien audacieuse pour des développeurs chevronnés de l'époque, pour l'entreprise où je suis en mission, une chimère)
- une équipe de développement défunte
- une remarquable absence de standards dans ce qui "fait tourner le service", soit une douzaine d'applications "micro" tournant sur PC.
- Framework (la "suite bureautique" à tout faire pour qui est bricoleur) et son langage de programmation, FRED
- Lotus 1-2-3 et ses macros (indispensable dans une Trésorerie)
- Turbo Pascal + BTrieve
- C + Informix
- APL + fichiers dBase III
À l'opposé de cette flore, il y a la "Direction des Systèmes d'Information et de l'Organisation", d'où je viens, où l'on parle principalement PL/I COBOL, et DB2.
La raison d'être de ce "SICOB" ? En 5 ans cette direction s'est équipée de PCs, et certains de ses cadres de livres de programmation. À la DSIO le délai de réalisation d'une application se compte en semestres, ici il se compte en semaines.
Les répercussions de cette vélocité et de cette versatilité en termes d'efficacité sont profondes. Mais quid de la maintenance ?
Pour maintenir ces applications, il m'a fallu apprendre vite (pour maîtriser les logiciels spécifiques un poche "Marabout" suffisait), mais aussi apprendre "loin", c'est à dire ne pas se perdre en s'isolant dans ces systèmes fermés. Pour cela, investir dans une matière plus durable et plus fondamentale (merci les éditions Masson, Microsoft Press, Intereditions…). Cette "culture" j'ai pu chaque fois la retrouver dans le code des applications. Elle vit à travers ce code.
🎛🤖👾💻🥱
— OK, M. Génération X, chouette album photo. Mais on en retient quoi ?
— Rien, sinon mes 3 conseils de survie :
-
Survolez le foisonnement de technologies, en mode radar 📡
-
N'approfondissez que ce qui peut vous coûter cher ou vous pincer très fort ☢️
-
Pratiquez vos fondamentaux 📚
(sur ce je déclare la partie de paintball/commentaires ouverte)
publié sur Linked In le 16/05/2023
Commentaires
Thèse : Tout doit être standardisé. Il suffit de définir LA bonne manière pour chaque chose. De cette manière on évite les discussions et les conflits d'idées.
Antithèse : Rien ne doit être standardisé. Chacun fait selon ses critères et ses préférences. De cette manière on évite les discussions et les conflits d'idées.
Synthèse : Une équipe établit parallèlement au logiciel qu'elle développe, un état de l'art définissant la meilleure façon de faire étant donnés son contexte, ses objectifs et ses contraintes. Les discussions et conflits d'idées sont incontournables si elle veut améliorer cet état de l'art.
🗺️🪜🧯
Prenons comme exemple les commentaires sur le code, un sujet qui comme la position des accolades ou l'espacement vertical, suscitent des débats animés à proportion inverse des enjeux, ayant plus d'impact sur les lecteurs du code que sur le comportement de celui-ci à l'exécution.
Pendant longtemps, la règle la plus courante a été de commenter le code, afin de le rendre plus compréhensible. J'ai eu l'occasion de travailler dans des environnements où le "taux de commentaire" était systématiquement mesuré. Qui dit mesurer dit surveiller. Qui dit surveiller dit maquiller. Dans certain cas — dans certains cas seulement — la règle des commentaires contribuait à d'absurdes initiatives de mise en conformité.
Avec la popularisation grandissante du refactoring et des "code smells" les commentaires sont presques devenus un "anti-pattern" : le commentaire est un déodorant apposé sur un code smell. D'où :
Ne commentez pas le code, réparez le.
Ce pattern, allié à d'autres tels que "Intention Revealing Names", "Extract Method", etc. fait reposer la maintenabilité du code principalement sur le code lui même ! (Une idée apparemment simple qui n'aurait pas marché du temps où l'on codait principalement en assembleur 😉)
Au détour d'une discussion récente avec des collègues, j'ai pu réaliser qu'aucune de ces deux règles : "Commentez votre code" et "Ne commentez pas le code, réparez-le" ne peut fonctionner de manière absolue. La première fait le présupposé que tout code quelqu'il soit manque de clarté. La seconde suggère que le code qui manque de clarté devrait être interdit, et réparé séance tenante par l'équipe, à qui son état de l'art dicte la perfection, rien de moins.
La règle qui fonctionnerait à mon sens, et qu'une équipe pourrait facilement intégrer à son état de l'art, la voici :
Commentez le code que vous ne pouvez pas réparer
Exemples :
// variable globale posée à des fins de test
// agencement
…
// action
…
// assertion
Le but d'un état de l'art n'est pas d'inscrire le projet dans le ciel abstrait des Lois du Génie Logiciel, mais d'aider l'équipe à progresser dans sa manière de résoudre un problème posé dans un contexte et des objectifs donné à un instant t.
Stay Tuned !
publié sur Linked In le 17/05/2023
Quinconce
🧱
— Franchement, mettre les parpaings en quinconce, c'est une perte de temps, tu ne crois pas ?
— Mais non ! C'est prouvé ! Et même éprouvé !
— Désolé, mais je ne vois aucune étude qui démontre le R.O.I des parpaings en quinconce. En les alignant, franchement ça va plus vite, pas besoin de mesurer, c'est plus simple, et on peut montrer des résultats au donneur d'ordre plus rapidement.
— Oui mais ton mur risque plus fort de te tomber sur la tête.
— Et pourquoi ça ?
— Parce que le ciment est plus fragile que le parpaing. Si il y a une faille, avec des parpaings alignés elle va jusqu'en bas. En quinconce elle s'arrête au rang du dessous. J'arrive pas à croire qu'il faille t'expliquer ça.
— OK, admettons. Mais si le ciment est plus fort que le parpaing, hein ? Qu'est-ce que tu en dis ?
— Ah si le ciment est plus costaud que le parpaing, je dis pas. Ça se discute.
— Ah ! Tu vois ? Tu vois ?
Comme Jérémie et Victor sont développeurs et non maçons, l'analogie s'arrête là. Quoiqu'ils décident à propos de leur état de l'art, aucun mur ne va leur tomber sur la tête, au propre comme au figuré.
Sur un chantier, un contremaître ferait remplacer les beaux alignements de Jérémie. Sur un projet, le manager n'a pas le temps de rentrer dans le technique à ce point. Tout ce qu'il entend, c'est un Jérémie qui va plus vite, et un Victor qui insiste pour qu'on fasse les choses bien, mais qui fait probablement de la sur-qualité.
L'état de l'art de la maçonnerie progresse depuis des millénaires, lentement mais sûrement. L'état de l'art du développement logiciel est chamboulé tous les 6 mois par les annonces fracassantes d'équipes dont les seuls budgets R&D mettraient votre PME à l'abri pour plusieurs années. Ces annonces sont relayées par les early adopters et les consultants, lesquels n'ont pas tous bâti de grands projets, mais ont tous 20/20 en Lecture Rapide.
À propos d'early adopters, en date d'avril 2023, InfoQ classe les technologies CQRS, Event Sourcing, Eventual Consistency dans son cadran "Late Majority". À ce stade avancé de déconnection avec le terrain, la seule limite d'InfoQ devient la vitesse à laquelle cette compagnie peut spéculer sur ses propres spéculations. Quand à lire ses recommandations pour mon prochain projet, c'est comme si je lisais Gala pour savoir comment le roi Charles ou le prince Albert font pour optimiser leur budget Cérémonies.
Dans mon expérience, il y a peu de Null Pointer Exceptions (ou de SegFaults) qu'une session de relecture de code n'aurait pu détecter. Relire du code ensemble (voire, l'écrire ensemble) c'est une exemple de façon de poser les briques en quinconce. Mais comme nos projets coûtent beaucoup d'argent, nous alignons les briques. Chaque projet repousse les limites des compétences des équipes qui les entreprennent. Nous cherchons à maximiser le nombre de fonctionnalités, tout en minimisant le coût de la qualité. Nous ne construisons pas pour durer.
🏚
publié sur Linked In le 18/05/2023
Plus Moins Intéressant
☕️🥐
— Alors comment ça c'est passé cette première démo avec ton équipe ?
— Bah ! À part le plantage au milieu de la partie la plus intéressante, tu veux dire ?
— J'en ai eu des échos…
— Et le client qui décide de partir au moment où le Tech Lead commence à examiner le code, embarrassant.
— J'imagine…
— Franchement je suis le premier surpris, je me figurais que le projet était au point.
— Tu viens d'arriver, prends un peu le temps pour comprendre comment les choses se passent ici.
— "cannot read property of undefined" ! Je te demande un peu.
— Un classique.
— Ça n'a pas l'air de t'étonner…
— Pas vraiment non.
— Du coup j'ai fait un point avec l'équipe. C'était un peu compliqué.
— Ah oui ?
— Il y a ce nouveau, là, Victor. C'est son premier poste. Mais j'ai l'impression que le courant ne passe pas entre lui et Jérémie.
— Jérémie, c'est le Tech Lead, n'est-ce pas ?
— Exact. Je leur ai seulement posé une question : est-ce que ce code a été relu ? Et c'est parti en live.
— C'est le genre de question qui met les gens sur la défensive, note.
— Je ne sais pas, mais en tout cas, il y a du travail, parce que leur système de développement n'est pas au point.
— Qu'est-ce que tu comptes faire ?
— Ah mais j'ai déjà commencé. Tu me connais. J'ai lancé un PMI sur le sujet.
— PMI ?
— Plus/Moins/Intéressant. J'ai gardé les résultats, regarde.
RELIRE LE CODE À PLUSIEURS : PLUS / MOINS / INTÉRESSANT
➕
- détecter certains problèmes de code plus rapidement
- expliquer son code à l'oral
- apprendre à propos de ce qu'on ne savait pas qu'on ne savait pas
- apprendre des trucs sans avoir à les demander
- faire connaissance avec le style de chacun
- partager sa culture
- prendre des décisions cohérentes (au lieu de les laisser pendantes)
- conduit l'équipe à se mettre d'accord sur un standard
➖
- mobilise du temps en équipe pour un résultat discutable
- force les gens à se mettre d'accord
- discussions, débats chronophages
- autorisation de critiquer, d'attaquer, d'enfoncer les autres
- pousse à ne pas chercher par eux-mêmes
- remise en question du savoir-faire
- perte d'originalité et de créativité
- on ne l'a jamais fait
- les autres équipes ne le font pas
ℹ️
- effet canard en plastique mais avant d'avoir des problèmes
- si le code a des tests, la revue peut aller plus vite
- pour avoir des revues il faut un standard, pour avoir un standard il faut des revues
- d'accord pour faire une appli ensemble, pas d'accord pour créer un standard ensemble
- est-on obligé de se critiquer pour s'améliorer ?
publié sur Linked In le 22/05/2023
Recadrage
— Bon Victor, tu sais pourquoi on doit se parler aujourd'hui ?
— Si je ne me trompe pas, c'est à cause de la discussion de l'autre jour, après la démo… 🧱
— Discussion ? Ce n'est pas des discussions que vous avez toi et Jérémie, ce sont des batailles !
— Je reconnais que c'est allé trop loin.
— Avoir un avis tranché sur la qualité de ce qu'on fait, c'est bien, mais à un moment il faut faire la part des choses.
— C'est juste qu'on a une démo qui plante, et qu'on ne fait rien pour changer ça.
— Jérémie est à son poste depuis 3 ans. Il en sait bien plus que toi sur le produit. Si tu penses pouvoir apporter des améliorations, ce serait une erreur de ne pas t'en faire un allié.
— OK.
— En toute franchise : est-ce que tu considères toujours avoir fait le bon choix en nous rejoignant ?
— Franchement, ici c'est très différent de l'entreprise où j'ai fait mon stage. Je ne m'y attendais pas.
— À quel point différent ? Ton stage portait sur le même type de produit, la même technologie.
— Jérémie réagit toujours comme s'il considérait qu'il a avec lui une équipe de bras cassés.
— Je ne peux pas te laisser dire ça. C'est mal le connaître.
— Il est le garant de la qualité du projet.
— Bien sûr. Ça te choque ?
— Non. Mais est-ce que ça veut dire que s'il n'est pas là, il n'y a pas de qualité ?
— C'est plus compliqué que ça.
— Dans mon équipe précédente, le garant de la qualité ce n'était pas une personne.
— Ah non ? C'était quoi ?
— Le standard.
— Les standards, c'est une chose…
— Non, pas les standards, le standard. C'est à dire : la meilleure pratique de l'équipe à l'instant t pour une activité donnée.
— Oui, bien sûr. Et ce n'est pas ce que vous mettez en place, toi, Jérémie et toute l'équipe ?
— Bah non.
— Et qu'est-ce qui te fait dire que non ?
— Est-ce que tu dirais que tu as un standard si on ne parle jamais du standard ?
— Qu'est-ce que tu veux dire ?
— Pas de debrief, pas de relecture, pas de revue. Ça prend trop de temps, paraît-il.
— Si ça doit partir en bataille de rue à chaque fois, je te confirme qu'on a zéro minute à consacrer à ça.
— C'est parce qu'on ne sait pas les faire.
— Peut-être.
— Pour s'améliorer, il faudrait commencer. Mais non. On avance dans le noir. Un coup ça marche, un coup on tombe sur un truc. On n'apprend pas.
— Tu exagères. On apprend ici, plus qu'ailleurs, c'est certain.
— Comment le savoir ? Il n'y a pas de standard. C'est comme si on produisait les pièces et qu'ensuite on cassait le moule.
— Qu'est-ce que tu proposes ?
— Je propose qu'on décrive le standard.
— Et comment tu proposes de faire cela : décrire le standard ?
— Simple : en relisant du code ensemble.
— Mais quel code ? Tout le code ? Où est-ce qu'on trouve le temps ?
— Pas tout le code d'un coup, évidemment.
— Par où commencer ?
— Par le code qui plante. Ce serait un bon début.
publié sur Linked In le 23/05/2023
Foire Aux Questions
0️⃣ Quelle est la procédure standard pour améliorer notre standard ?
Relire le code ensemble, afin de trouver des défauts 👀
La personne qui a écrit le code explique son fonctionnement💡
L'équipe identifie des défauts 👆
Une personne prend des notes 📝
Une autre surveille le temps ⏳
À la fin de la session l'équipe décide du sort du code :
- OK : le code va en production ✅
- OK si les améliorations … sont apportées 🚦
- KO : à revoir avant d'aller en production ❌
1️⃣ On peut trouver 1000 défauts à un code : lesquels sont les plus importants et par où commencer ?
Les défauts les plus importants vont émerger en priorité durant la relecture. 🧩
Commencer par le code qui présente le plus de problèmes en production ou le code particulièrement difficile à faire évoluer 🔥
2️⃣ Tout est relatif en qualité logicielle : comment se mettre d'accord sur ce qui est un défaut ou non ?
Comme avec tout sujet de désaccord : en en parlant et en prenant des décisions. C'est l'objet de la relecture de code. 🗺
3️⃣ Quel genre de problème peut on trouver ?
- standard pas respecté : le code doit être mis au standard ❎
- absence de standard : le standard doit être amélioré pour résoudre ce problème ➕
- cas de conception : ce problème spécifique doit être résolu dans une autre session de conception 📐
4️⃣ Comment peut-on dire "ce n'est pas standard" si on n'a pas de standard ?
Si nous avons un produit qui tient à peu près debout en production, alors nous avons un standard, même minimal. Le tout est de ne pas le laisser se dégrader. 🕸
5️⃣ Trouver des défauts c'est bien gentil, mais si on pas le temps de les corriger ?
Si nous prenons le temps de corriger les défauts, nous allons améliorer la qualité de notre application, et donc perdre moins de temps sur des problèmes en production. ♻️
Identifier des défauts que nous ne corrigerons pas revient à organiser la perte de temps 💸
6️⃣ Comment éviter la violence des critiques pendant la revue ?
En respectant les personnes. On peut être critique avec un produit sans être critique avec la personne qui crée ce produit 🙄
On peut également suggérer des améliorations au lieu d'énoncer des critiques 🪜
7️⃣ Comment tu vas éviter les discussions à l'infini ?
Via le process cf 0️⃣
8️⃣ Pourquoi est-ce que ça marche ?
La relecture de code
- trouve des défauts 🔦
- améliore le standard 🗺
- améliore la communication à propos du standard 🤝
- améliore la cohérence de l'équipe 💫
9️⃣ Et tu crois que c'est ça qui va sauver le projet ?
Je préfèrerais travailler sur un projet qui n'a pas besoin d'être "sauvé" 🚒
Mieux vaut prévenir que guérir, mais si vous vous en sortez mieux pour moins cher en corrigeant la prod', ne faites pas de prévention 🤷♂️
🔟Quel risque comporte cette stratégie ?
La stratégie de prévention élimine les problèmes. En l'absence de problème, les décideurs décident d'éliminer la stratégie de prévention. 🤯
publié sur Linked In le 24/05/2023
Auto-Prescription
Merci Mauko pour ta contribution à cette conversation à propos du standard. La distinction que tu fais entre descriptif et génératif, complexe et simple, invite à considérer comment on peut parfois "altérer" un standard récemment acquis.
Par ex. une équipe met en place une démarche inspirée de Scrum. Chaque jour à une heure fixe, l'équipe se réunit afin de faire le point rapidement sur ce qui empêche chacun d'avancer.
Après un temps, le daily meeting traîne en longueur, (beaucoup de sujets, suscitant des longues mises au point) 🥱
Ou bien, lorsque le Scrum Master n'est pas présent ce jour là, la réunion n'a pas lieu 🕳
Ou bien la réunion se transforme en rapport d'activité quotitien au PO ou au SM 🧐
Autre exemple : une équipe se forme à TDD, à la suite de quoi les développeurs essaient de suivre le cycle Test-Code-Refactor :
- Ecris d'abord un test qui ne passe pas
- Ecris le code le plus simple qui fasse passer ce test
- Remanie le code sans en changer le comportement
Après un certain temps, l'étape de refactoring est négligée pendant plusieurs cycles, jusqu'à devenir importante au point de créer un ticket de refactoring 🧻
Ou bien le code écrit à l'étape 2 implémente bien plus que ce qui suffirait à passer le test 🔥
Ou bien l'étape de test reprend place après l'étape de code ("comment tester une méthode privée ?") 🔄
Ces exemples d'altération d'une pratique ne sont nullement une fatalité. D'autres équipes, sur la base des mêmes sources d'informations, des mêmes formations, pourraient très bien persister dans leur pratique et bien sûr l'améliorer. Cela ne tient pas à la nature de la pratique elle-même, mais à la manière dont elle est acquise et intégrée par l'équipe, qui se l'approprie ou non, dans son contexte.
Un standard imposé de l'extérieur (par une autorité ou une tradition quelconques) sera d'autant plus facilement altéré (voire défiguré) qu'il est a) mal compris par ceux qui l'imposent, b) vécu comme un carcan par ceux qui le "reçoivent". L'amélioration continue ne marche pas à coup de décrets.
Le standard, c'est l'état de l'art de l'équipe, c'est à dire l'ensemble des pratiques qu'elle se donne comme la meilleure façon de résoudre un problème étant donnés ses objectifs et contraintes.
Il inclut des règles simples ou complexes, précises, ou génériques. Aucune de ces "heuristiques" ne garantit de résultat dans l'absolu : elles sont seulement reconnues et éprouvées par l'équipe qui les a intégrées, dans le contexte où elle se trouve.
-
simple, tacite, quasi universel : indenter le code 🗺
-
complexe, souvent vrai, incomplet : écrire des TUs au fur et à mesure afin d'éviter des problèmes une fois en production 🧯
Le standard constitue t'il une prescription ? Pour une personne qui rejoint l'équipe, sans doute. Pour l'équipe elle-même, certainement pas. C'est tout l'objet du standard que d'être constitué et amélioré par l'équipe elle-même au cours de la réalisation.
Stay Tuned !
publié sur Linked In le 26/05/2023
Transmission
- Transmission
- Bras de Mer et Bras-Cassés
- Où apprendre et s'améliorer ?
- Transmissions
- Auto-Formation
- Apprentissage, Performance
Transmission
L'équipe de Victor et Jérémie fait une relecture de code. La conversation s'engage entre Victor, et Tom qui a modifié le code.
— Question : y a t'il des tests ?
— Hmm. Il y en a eu, à un moment. C'est Clara qui les avait écrits.
— Qui est-ce ?
— C'était une développeuse sur le projet. Mais elle est partie en fin d'année dernière. Attends, je peux peut être retrouver les tests en consultant l'historique…
— Et donc, Clara est partie, les tests sont partis avec elle ?
— Euh non, ce n'est pas comme ça que ça s'est passé.
— …
— Ses tests étaient trop coûteux à maintenir. À un moment, on était en mode crunch avec une grosse échéance à tenir, et on avait une modif importante sur la signature de certaines méthodes, et ses tests bloquaient à la compilation. Donc on a décidé de les retirer du build.
— Mais si Clara n'avait pas quitté le projet, ce code aurait des tests ?
— Peut-être. Peut-être pas.
😔
C'est le lendemain de la naissance de mon 2ème fils. Je suis dans la chambre d'hôpital avec sa maman et lui, et son grand frère de 3 ans. L'infirmière entre, nous lui disons bonjour. Elle dit :
— Eh ben ! On voit que c'est l'équipe de nuit qui s'est occuppé de cette chambre…
😟
Deux situations que rien ne rend comparables sauf deux points :
- c'est un travail d'équipe
- il n'y a pas de transmission
🏃♀️🏃🏽🏃🏼♂️🏃🏼♂️
Un projet de développement, c'est un peu comme une course de relais (seulement plus complexe, et moins physique 😅). C'est un travail d'équipe et de transmission. Courir vite a une certaine importance, mais sans coordination, cela ne sert à rien.
Imaginez une course de relais durant laquelle un des coureurs aurait quitté la course avant la fin. Les entraîneurs cherchent un remplaçant, vite. Ils abordent quelques personnes entre la piste et les gradins.
— Tu sais tenir un bâton ?
— Oui.
— Tu cours vite ?
— Je pense, oui.
— Alors arrive ici !
Ridicule, n'est-ce pas ? C'est pourtant de façon analogue que se déroulent beaucoup projets de développement. Une équipe est formée, à partir d'invididus sélectionnés et triés sur le volet. Pour être recrutée chaque personne met en valeur ses compétence, son expérience, sa passion pour le code, son goût d'apprendre. Une fois l'équipe en place, chacun contribue à faire évoluer l'état de l'art de l'équipe, en proposant des améliorations, voire en les appliquant directement. Le produit logiciel résultant représente à l'instant t la quintessence de ce que cette équipe peut réaliser, dans le contexte où elle se trouve, étant donnés ses objectifs.
Si l'objectif est de créer un POC, l'équipe place le focus sur un aspect important en délaissant le reste.
Si c'est de créer un système viable pour 5 ans, elle place le focus sur le standard. Elle le fait en observant, en planifiant, en expérimentant et en débriefant. C'est sa manière d'améliorer durablement son état de l'art.
Pas d'expérimentation, pas de transmission ⇒ pas de standard, pas d'amélioration.
publié sur Linked In le 29/05/2023
Bras de Mer et Bras-Cassés
— Le projet a déroulé 4 sprints déjà, et ton n'équipe n'a pas gagné en vélocité. Qu'est-ce qui explique cela ?
— J'ai des bras-cassés.
— Intéressant… Ils sont tous arrivés ici, dans la boite d'abord, puis au 5ème étage, puis chez toi… 🙄
— Non, bien sûr. Mais tu vois ce que je veux dire…
Reporter la suite de cette conversation n'aurait pas d'intérêt : sa valeur d'apprentissage vient subitement de tomber à zéro. Le Scrum Master qui parle ici de son équipe s'en remet à la sacro-sainte logique du mérite et de la compétence individuels : les autres ont des bons, il a des mauvais. Tout est dit.
La posture du blâme — moi je suis OK, c'est l'autre qui n'est pas OK — est notre tactique la plus courante lorsque notre besoin de sécurité émotionnelle n'est pas rempli. C'est un remède universel : on le trouve partout, à l'école, à la maison, en politique (où il fait rage), dans la presse, les media, et bien sûr au travail.
Au travail, la palette du blâme se décline en différentes nuances et degrés de toxicité. De l'Erreur Fondamentale d'Attribution jusqu'à la tyrannie de la mauvaise foi, dans chaque situation on retrouve un invariant : là où règne le blâme, on accorde peu d'importance au standard, à la transmission, à l'amélioration continue.
Dans beaucoup d'entreprises où l'on saura vous dire qui sont les "bons" et les "mauvais", on ne pourra pas ne serait-ce que vous guider vers une trace écrite qui indiquerait l'existence d'un standard.
Il y a quelques jours, par pur besoin de perdre mon temps, je regardais sur youtube des vidéos de vacanciers plantant leurs hors-bord hors de prix sur le bras de mer Haulover près de Miami Beach. Après une bonne heure de visionnage, 2 phénomènes m'ont frappé par leur régularité :
-
le bateau arrête net sa progression la 2ème fois qu'une vague prend l'avant de plein fouet
-
jamais aucun des passagers sur le bateau ne porte de gilet de sauvetage
Pour résumer : les navigateurs qui ont des difficultés dans ce passage (particulièrement difficile) en ont également avec le respect d'un standard sur le bateau. On peut en déduire qu'ils n'ont pas été suffisamment formés à la navigation : elle n'est pas leur métier, et probablement même pas leur hobby. Ici l'amélioration n'est pas continue, elle est occasionnelle (et le prix à payer exhorbitant).
🛥🌊🚤
Revenons sur la terre ferme : cette équipe de développement, dont la vélocité ne "décolle" pas, elle a un cadre, qui devrait lui permettre de naviguer sans danger dans les bras dangereux du projet, mais aussi de sécuriser sa productivité : un standard. Un ensemble de dispositions, de règles, sur lequel elle débriefe régulièrement, afin d'améliorer en continu.
Ce standard, ce serait à la fois un support et un matériau de premier choix pour notre Scrum Master. Ça lui permettrait aussi de quitter sa posture de blâme. 🗺
publié sur Linked In le 30/05/2023
Où apprendre et s'améliorer ?
Dans une entreprise qui manufacture des produits, pour peu qu'elle soit gérée dans une approche d'amélioration continue, l'amélioration se produit sur le lieu de travail, et non en dehors. Ses managers n'exigent pas des employé·es qu'ils ou elles améliorent leur travail le soir ou le week end, en pratiquant chez eux 5S, jidoka ou kaizen. 🧱
Dans la plupart des entreprises où l'on développe du logiciel, l'apprentissage se produit en grande partie hors du lieu et du temps de travail. 🛋️
Si vous êtes un·e développeur·se, ou tech lead voici une question pour vous :
Imaginez vous et votre équipe ayant travaillé tout ce temps sur votre projet (6 mois, 1 an, 5 ans ?) sans aucun recours à votre ordi perso, mais uniquement sur le matériel et les horaires du projet. Pensez-vous que l'état de l'art de votre équipe serait au niveau où il se trouve actuellement ?
Dans le développement logiciel, des pratiques telles que 5S, ou Jidoka n'ont pas leur équivalent (immédiat). Et pour ce qui est du standard on s'en remet à l'idée commune que l'on se fait de l'état de l'art du moment sur le marché.
Une approche d'amélioration continue spécifique au développement logiciel doit inclure à mon sens les pratiques essentielles de prévention des défauts et de réduction de la "friction" que présente toute base de code existante :
- tests à grain fin, automatisés, permettant de sécuriser le comportement du code contre les régressions
- relecture du code, permettant de tuer dans l'œuf les défauts de conception
- refactoring en continu, assurant la fluididité de la communication des idées dans le code
Or ces 3 pratiques ne sont pas "mainstream", loin de là. Elles sont rassurantes à lire sur un CV, mais ne sont pas encouragées une fois sur le terrain, parce qu'elles entrent en conflit avec les échéances intenables et les livraisons en retard, aggravées par les problèmes de qualité. 🚒
Elles font également l'objet de controverses sur les réseaux sociaux. Les développeurs forment une population jeune, qui n'hésite pas à casser les vieux préceptes sur la base d'une expérience insuffisante, ce qui fait le ravissement des courtiers en idées nouvelles. Relire du code ensemble, quelle idée terriblement 20ème siècle. Les tests unitaires ? Une perte de temps. 😎
Ces controverses arrivent jusqu'à l'entreprise, où elles renforcent le barrage fait aux pratiques éprouvées. "Aucune étude ne démontre l'efficacité de TDD". Aucune étude ne démontre l'efficacité du Code & Fix non plus, mais cela ne change rien : en s'appuyant sur les acquis individuels d'artisans logiciels qui s'instruisent à la maison, au lieu de faire de l'amélioration continue en équipe le cœur de l'apprentissage, l'entreprise encourage le turn-over et s'enfonce dans le legacy.
Beaucoup d'entreprises se demandent comment garder leur développeur·ses. Suggestion : faire en sorte qu'on apprenne plus facilement chez vous en équipe que tout·e seul·e sur internet.
publié sur Linked In le 03/06/2023
Transmissions
Il y a 4 jours se déroulait AlpesCraft, la conférence et non-conférence que je ne veux manquer sous aucun prétexte !
J'ai eu le privilège d'y animer pour la première fois une session sur le Legacy en forme d'Escape Game, avec un succès …mitigé 😅. La dynamique du groupe (nombreux) y a pris trop de place et la technique pas assez. Merci aux participant·es pour leur patience et pour leurs retours judicieux, qui me donnent des pistes d'amélioration précieuses.
Andrea Chiou et moi avons proposé un atelier métaphorique, Empathy Toys, ou comment explorer à l'infini nos possibilités et nos barrières de communication. Une session riche en énergie comme en enseignements. Les connections entre cet atelier/jeu à contraintes et le "knowledge work" en général sont frappantes.
Nous avons aussi proposé le lendemain un autre atelier métaphorique, the Failure Game, un autre jeu à contraintes, qui fait intervenir la prise de risque en équipe, sur la base d'un équilibre précaire. Là aussi, des parallèles frappants avec nos métiers.
Parmi les thèmes qui ont guidé mes pas durant le forum ouvert :
Avec Manuel Vacelet, nous avons animé une conversation titrée : Vous ne produisez pas du logiciel, vous le changez. Je ne suis pas tout seul à penser que le modèle du développement de logiciel comme activité de production a vécu !
J'ai pu participer à la session Slow Code de Mathieu Cans, laquelle m'a laissé perplexe et déboussolé tellement tout s'y enchaînait à une vitesse déroutante 😃.
TDD : Qu'est-ce que c'est que cette bête là ? Est-ce une méthode ? Une approche ? Une technique ? Est-ce du désign émergeant ? Est-ce du testing ?
XP : Mon approche préférée pour développer du logiciel, car elle fait fi des barrières habituelles, de la gestion de projet, et met en avant les pratiques de prévention qui manquent tellement, partout ! (Qui sème la controverse récolte des idées). Merci Pascal LE MERRER pour ta keynote !
Merci Bastien David pour cette conversation en fishbowl à propos du craft.
Hadrien Mens-Pellen nous a fait une présentation du langage Toki Pona, la langue du bien. C'était fascinant !
Merci Houssam FAKIH d'avoir présenté et facilité notre forum ouvert !
Pour la richesse de rencontres et nos conversations passées et à venir, un grand merci à
🎯 Arnaud Langlade
Arnaud Thiefaine
Colin Damon
💎Dorra BARTAGUIZ
Fontaine Emeric
Jean Dupuis
Johan Martinsson
Khaled Souf
Nicolas Savois
Rémy Sanlaville
Thierry de Pauw
Willy Malvault
Xavier Nopre
ainsi qu'à celles et ceux que j'oublie de mentionner ici.
Et encore merci, chaleureusement, aux organisateurs !
publié sur Linked In le 05/06/2023
Auto-Formation
— Bon eh bien on a fait le tour. Bon courage tout le monde ! 👋
— Merci Jérémie, bon courage ! 👋
— Victor, est-ce qu'on peut se parler en privé si tu as 5 minutes ?
— OK.
— Victor, on sort d'un débrief d'une heure dans lequel tu n'as pas dit 2 mots. Ça ne te ressemble pas. Est-ce que tu es en colère ?
— C'est vrai. En colère, non, mais intrigué, oui.
— Qu'est-ce qui t'intrigue ?
— Toujours pareil, Jérémie, la même chose depuis des semaines en fait.
— Si c'est à propos des tests auto sur le code des contrôleurs, tu sais comme moi que c'est mis sur l'étagère pour l'instant. C'est ça qui te chiffonne ?
— Justement, parlons-en. Si on pouvait reprendre le raisonnement qui a mené à cette décision, ça m'aiderait à mieux comprendre.
— OK. Je n'ai pas trop le temps là maintenant, mais OK.
— Début Mai : la démo faite aux sponsors plante sur le formulaire de recherche. On regarde ce qui se passe. Le sponsor quitte la démo.
— Oui, je me souviens bien. On en a assez parlé depuis…
— Après investigation : un appel de fonction qui retourne undefined suivi d'un appel sur undefined.
— Classique.
— Tu en parles comme si c'était l'arroseur arrosé. Le plus vieux gag du monde.
— Je veux dire…
— Moi ce qui m'étonne c'est qu'on puisse avoir en démo des gags classiques. Donne moi un bug nouveau, insolite, surprenant, OK. Mais un classique !?
— Ah tu vois que tu es en colère…
— Si c'est classique, ça devrait être une affaire classée depuis longtemps, non, tu ne crois pas ?
— Est-ce qu'on peut revenir au récap ? Je vais manquer de temps, là.
— 9 Mai : on confirme que le code de ce contrôleur n'est vérifié par aucun test, auto ou exploratoire. Et qu'il n'a pas été relu.
— On manquait de temps. Tu le sais très bien.
— 10 Mai : on valide la mise en place de tests auto sur cette partie de l'application. Xavier dit qu'il est OK avec la démarche, mais qu'il faut qu'il soit formé, ou qu'il se forme.
— Exact. Ça ne va pas de soi.
— On décide une expérimentation — j'ai encore mes notes — de 3 jours, en binômes, avec l'objectif de poser des tests, refactorer au besoin, et faire un état des lieux ensuite.
— Oui, mais entre-temps…
— 16 Mai : c'est reporté. Xavier prend une nouvelle story. Il me dit qu'il a été vu par le manager.
— Exact : JP lui a demandé s'il pouvait essayer de se former chez lui plutôt que sur le temps du projet. Il a fait valoir que ce n'est pas à la boite de former les prestas sur du temps qu'ils nous facturent.
— Ça n'a aucun sens.
— Pour toi, peut-être.
— Et tu penses que Xavier ne se forme pas en ce moment ?
— Bah si, j'imagine qu'il se forme, sur son ordi, le soir.
— Mais non : c'est ici, au travail, qu'il se forme, bien sûr, comme tout le monde. Ce n'est pas la question.
— 🤔
— La question c'est : à quelle vitesse ?
publié sur Linked In le 07/06/2023
Apprentissage, Performance
🏭 Chère entreprise,
Il faut se rendre à l'évidence : tu obtiens ce que tu demandes exactement, quoi que tu obtiennes.
Si ton règlement exige que tes développeurs·es soient payés à produire et non à se former, tu obtiendras des développeurs·es qui produisent, et ne se forment pas. Dès lors, ta capacité à créer et maintenir du logiciel de qualité va dépendre de la formation initiale de tes collaborateurs·ices et de leur vocation à s'améliorer sur leur temps perso.
Caveat : dans une fameuse école d'ingé parisienne on disait encore il y a quelques années : "Les tests, c'est pour ceux qui ne savent pas coder". 🧐
En même temps je connais des développeurs qui ont bientôt 35 ans d'expérience et qui n'ont jamais écrit un test auto. Ils travaillent dans une ESN qui fait des milliards de bénéfices. Ils prestent pour des entreprises clientes qui obtiennent ce qu'elles demandent.
Alors bien sûr, laisser ton personnel se former au lieu de produire, ce n'est pas de la bonne gestion. Le temps des salariés et des prestataires coûte cher. Mais tu n'as pas seulement besoin de produire : il te faut aussi t'améliorer. C'est vrai partout dans l'industrie, et en informatique c'est une évidence axiomatique, à moins que tes équipes ne soit occupées à réinventer la roue (et je suis sûr qu'il y a des clients pour ça). 🎡
Oui, dis-tu, mais il faut aller vite ! 🏎
Ah, la vitesse ! Mais la vitesse dépend de la stabilité. La vitesse sans la stabilité, c'est le chaos.
⇒ Plus ta production est performante, plus tu as des marges de manœuvre pour t'adapter
⇒ Plus tu as de marges de manœuvre, plus tu peux apprendre
⇒ Plus tu peux apprendre, moins il y a de variations incontrôlées dans ta production
⇒ Moins il y a de variations, plus tes performances augmentent
{:width="800px"}
Cela peut être un cercle vertueux : 💬
— On a stabilisé cette version, je propose qu'on décale la prochaine feature.
— Décaler, pour quoi faire ?
— Pour consolider ce qu'on a mis en place dans cette version : mettre à jour l'ADR, refactorer en binômes, documenter…
— OK.
Et bien sûr cela peut être un cercle vicieux : 🗯
— Je crois que j'ai enfin pu corriger ce bug.
— C'est pas trop tôt. Hop ! On relivre.
— Attends, est-ce qu'on pourrait poser quelques tests… 😬
— On relivre, je te dis, on verra ça plus tard ! On est en retard ! 🤬
Dans un projet en crise, on n'apprend pas (on s'adapte). Dans un projet stable, on apprend.
Alors chère entreprise, si ton projet n'est pas stable, tu es sans doute aux prises avec un cercle vicieux. De ces deux stratégies :
1️⃣ Tes développeurs·es se forment le soir et le week end sur leur propres ressources
2️⃣ Tu mets en place un process d'amélioration continue
Laquelle est la plus fiable ? La plus pérenne ?
Tu veux aller plus vite ?
🛠 améliore ton outillage
🎚 améliore tes standards
📋 améliore ton process
🤸🏻♂️ cesse de compter uniquement sur les quelques passionné·es qui ont du temps libre
Publié sur Linked In le 08/06/2023
Systèmes
- Diagrammes et Modèles 1
- Diagrammes et Modèles 2
- Diagrammes et Modèles 3
- Diagrammes et Modèles 4
- Diagrammes et Modèles 5
- Diagrammes et Modèles 6
- Diagrammes et Modèles 7
- Diagrammes et Modèles 8
- Diagrammes et Modèles 9
- Diagrammes et Modèles 10
Diagrammes et Modèles 1
— Bilan des courses, on est au sprint 15 et les choses ne vont pas mieux. Je dirais que par rapport au début de l'année on a 4 fois plus de bugs. 4 fois plus !
— …
— Si seulement on pouvait dénicher de meilleurs développeurs !
— …
— Non, ce n'est pas ce que je voulais dire. Mais ça me stresse, aussi, je suis inquiet. J'ai besoin de résultats. Dans cette maison on n'est pas en sécurité si on ne montre pas des résultats.
— …
… Mais je sais bien que plus on s'occuppe tôt des défauts, moins on en a. Mais comment veux-tu convaincre les équipes ? C'est pas si évident.
— …
— …prévenir que guérir, je sais !
— …
— Ce que je pense faire ? Pour l'instant recruter 2 développeurs de plus…
— …
— Notre quoi ?
— …
— Oui, on pourrait aussi améliorer notre stratégie de prévention. La question c'est : par où commencer ?
— …
— Oui, tu as raison. Le mieux serait que tu passes.
☎️
— Ces défauts, d'où est-ce qu'il viennent ?
— Tu en as de bonnes. Si j'avais la réponse à cette question, je n'aurais pas de problème de défauts.
— Euh, oui. C'est pas faux. Comment est-ce que vous découvrez qu'il y a un défaut dans le code ?
— Quand on reçoit un rapport d'incident.
— À ton avis, qu'est-ce qui contribue à l'apparition de défauts ?
— C'est facile : il suffit que les développeurs touchent au code !
— …
— Non, je plaisante, bien sûr. C'est un peu du cynisme de ma part…
— Je ne trouve pas ça cynique. Il faut bien qu'il y ait eu un changement dans le code pour qu'un défaut apparaisse là où il n'y en avait pas auparavant. On pourrait même dire que statistiquement parlant, pour un grand nombre de modifications du code, on aura proportionnellement un certain nombre de défauts insérés.
— Pas sûr, ça dépend qui intervient…
— Attends : c'est bien du code écrit et conçu par des humains ?
— Oui.
— Donc c'est sûr, il y aura des défauts introduits lors de changement dans le code.
— On peut le voir comme ça.
— Et quand ton équipe reçoit des rapports d'incident, qu'est-ce qu'elle fait ?
— Elle corrige au plus vite, évidemment.
— Je vois.
— Il te faut plus d'informations, j'imagine.
— Pour l'instant je vais noter ce qu'on a. Ça nous fera un modèle de départ.
— Un modèle ?
— Disons une espèce de vision en réduction de ton système.
— Tu n'aurais pas une solution, plutôt ?
— Ça va nous aider à y voir plus clair.
{:width="800px"} 2 variables, reflétant 2 agrégats :
le nombre de CHANGEMENTS effectués sur la conception
le nombre de rapports d'INCIDENTS
1 relation d'influence réciproque :
- Plus on fait de changements plus il y a d'incidents (même si chaque changement ne produit pas un incident). Cette influence se produit avec un délai, un incident n'apparaissant pas immédiatement dès qu'il y a changement.
CHANGEMENTS —|D|→ INCIDENTS
- Plus il y a d'incidents, plus on va changer le code (même si chaque incident ne génère pas un changement).
INCIDENTS —→ CHANGEMENTS
stay tuned!
publié sur Linked In le 26/06/2023
Diagrammes et Modèles 2
— Où est-ce qu'on en était ?
— On a identifié 2 agrégats dans le système formé par ton équipe de développement, dénotés par 2 variables facile à observer, et même à dénombrer :
- les CHANGEMENTS apportés au logiciel
- les rapports d'INCIDENTS
— D'accord.
— Plus on apporte de changements, plus on a de risque de recevoir des rapports d'incidents. Plus on a d'incidents, plus on apporte des changements.
— Et où est-ce qu'on va avec ça ?
— On va, on va… essayer de creuser ton problème si tu veux bien t’accrocher un peu. On cherche d’autres aggrégats. Qu'est-ce qui ferait qu'on aurait beaucoup plus d'incidents pour un nombre de changements pas plus élevé ?
— Facile : si on produisait plus de bugs.
— C'est à dire ? Un exemple ?
— Le logiciel ne se comporte pas comme attendu. Exemple, ticket #4802: "Null Pointer Exception".
— Pour qu'il y ait un incident, il faut donc un DYSFONCTIONNEMENT, c'est à dire un comportement résultant d'un changement et qui ne répond pas à une ATTENTE. On a 2 nouveaux agrégats :
- un changement sur la conception peut créer un DYSFONCTIONNEMENT
- si ce comportement ne matche pas une ATTENTE, alors on peut avoir, après un certain délai, un rapport d'INCIDENT
— Soit.
— Donc un incident, c'est la rencontre entre une attente et un dysfonctionnement du système.
CHANGEMENTS → DYSFONCTIONNEMENTS —&—|D|→ INCIDENTS
ATTENTES —&—|D|→ INCIDENTS
INCIDENTS → CHANGEMENTS
{:width="800px"}
— Oui mais non : tous les tickets ne sont pas des bugs. Prend celui-ci, #4807 : "La somme des arrondis doit être égal à l'arrondi de la somme. Veuillez revoir". On a un défaut de calcul, on attendait l'application de cette règle. C'est juste qu'on ne le "savait" pas encore. Ce n'était écrit nulle part.
— On ne peut pas tout décrire à l'avance. Un autre exemple ?
— "La requête prend trop de temps". Bien sûr ! Cet utilisateur a lancé une requête qui fait le produit de 2 longues tables !
— On a un comportement correct, mais vu comme un dysfonctionnement, du fait d'une attente irréaliste.
— Et celui-là : "Pourriez vous ajouter les pourcentages…", ce n'est pas un incident.
— Là on a un comportement correct, et une nouvelle attente, en quelque sorte.
— Bon. Qu'est-ce qu'on tire de tout ça ?
— Plusieurs choses :
ATTENTES et DYSFONCTIONNEMENTS ne sont pas des agrégats aussi facile à dénombrer que les 2 premiers, parce qu'on ne peut pas compter ce que l'on ne connaît pas encore. On va les représenter avec une forme spéciale, par ex. un nuage.
Il y a différentes sources d'incidents :
- dysfonctionnement (null pointer exception ?!)
- attentes incomprises (et l'arrondi ?)
- fonctionnement incompris (requête irréaliste)
- nouvelles attentes (svp des pourcentages)
Dans chaque cas, on en apprend plus sur les dysfonctionnements et/ou les attentes.
En somme tes incidents sont comme un révélateur en photo (argentique) : c'est une fois la photo révélée qu'on identifie les défauts…
— Oui. Le problème c'est que la révélation arrive un peu tard !
Stay Tuned !
publié sur Linked In le 27/06/2023
Diagrammes et Modèles 3
— Qu'est-ce que nous essayons de faire, au juste avec ces diagrammes ?
— Trouver des relations entre des variables à propos de ce que nous observons.
— Et quand on a trouvé ces relations, qu'est-ce qu'on a de plus ?
— On peut identifier des points d'interventions, c'est à dire changer ce que nous faisons de manière à changer ces relations.
— Mouais.
— Ce qu'on a jusqu'ici :
- ton équipe effectue des changements dans un logiciel
- une partie de ces changements provoquent des dysfonctionnements
- ces dysfonctionnements ne sont observables que sous la forme de rapports d'incidents, lorsque le dysfonctionnement fait que le logiciel ne répond pas aux attentes
- munie de ces rapports d'incident, ton équipe effectue de nouveaux changements
— C'est un peu léger, ta description. L'équipe ne se contente pas d'attendre tranquillement des incidents. On fait des tests, figure-toi.
— Comment est-ce que vous faites vos tests ?
— Eh bien une partie de l'équipe installe le logiciel dans un environnement de tests, et ensuite exécute des scénarios de tests, à la recherche de ce qui pourrait ne pas marcher.
— Et quand elle trouve un dysfonctionnement ?
— Elle produit un rapport d'anomalie à destination des développeurs.
— Je vois. On a donc une nouvelle relation :
CHANGEMENTS → TESTS —&—|D|→ ANOMALIES
DYSFONCTIONNEMENTS —&—|D|→ ANOMALIES
ATTENTES —&—|D|→ ANOMALIES
ANOMALIES → CHANGEMENTS
{:width="800px"}
Lorsque l'équipe change le logiciel, elle procède à des tests. Les tests révèlent des dysfonctionnements, c'est à dire des façons de fonctionner qui ne répondent pas aux attentes. Les dysfonctionnements sont consignés dans des rapports d'anomalies, ce qui permet de changer à nouveau le logiciel.
— C'est ça.
— On a un diagramme un peu plus compliqué, mais qui permet de voir ce que vous faites pour pallier au problème du révélateur.
— Le révélateur ?
— Oui, rappelle toi : le fait que les incidents en production ne nous révèlent les problèmes que très tard, lorsque le dysfonctionnement est déjà en production.
— Exact.
— Avec une démarche de tests systématique, vous pouvez identifier les dysfonctionnements et les supprimer avant le passage en prod.
— Tu as raison. Il faut que nous recrutions plus de testeurs.
— Est-ce que c'est ça qui va améliorer la vitesse à laquelle vous réalisez votre logiciel ?
— Si je suis ton modèle, oui : des défauts trouvés avant la prod, c'est toujours du temps gagné, crois-moi.
— J'ai connu une situation dans laquelle un manager avait fait exactement ce que tu t'apprêtes à faire, pour avoir moins d'incidents : il a recruté des testeurs supplémentaires.
— Et… ?
— Il a eu moins d'incidents. Mais au final le temps de développement a doublé.
— Comment ça ?
— Les testeurs trouvent des problèmes plus efficacement que les utilisateurs en production, figure toi.
— Oui, c'est leur job !
— Tu vois un insecte sortir de dessous une pierre. Tu soulèves la pierre. Qu'est-ce que tu vois ?
— Argh…
Stay Tuned !
publié sur Linked In le 28/06/2023
Diagrammes et Modèles 4
— Si je comprends bien, on est pris dans étau.
— Qu'est-ce que tu veux dire ?
— Soit nous testons notre logiciel de bout en bout, et nous allongeons les délais de livraison, soit nous le livrons au plus tôt, mais alors nous devons traiter les incidents en production.
— Si on reprend le diagramme qui modèlise ton système :
- certains changements entraînent des dysfonctionnements
- certains dysfonctionnements seront détectés via des tests, ce qui laisse une chance de les corriger avant la mise en production
- certains dysfonctionnements "échapperont" aux tests, et ne seront identifiés qu'en production
— Dans les deux cas, il faut corriger les problèmes, et ça prend du temps.
— Oui, mais si ton équipe n'effectuait aucun test, ta stratégie se limiterait à attendre que les incidents arrivent. Ce serait terrible !
— Ce qu'il faudrait, c'est tester, mais seulement les parties critiques du logiciel.
— Tu veux dire celles qui doivent absolument fonctionner ?
— Oui.
— Je suis certain que ton équipe fait déjà une telle sélection dans ce qu'elle teste.
— Alors que faire ?
— Jusqu'ici on recherche des dysfonctionnements existants dans le système. On pourrait mettre en place une stratégie visant à les prévenir, plutôt.
— Par exemple ?
— Par exemple, si tu programmes en javascript et que ton code additionne une chaîne de caractères à un nombre, tu viens de créer un dysfonctionnement.
— C'est probable.
— C'est quasi-certain. On pourrait empêcher ce défaut d'arriver en production, et même en environnement de tests. Il existe au moins 3 moyens :
- relire le code, de préférence en équipe
- écrire un tests automatisé qui va échouer sur le résultat attendu
- utiliser un langage comme typescript, qui vérifie le type des termes d'une addition.
— Tout ça c'est bien, mais ça ne se fait pas du jour au lendemain. Ça prend du temps.
— Ça vaut peut être le coup d'essayer : pour l'instant c'est la seule stratégie qui te permet de réduire le nombre de dysfonctionnements : on a une nouvelle relation
CHANGEMENTS → VÉRIFICATIONS -⊖→ DYSFONCTIONNEMENTS
ce qui veut dire que l'on réduit le nombre de dysfonctionnements à la source.
{:width="800px"}
— Note que ça plairait peut être à notre sponsor ce que tu viens de dessiner là.
— Ah oui ?
— Il se plaint que l'équipe ne soit pas capable de corriger les défauts sans en introduire de nouveaux.
— Ce que dit ce diagramme, c'est qu'avec un système assez grand, sans régulateur, l'activité de l'équipe tomberait dans un cercle vicieux :
CHANGEMENTS → DYSFONCTIONNEMENTS → INCIDENTS → CHANGEMENTS.
Pour réguler l'activité et empêcher un effet boule de neige , il faut soit réduire le nombre d'attentes, c.à.d moins de fonctionnalités promises, et/ou moins de clients…
— Hors de question.
— …soit réduire le nombre de dysfonctionnements à la source.
— C'est mieux.
— Et pour ça il vous faut un processus de vérification.
— On en revient toujours là.
— …mieux vaut prévenir que guérir.
Stay Tuned !
publié sur Linked In le 29/06/2023
Diagrammes et Modèles 5
— C'est bien joli tes diagrammes, mais je ne suis pas plus avancé.
— Quand même, est-ce qu'on n'y voit pas au moins un peu plus clair ?
— Si, bien sûr. Mais je n'ai pas de solution…
— On vient juste d'en trouver une ! Mets en place un processus de vérification : revues, tests automatisés.
— Pour ça, il faut former les personnes. Et là, on n'a pas le temps.
— Ah ah ! La fameuse roue carrée !
— Je ne te suis plus, là.
— Oui, non, la roue carrée c'est absurde. Tu connais l'histoire du bûcheron ?
— Je ne sais pas. Dis toujours ?
— C'est un bûcheron qui abat un arbre à la hache, très laborieusement. Un autre bûcheron lui demande : ça va ?
—— Non, j'ai un mal fou à abattre ces arbres.
—— Pas étonnant. Regarde ta hache, elle est émoussée. Tu devrais l'aiguiser.
—— Si tu crois que j'ai le temps avec tous ces arbres à abattre !
— …
— Oui, bon. Essayons un autre diagramme. Ton équipe a des performances insuffisantes. Pour corriger ça, elle devrait mettre en place des améliorations. Pour améliorer, il lui faut faire des apprentissages.
— On est d'accord. Mais c'est là que tout s'arrête. On n'a pas de marges de manœuvre.
— Qu'est-ce que tu veux dire ?
— Il nous manque du temps, ou des ressources, mais surtout du temps, pour apprendre.
— Je vois. Et qu'est-ce qui contribuerait à vous donner des marges de manœuvre ?
— Moins de problèmes en prod', ça aiderait !
— Je vois.
PERFORMANCES → MARGES DE MANŒUVRE
MARGES DE MANŒUVRE → APPRENTISSAGES
APPRENTISSAGES → AMÉLIORATIONS
AMÉLIORATIONS → PERFORMANCES
— C'est un cercle vicieux.
— C'est aussi un cercle vertueux. Si ton équipe était plus performante, elle gagnerait du temps, qu'elle pourrait utiliser à s'améliorer, etc.
— Si…
— C'est une boucle de renforcement. Donc ça doit finir par s'arrêter. Comme une avalanche.
— Avalanche ?
— Qu'est-ce qui se passe à la fin ? Si les performances sont vraiment catastrophiques ?
— Je me fais virer. L'équipe aussi.
— Mais après ? Le projet s'arrête ?
— Probablement pas. J'imagine qu'on lui trouverait de quoi faire un nouveau départ…
— C'est ça qui est intéressant ! On va le noter. J'imagine qu'il y a un seuil de performances, en deça duquel tes chefs prendraient des contre-mesures. Et leur intervention consisterait, en quelque sorte, à étendre le budget du projet.
— Si on veut. Mais on se ferait d'abord virer.
— Dommage, car avec cette extension l'équipe aurait des marges de manœuvres !
— Que se passerait-il si au contraire les performances étaient excellentes ? S'il n'y avait aucun écart de performance ?
— Hmmm. J'imagine qu'on nous donnerait de nouvelles contraintes. Faites moins cher ! Ajoutez des features ! Ça ne s'arrête jamais, vraiment.
— Et ces contraintes réduiraient vos marges de manœuvres.
— Voilà.
PERFORMANCES -⊖→ ÉCARTS DE PERFORMANCE | SEUIL DE PERFORMANCE
ÉCARTS DE PERFORMANCE → EXTENSIONS DE BUDGET
ÉCARTS DE PERFORMANCE -⊖→ CONTRAINTES
CONTRAINTES -⊖→ MARGES DE MANŒUVRE
— C'est donc comme ça que le système s'équilibre et continue.
{:width="800px"}
Stay Tuned !
publié sur Linked In le 30/06/2023
Diagrammes et Modèles 6
Martin : Bon j'ai parlé de ton idée en COMEX, figure-toi.
Carla : Mon idée ?
M: Oui, ton idée d'améliorer les performances en s'appuyant sur l'apprentissage.
C: Ah. Ce n'est pas exactement mon idée mais…
M: Peu importe : tout le monde est contre.
C: Oh.
M: À la place ils recommandent de "faire le ménage."
C: J'ai peur de comprendre, mais explique ?
M: On sort les moins performants, ça va inciter ceux qui restent à s'améliorer.
C: 😮😬😶🤧
M: Ça va ?
C: Oui, oui. J'ai avalé de travers. Il est fort ce café. Ahem. Question : À quoi tu vas reconnaître les moins performants ?
M: Oh les gens parlent, figure toi. Il suffit d'aller sur le terrain.
C: Donc un système de recommandation, en quelque sorte. 🙄
M: Pas seulement. Il y a aussi la vélocité individuelle…
C: Je vois ça. "You're fired!"
M: Hein ?
C: Non, rien.
M: Carla, je vois bien que tu n'approuves pas, alors crache le morceau.
C: Est-ce que vous allez réduire le scope du projet ?
M: Ce n'est pas prévu, pourquoi ?
C: Je te propose qu'on dessine un diagramme.
M: OK.
C: On établit une relation d'influence entre les performances individuelles et le nombre de défauts constatés en production. Qu'est-ce qui détermine selon toi le niveau de performance de chacun ?
M: Ses compétences, bien sûr.
C: La charge de travail également, non ? Je peux déplacer 5 kilos sur 2 km à une certaine vitesse. Si c'est 25 kilos ça va être un peu plus lent…
M: Oui, évidemment.
C: Donc la performance est un effet composé du nivau de compétence divisé par la charge de travail. Si celle-ci est trop élevée, la performance diminue.
PERFORMANCE INDIVIDUELLE -⊖→ DÉFAUTS EN PRODUCTION
COMPÉTENCES INDIVIDUELLES -⊘→ PERFORMANCES INDIVIDUELLES
CHARGE DE TRAVAIL INDIVIDUELLE -⊘→ PERFORMANCES INDIVIDUELLES
M: Admettons
C: Plus on a de défauts, plus l'écart avec la qualité requise se creuse. Et quand il se creuse trop, on sort des personnes du projet.
DÉFAUTS EN PRODUCTION -⊖→ ÉCART / QUALITÉ REQUISE
ÉCART / QUALITÉ REQUISE -⊖→ PERSONNES EN CHARGE
M: C'est l'idée.
C: Note que c'est la charge de travail totale, ainsi que le nombre de personnes en charge, qui détermine la charge de travail individuelle. Et aussi que le nombre de défauts en production augmente la charge de travail totale.
CHARGE DE TRAVAIL TOTALE -⊘→ PERFORMANCES INDIVIDUELLES
PERSONNES EN CHARGE -⊘→ PERFORMANCES INDIVIDUELLES
DÉFAUTS EN PRODUCTION → CHARGE DE TRAVAIL TOTALE
{:width="800px"}
M: En effet. Qu'est-ce que tu penses de tout ça ?
C: Je pense que tu as un job bien compliqué. Je sais qu'on est lundi, mais là quand même…
M: Qu'est-ce qui est compliqué ?
C: Tu vas annoncer à l'équipe :
- merci de corriger tous les bugs en prod, en plus du backlog
- si la qualité ne s'améliore pas, je vous annonce qu'on va réduire l'équipe
- en ce qui concerne le backlog, il reste inchangé
- bonne journée !
M: Mmmh 🤔
C: Il doit y avoir une meilleure solution.
Stay Tuned !
publié sur Linked In le 03/07/2023
Diagrammes et Modèles 7
M: Tu as raison, ça ne marche pas.
C: Euh… Qu'est-ce qui ne marche pas ?
M: La stratégie trouvée en COMEX : on se sépare des mauvais.
C: Sans blague. C'était un 180 cette idée.
M: Un 180 ?
C: Oui. Une idée 100% contre-productive, si tu préfères.
M: Ah oui.
C: Tu sais, quand tu veux aller dans une direction et que tu vas exactement dans la direction opposée.
M: Oui bah ça va, j'ai compris.
C: Un pur effet cobra.
M: Effet cobra ?
C: Je ne sais pas si l'histoire est prouvée, mais voilà : à Delhi, le gouvernement colonial britannique à l'époque, voulant se débarasser des cobras en trop grand nombre, avait décrété une récompense pour chaque cobra mort qu'on lui amenait. Ça n'a pas marché : les habitants se sont mis à élever des cobras. Le gouvernement a supprimé la récompense. Les habitants ont relâché les cobras qu'ils élevaient. Au final la ville s'est retrouvée avec encore plus de cobras.
M: Je vois. S'ils avaient fait un diagramme ils l'auraient vu aussi.
C: Je ne sais pas, mais on peut se prêter à l'exercice. Plus on livre des cobras, plus on obtient de récompenses. Plus il y a de cobras livrés, moins il y a de cobras vivants.
COBRAS LIVRÉS → RÉCOMPENSES
COBRAS VIVANTS → COBRAS LIVRÉS
COBRAS LIVRÉS -⊖→ COBRAS VIVANTS
Le système de récompense incite à créer des élevages, qui permettront de renouveler la population de cobras.
RÉCOMPENSES → ÉLEVAGES
ÉLEVAGES -|D|→ COBRAS VIVANTS
Lorsque la récompense est supprimée, la création d'élevage s'arrête, mais entretemps la population de cobras a augmenté.
{:width="800px"}
M: C'est un exemple intéressant, mais quel rapport avec notre politique de performances ?
C: Dans les deux cas, il y a une erreur de raisonnement :
- On a cru que la récompense diminuerait la population des cobras. Elle a eu l'effet inverse.
- On croit que la suppression des "mauvais développeurs" va diminuer la quantité de défauts. Elle aura l'effet inverse.
M: Moins de mauvais développeurs ⇒ moins de défauts, c'est logique…
C: Regarde mieux le diagramme qu'on a fait hier. Moins de développeurs ⇒ plus de travail par développeur ⇒ moins de temps pour améliorer. Du reste ce n'est pas seulement une erreur de raisonnement, c'est une erreur d'observation.
M: Comment ça ?
C: Explique moi ce qu'est un mauvais développeur ? Sur quelles observations tu te bases ?
M: Ça existe, les mauvais développeurs figure toi.
C: Je ne le conteste pas. Mais que peux tu observer à propos des "mauvais" développeurs qui les différencie des "bons" ?
M: Oh, un tas de choses…
C: Vous avez un standard qui vous aide à les identifier ?
M: Non, pas vraiment…
C: Vous n'avez pas de standard, mais vous vous apprêtez à sortir les mauvais développeurs.
M: C'est facile de critiquer. Qu'est-ce que tu suggères ?
C: À ta place, j'interrogerais des développeurs et je leur demanderais ce qui leur a permis de progresser dans leur pratique. Je doute qu'il y en ait un·e seul·e qui réponde "mes collègues se faisaient virer".
Stay tuned !
publié sur Linked In le 04/07/2023
Diagrammes et Modèles 8
Carla: Martin, comment ça va ?
Martin: Un peu sous pression, mais OK. Au fait merci pour le diagramme d'hier. Je crois que ça nous a évité de faire une erreur.
C: Contente que ça te soit utile…
M: Bien sûr, le COMEX est toujours dans l'attente d'une solution pour le projet. Ils me demandent si on ne pourrait pas doubler les cadences et mettre le turbo.
C: "Doubler les cadences" ?
M: De l'autre côté l'équipe me dit que pour aller plus vite il faut recruter, et que pour faire de la qualité, il faut plus de temps…
C: Je commence à croire que vous avez un sérieux problème de modèles mentaux, ici.
M: Pardon ?
C: Tu sais, un modèle mental : la représentation qu'une personne se fait d'un système.
M: Je ne te suis pas très bien.
C: Que font la plupart des gens quand ils entrent dans une pièce où il fait très froid ?
M: Ils cherchent le thermostat ?
C: Exact. Et que font ils quand ils le trouvent ?
M: Euh… Ils le poussent à fond. Pour avoir chaud plus vite.
C: Voilà ! Il y a 2 modèles mentaux distincts :
Pour les usagers : Le curseur du thermostat commande la quantité de combustible transmise à la chaudière et donc la vitesse de réchauffement de la pièce.
Pour le fabriquant : le curseur du thermostat commande un interrupteur relié à un capteur. Il permet d'activer la chaudière jusqu'à ce qu'à obtention de la température souhaitée.
M: Et alors ?
C: Les usagers croient que la pièce chauffera plus vite s'ils mettent le chauffage à fond. Mais la pièce ne se réchauffera pas plus vite. Par contre le chauffage marchera tant qu'il ne fait pas très chaud.
M: Je vois.
C: Ici, à propos du même problème, on dirait que vous avez des modèles mentaux différents :
pour le COMEX :
- la vélocité et la qualité du projet dépendent de la performance individuelle de chacun
- une personne travaille mieux et plus vite si elle sent qu'elle pourrait perdre son poste
pour l'équipe :
- pour améliorer la qualité du projet il faut plus de temps
- pour aller plus vite il faut être plus nombreux
{:width="800px"}
M: Tu as raison, vu comme ça, ça ne peut pas marcher, à moins de changer de modèle.
C: Pour que les gens changent de modèle mental à propos du chauffage, il faudrait qu'ils se documentent, ou bien que le système affiche le débit d'énergie.
M: Tu sous-entends qu'on ne communique pas suffisamment ?
C: Ou pas suffisamment clairement… Du coup, il y a plusieurs fossés :
- entre ce qui a été réalisé et la roadmap initiale
- entre ce que peut promettre l'équipe et ce qu'attend le COMEX
- entre un modèle mental basé sur le temps et un modèle mental basé sur la motivation
M: On s'en sort comment ?
C: Je ne sais pas. Tu pourrais commencer par partager ce constat.
M: On n'a pas trop le temps pour ça.
C: Alors je ne sais pas. 🤷🏼♀️
Stay Tuned !
publié sur Linked In le 05/07/2023
Diagrammes et Modèles 9
Martin: Est-ce que je peux te parler franchement ?
Carla: Quelle drôle de question ! Bien sûr !
M: C'est bien gentil ces diagrammes, mais en quoi ça nous aide ?
C: …
M: Je veux dire, c'est très général, on n'apprend rien qu'on ne sache déjà, non ?
C: Est-ce que tu n'as jamais rêvé de fabriquer une machine à ranger les affaires ?
M: Tu veux dire un robot ?
C: Si tu veux. Une machine qui rangerait tous les legos dans la chambre des enfants à la fin de la journée par exemple.
M: Ne m'en parle pas, c'était le drame encore dimanche dernier, avec mon fils cadet.
C: Ah ?
M: Léa a passé la journée à lui demander de ranger sa chambre.
C: …
M: Moi j'étais en mode, mais laisse-le profiter, il rangera ce soir… Évidemment ça crée tout de suite une discussion sur nos postures respectives… bref. Tout ça jusqu'au moment de le coucher, évidemment il y a eu zéro rangement, et là je marche sur un lego.
C: Ouch !
M: Et je m'emporte, commme un imbécile.
C: Ça c'est intéressant.
M: Oui, oh. 😠
C: Je veux dire : en combien de temps se constitue un désordre ?
M: En ce qui concerne la chambre de Théo, il ne lui faut pas une demi-journée avant que ce soit un désordre complet.
C: Et ça se produit petit à petit, j'imagine.
M: Oui. Jusqu'au moment où il faut s'y mettre et tout ranger. C'est pénible.
C: Justement, c'est un autre truc que l'on peut dire à propos de ton équipe et de l'organisation : vous réagissez trop fort trop tard.
M: Ah bon ?
C: Ce qui est un peu logique, si vous avez des modèles mentaux différents à propos de ce qui se passe.
M: Je ne te suis pas.
C: D'où l'idée de faire des diagrammes ! Tu as déjà assisté à des désaccords dans ton équipe sur des mesure préventives ? Tu sais quand quelqu'un dit par exemple : on devrait écrire des tests sur cette partie du code, ça nous évitera des problèmes ! Et que les autres lui répondent : perte de temps ! On n'aura pas de problèmes !
M: Bien sûr.
C: Tu vois le tableau :
- on fait des raccourcis sur la qualité, petit à petit
- jusqu'au moment où on a un problème en production
- une fois qu'on a des problèmes en production, on n'a plus le temps d'améliorer la qualité
- on prend conscience qu'il faudrait le faire, mais on a trop de problèmes en production
- et ça continue comme ça jusqu'à une crise.
Tout vient du fait qu'il y a un temps plus ou moins long entre le moment où on fait un raccourci, et le moment où ses conséquences se manifestent.
{:width="800px"}
M: Et qu'est-ce qu'on peut faire alors ?
C: Si j'étais à votre place, je ferais de chaque problème constaté en production ou en tests, une occasion d'améliorer le standard. C'est à dire corriger non seulement le symptôme, mais le problème structurel qui provoque les symptômes.
M: Et avec quel budget ?
C: Nous y revoilà. Le remède coûte trop cher.
M: Voilà.
C: Et donc tu attends que le prix du remède diminue.
M: En quelque sorte.
C: Mais pendant ce temps, le prix du remède augmente.
M: C'est pas prouvé.
C: Dans ton modèle, peut être pas…
Stay Tuned !
publié sur Linke In le 06/07/2023
Diagrammes et Modèles 10
from: carla
to: martin
date: 2023-07-10
subject: diagrammes
Hello Martin,
Pour faire suite à ta demande, et avant mon départ en vacances, voici un récap de nos conversations.
En pièce jointe je t'ai fait une copie de quelques archétypes fréquents.
En espérant que ça aide.
Ciao! 👋
- Un diagramme présente les éléments d'un système sous la forme d'agrégats entre lesquels sont tracées des relations d'influence. Lorsqu'il y a influence réciproque (directe ou indirecte) on parle de boucles de rétroaction positives (explosion, effondrement) et négatives (régulation).
{:width="800px"}
- On n'est pas forcément obligé de mesurer pratiquement tous les agrégats sur lesquels on raisonne, même s'il faut ultimement pouvoir vérifier la pertinence du modèle à travers des observations. Par exemple on peut voir un rapport d'incident comme la rencontre entre un des dysfonctionnements du système et une attente à propos du système, même si ces 2 agrégats ne sont pas recensés ni mesurés a priori.
{:width="800px"}
- Un diagramme permet de trouver des points d'interventions, i.e. des changements dans le process ou les décisions visant à améliorer le comportement du système. Par exemple, une action de tests après chaque changement permet de réduire le nombre de dysfonctionnements rencontrés en aval dans le process.
{:width="800px"}
- En insérant des contre-mesures à bon escient, on peut réduire un agrégat "à la source" plutôt que seulement limiter les effets de cet agrégat sur le reste du système. Par exemple, des vérifications automatisées et des relectures permettent de supprimer des dysfonctionnements à la source, limitant ainsi les anomalies et incidents en aval.
{:width="800px"}
-
Une boucle de rétroaction positive fait nécessairement partie d'un système plus vaste dans lequel l'effet qu'elle crée rencontre une limite. L'avalanche s'arrête au fond de la vallée. Les problèmes de qualité s'accumulent jusqu'à l'arrêt du projet, ou sa reprise avec un nouveau budget.
-
Un diagramme d'effet permet de découvrir qu'une contre-mesure est erronée sans avoir à l'expérimenter. Par exemple, virer les contributeurs les moins performants d'un projet diminue la performance globale du projet au lieu de l'améliorer.
-
Dessiner des diagrammes en équipe permet de réveler les différents modèles mentaux que nous avons à propos d'une certaine réalité, de mettre ces modèles "sur la table" et d'éviter des décisions incohérentes.
-
Un pattern de rétroaction fréquent consiste à corriger le symptôme d'un problème à l'aide d'une solution superficielle, laquelle a pour effet de limiter l'apport d'une solution fondamentale au problème. Les comportements d'addiction sont de cette sorte. Par exemple une équipe de développement qui est aux prises avec une séquence continue de corrections en urgence au détriment des actions d'amélioration de la qualité contracte une addition aux bugs.
{:width="800px"}
publié sur Linked In le 09/07/2023
Test
Et si on parlait test ?
En commençant par un peu de vocabulaire. "Tester" : en voilà un mot chargé… On l'utilise pour désigner des choses très différentes. Comme tout le monde j'ai une tolérance raisonnable pour l'ambiguïté et je suis habitué à la polysémie des mots du français, mais dans le cas du mot "tester", je ne peux m'empêcher d'y voir une source de confusion.
Voici quelques significations du mot tester :
▷ tester : évaluer une condition. Par ex. sous linux, la phrase :
test -f README.md
évalue si le fichier README.md
est présent dans le répertoire courant. Autre exemple, en assembleur 68000 l'instruction
tst
compare son opérande à zéro et change les drapeaux du registre de codes de condition en conséquence.
△ tester : vérifier qu'une donnée, un état, un comportement est conforme à un attendu. Par exemple, la méthode :
testApres12StrikesScoreEgale300()
vérifie que le code d'un calculateur de score au bowling est capable de comptabiliser correctement un "perfect". Autre exemple, la page Cucumber intitulée
TestLogin.feature
vérifie qu'étant donnés un identifiant et un mot de passe reconnus par le système, quand on saisit cet identifiant et ce mot de passe dans le système, alors on accède la page d'accueil du système (si vous trouvez cette explication verbeuse, songez qu'ici je vous fais grâce des détails).
▵ tester : (par extension) écrire du code de vérification automatisée.
"Maintenant qu'on a testé les strikes et les spares, il reste le cas du perfect."
_ ▽ tester _ : essayer un produit, un artefact ou une idée, en vue d'y trouver des problèmes potentiels. Comme dans :
j'ai testé Overleaf pour créer mon cv en LaTeX et je suis mitigé
ou bien comme dans ce court dialogue:
— La QA a testé la reprise de facture avec un avoir et ils ont réussi à produire des factures avec des montants négatifs !
— Non mais c'est quoi leur problème, à la fin ?
▻ tester : mettre à l'épreuve, comme dans les tests d'intrusion par exemple.
Toutes ces acceptions font que lorsque j'entends dire qu'un projet présente "une couverture de tests de 75%", j'ai du mal à retenir des questions.
Quel genre de "test" ? La "couverture" de quelle surface ? La proportion de quoi sur quoi ? Bref, ça m'intrigue.
Toujours est-il qu'en réaction à cette profusion de sens, l'industrie, cherchant sans doute à clarifier, a classifié : c'est la fameuse pyramide des tests, qu'on trouve sous diverses latitudes, munies de légendes variables, et qui est en passe de bientôt disparaître derrière la fumée des débats qu'elle provoque. Son problème à mes yeux, et qui n'est pas des moindres, c'est qu'elle ne parle que de COMMENT tester : automatiquement, unitairement, isolément, de bout en bout, "manuellement", etc.
Personnellement j'utilise une autre classification, histoire de rafraîchir ma vision du sujet.
Stay Tuned ! 📡
publié sur Linked In le 22/08/2023
J'allais détailler pourquoi je jette aux gémonies la pyramide des tests, et la couverture des tests avec elle, mais inutile : le dernier billet de Laurent Bossavit met en lumière le problème bien mieux que je ne l'aurais fait. Lisez-le !
Vous l'avez lu ?
Lorsque nous réduisons un potentiel problème de qualité à un rapport de quantité, nous raisonnons à l'emporte-pièce, et notre stratégie s'en ressent.
Traverseriez-vous une rivière profonde d'1 mètre en moyenne ?
"18 heures d'indisponibilité ! Et pourtant notre coverage est en amélioration constante, je ne comprend pas". Famous last words.
△
Je n'ai donc pas de conseil à donner en taille de couverture ou en forme de pyramide. Mais ça ne m'empêche pas de formuler certaines réflexions, et de les partager. 😅
Nous posons des tests sur un système et nous le testons (ce n'est pas la même chose) en vue de réduire autant que possible le potentiel de problèmes que ce système présentera eu égard à ses objectifs et au contexte dans lequel il devra fonctionner.
En écrivant des tests, nous cherchons à nous prémunir contre des inconnues connues : ce sont tous les problèmes que nous pouvons anticiper à la conception, les erreurs que nous savons que nous risquons de faire, la complexité que nous ne voulons pas laisser dans l'ombre. Nous voulons mitiger les effets connus de cette complexité.
▶️
— j'écris un test: testApres12StrikesScoreEgale300() et il va échouer parce que le programme ne tient pas encore compte de la règle du 10ème frame.
⏸
En testant, nous cherchons à nous prémunir contre des inconnues inconnues : ce sont toutes les surprises que nous réserve le produit, qui échappent à notre compréhension limitée de ce système à l'instant t. Nous allons à la rencontre de sa complexité (avant que celle-ci ne frappe nos utilisateurs).
▶️
— La QA a réussi à produire une facture avec un montant négatif! Ils sont trop forts !
⏸
Pour des raisons culturelles, sociologiques, historiques, mais aussi techniques, nous focalisons cette activité de "test" sur deux centres d'intérêt à peu près distincts :
- le comportement du système avec l'extérieur, i.e les interactions Humains/Machine 🖥🤔
- le comportement "interne" du système, i.e les interactions Machine/Machine ⚙️🤖
Ces deux partages :
- inconnues connues / inconnues inconnues
- interactions H/M / interactions M/M
divisent en 4 zones l'étendue du territoire dans lequel le mot "test" revêt du sens pour le développement de logiciel. Dans chacune des zones, les états de l'art, les procédés, les pratiques, les process sont différents, et à juste titre. Cf le diagramme en illustration. Cette carte heuristique, ce "mind-map", permet de détecter rapidement des erreurs de stratégie. Je me suis permis de mentionner dans chaque zone ma stratégie préférée.
Prochainement sur cette chaîne, un quizz pour valider ou infirmer ce modèle. Stay Tuned ! 📡
publié sur Linked In le 23/08/2023
— Qu'est-ce que ça représente, cette carte ?
— Ça ? Les vestiges d'une application…
— Comprends pas.
— La ligne pointillée bleue délimite l'ensemble des comportements que l'application devait présenter une fois installée en production. L'équipe qui a conçu cette application, et l'a construite, s'est dit : elle n'ira pas plus loin, mais à tout le moins, elle fera ça, c'est à dire ce qui se trouve à l'intérieur de la ligne bleue.
— Et les triangles rouges ?
— Ce sont tous les comportements incorrects rencontrés par ceux qui ont utilisé l'application.
— Des bugs, donc.
— Disons des variations de comportement qui ne faisaient pas partie du plan.
— C'est ce que je dis. Des bugs. Je ne vois pas la différence…
— C'est parce le mot bug est si vague… on peut y mettre tout et n'importe quoi.
— Par exemple, ce triangle rouge tout en haut vers la gauche, il représente quoi ?
— La déclaration d'un utilisateur à l'équipe : "là le calcul est peut être conforme à la spéc, comme vous dites, mais en tout cas ce n'est pas comme ça que ça marche dans la vraie vie."
— Je vois. Ce n'était pas un défaut du programme.
— C'était un problème de conception fonctionnelle, si tu veux.
— Donc les triangles rouges représentent des défauts, non pas du programme, mais de la conception ? On n'a pas fait le bon produit ?
— Pas forcément : tu vois qu'il y a aussi des triangles rouges à l'intérieur de l'enceinte tracée en bleu.
— Qu'est-ce qu'ils représentent ceux-là ? Par exemple le triangle le plus haut dans le pentagone ?
— Ça, c'est quand on a remarqué, en production, que l'application ne détectait pas correctement les portefeuilles ayant des comptes dont le solde a dépassé un certain seuil de sécurité.
— Et ça, ça aurait dû être compris lors de la conception ? C'est pour cela que ce triangle est à l'intérieur de l'enceinte bleue ?
— Exact. Le comportement "tu donneras la liste des comptes du portefeuille dont le solde dépasse tant" faisait partie des comportements possibles de l'application à la conception. Mais un utilisateur à réussi à montrer que dans certain cas, ce comportement n'était pas correctement implémenté.
— Ça paraît fou. Vérifier les soldes des comptes d'un portefeuille, c'est quand même pas sorcier !
— Je comprends ton étonnement. Ce que ne dit pas la carte, c'est qu'il n'y avait pas de test dans ce projet.
— Quoi pas de test ?
— Il y a eu tout au plus quelques essais à la hâte, juste avant de livrer.
— Mais quand même ! Comment on peut se tromper sur un truc aussi simple ?
— S'il n'y a pas de test, pas de vérification, pas de relecture, personne pour chercher ne serait-ce qu'un problème éventuel…
— Mais ça ne peut pas marcher !
— Et ça n'a pas marché. Est-ce que tu vois des acteurs sur cette carte ?
— Non. On devrait en voir ?
— Si le projet avait survécu, oui.
(à suivre)
publié sur Linked In le 25/09/2023
— Une nouvelle carte ! Avec cette fois des "acteurs" comme tu dis. Ils chassent les bugs ?
— Disons qu'ils recherchent activement des problèmes possibles avec l'application.
— À voir le nombre de triangles, ils ne vont pas rentrer bredouille…
— Oui, c’est un bon terrain de jeu.
— On voit qu'ils sont surtout concentrés sur le périmètre initial de la conception.
— Exact. Ils le parcourent en s'aidant de la doc fonctionnelle, qu'ils transforment en "plans de tests". Ensuite ils exercent le code de l'application en suivant ce plan.
— Ils explorent aussi la zone extérieure, on dirait ?
— Dès qu'ils le peuvent, oui. Mais il ne le peuvent pas souvent: le périmètre "connu" de la conception présente déjà assez de problèmes pour remplir leurs journées.
— Au moins ici le scénario dont tu parlais hier ne risque pas de se produire.
— Tu veux parler du cas où la liste des comptes dont le solde dépasse un certain seuil n'est pas correcte ?
— Oui. Ici, un testeur peut essayer la "feature" dans tous les sens possibles, et finir par trouver le bug !
— En y passant le temps qu'il faut, bien sûr.
— Bah ! C'est mieux que rien.
— Supposons que l'application autorise une opération seulement si le portefeuille ne contient aucun compte en "dépassement". Comment tu t'y prendrais pour vérifier cette partie de son comportement ?
— Eh bien je testerais plusieurs cas :
∙ un portefeuille ne contenant aucun compte en dépassement, et l'opération est effectuée
∙ un portefeuille contenant un seul compte en dépassement, et l'opération est refusée
∙ un portefeuille contenant plusieurs comptes en dépassement, même résultat
∙ un portefeuille vide…
— Pas sûr qu'avec cette liste de cas tu aurais détecté le défaut dont on parlait hier.
— Je ne vois comment je l'aurais raté ! On a tous les cas de figure.
— Je ne sais pas si tu as recensé tous les cas de figure, mais je sais une chose : effectuer tous ces tests prend un certain temps.
— Hélas. Mais avec une IA…
— En attendant qu'une IA soit capable de raisonner jusqu'au point où elle peut élaborer une suite de cas pertinente, les testeurs prennent leur courage à deux mains, leurs journées de 8 heures, leur maigre budget de test, et essaient tant bien que mal de "couvrir" le périmètre de l'application.
— Je présume que pour cette application, tu militerais pour qu'on recrute plus de testeurs ?
— Ce ne n'est pas dit que le remède "plus de testeurs" viendrait à bout de tous les problèmes. Mais ce serait déjà mieux que rien.
— Évidemment, dans ce cas, le projet coûterait plus cher.
— Oui. Je doute que le client de cette application accepterait de payer plus cher pour ce travail de vérification assez élémentaire…
— Je suppose qu'il demanderait plutôt qu'on recrute de meilleurs développeurs !
— "Des meilleurs développeurs" c'est aussi plus cher.
— Il n'y a pas de solution, donc.
— Tant qu'on passe plus de temps à corriger les problèmes qu'à essayer de prévenir leur apparition, non.
(à suivre)
publié sur Linked In le 26/09/2023 #testing #tdd
— Ok, nouvelle carte. Où sont passés les chasseurs ?
— Ils ne font pas partie du dispositif. Pas de testeurs, pas de "QA", ici.
— Et ces acteurs, à l'intérieur du périmètre en bleu, qu'est-ce qu'ils font ?
— De la conception.
— Je vois. D'où leur tableaux blancs. En tout cas, pas un seul "bug", à l'intérieur de l'enceinte !
— Exact. C'est de la bonne conception, tout est vérifié, relu, testé.
— C'est propre !
— Tu ne crois pas si bien dire, c'est comme ça qu'ils qualifient leur démarche. Quelle que soit la phase du projet, ils ont soin d'ajouter des vérifications automatisées là où ils développent, aménagent, et maintiennent.
— Du coup, plus de problème.
— Disons que toutes les inconnues connues sont "couvertes".
— Mais il reste les inconnues inconnues, c'est ça ?
— Voilà.
— Bah, tant qu'elles sont à l'extérieur du périmètre de conception, on s'en f…
— Hmm. Ce n'est peut être pas clair, mais ce qu'indique la carte justement, c'est que l'usage du logiciel dépasse, et de loin, le périmètre de conception.
— C'est à dire ?
— Le pentagone bleu contient juste un modèle de ce qui va se produire avec l'application dans son éco-système, une vision simplifiée, si tu veux. À "l'extérieur" de cette conception, on va trouver des inconnues inconnues plus ou moins intéressantes, des "bugs" comme tu dis.
— Hum. Un exemple serait le bienvenu, là maintenant.
— Soit. L'application qui gére les vélos que j'utilise en ville me propose, contre remise, d'aller changer la batterie du vélo dans une des boutiques qui met à disposition des batteries de rechange. Elle m'indique où se trouve ce magasin et me demande si j'accepte d'aller faire l'échange. J'accepte.
— Ok.
— J'arrive à la porte du magasin. Normalement, je signale que je suis arrivé. L'application le valide (elle me localise) et doit maintenant me guider pour l'échange de batterie, une séquence bien précise.
— Ok.
— Tu devines le problème ?
— Ton smartphone vient juste de mourir ?
— Non.
— Tu n'as pas de réseau là où se trouve le magasin ?
— Bingo. Il faut que je marche un peu, 50 mètres, pour retrouver du réseau. Et là qu'est-ce qui se passe ?
— Aucune idée.
— L'application pense que je ne suis pas encore arrivé, et ne m'autorise pas à retirer la batterie.
— Ah mince.
— Oui, mince.
— Non mais ce cas là ils ont dû le prévoir quand même !
— Ce n'est pas la question. Ils l'ont peut être pressenti, et décidé qu'ils n'avaient pas de solution économiquement sensée à ce problème, ou simplement pas le temps.
— Puisque ce n'est pas dans le périmètre… C'est ce que dit la carte.
— Non, ce que dit la carte, c'est que la carte n'est pas le territoire, justement.
— Concrètement ?
— Elle dit: "Tu devrais explorer ce territoire, sinon tes utilisateurs vont rencontrer des triangles rouges que tu ne pourras pas localiser tant que tu reste dans les limites de tes modèles de conception."
— "Et ce sera ton problème"
— Dans certain cas, oui, dans d'autres non.
— Comment le savoir ?
— En explorant !
(à suivre)
publié sur Linked In le 27/09/2023
— Ah ! Cette fois-ci on a à la fois les concepteurs, et les chasseurs de bugs.
— Oui. Appellons-les les "défenseurs" et les "explorateurs".
— À lire cette carte on dirait que dans leurs activités respectives ils sont parfaitement isolés les uns des autres.
— C'est l'impression que donne ce pentagone bleu, mais c'est le contraire qui est vrai : les explorateurs fournissent sans cesse aux défenseurs des informations cruciales à propos du système, et réciproquement.
— Mais qui est responsable de sa qualité, au final ?
— Les deux acteurs sont responsables, et contributeurs.
— Il y a donc une phase de "build" et une phase de "test" ?
— Il y a plutôt deux activités menées parallèlement et en complément l'une de l'autre : les défenseurs conçoivent, spécifient, implémentent et vérifient les comportements de l'application. Les explorateurs, eux, recherchent activement des problèmes possibles avec l'application, dont les défenseurs n'auraient pas encore conscience.
— Je vois. Les défenseurs construisent des défenses. Les explorateurs vont au delà des défenses et cherchent les menaces qui ont échappé à la sagacité des défenseurs.
— Voilà.
— Pourquoi deux rôles ? Pourquoi les défenseurs ne deviendraient-ils pas des explorateurs à l'occasion ?
— Individuellement, c'est parfaitement possible, il suffit que l'organisation l'encourage.
— Je veux dire : la plupart des personnes que je connais et qui savent concevoir et coder un logiciel, seraient également capables, je pense, de tester ce logiciel de manière exploratoire.
— Peut-être. Mais mets-toi un moment à la place de l'organisation, du management. Comment tu établis que des développeurs ont bien fait leur travail ?
— S'ils ont livré dans les délais, un logiciel fiable, répondant au besoin, et du code facile à maintenir.
— Et comment est-ce que tu établis que des testeurs ont bien fait leur travail ?
— Je dirais : s'ils ont trouvé et signalé rapidement les problèmes les plus critiques ?
— Voilà. Le management peut exercer une pression, ou une incitation, qui encouragerait à la fois la tenue des délais et la ténacité à rechercher les menaces à la valeur. Sur une équipe, c'est assez simple. Sur un individu, c'est problématique.
— Donc, en résumé, qu'est-ce que tu préconises, comme stratégie de tests ?
— En bref :
1️⃣ Si tu veux créer et faire grandir un logiciel, tu dois à la fois défendre et explorer. Il te faut de bons concepteurs et de bon testeurs.
2️⃣ Les personnes qui conçoivent et construisent le système sont les mieux à même de le défendre: en écrivant des tests.
3️⃣ Les explorateurs/testeurs ne peuvent travailler efficacement que si le système a des défenses.
— Deux rôles pour assurer la qualité ça complique quand même un peu les choses, tu ne crois pas ?
— Ça les complique, mais pas autant que des nuées de bugs en production.
publié sur Linked In le 28/09/2023
⚫️ Lorsque je passe mon smartphone sur la borne du portique pour présenter le QR code de mon ticket, le portique ne valide pas mon ticket. C'est parce que mon appareil est passé en mode "paiement", et n'affiche plus le QR code.
Selon vous, qui serait le plus à même d'identifier ce problème ?
A - un utilisateur (et c'est tombé sur moi)
B - un défenseur
C - un explorateur
D - un responsable de la SNCF ou de chez smartphone
🟣 À propos de l'application qui ne détectait pas correctement les portefeuilles ayant des comptes dont le solde dépasse le seuil de sécurité, ces informations :
- le code (Java) examine chaque compte en traversant un tableau au moyen d'une boucle for
- la boucle for est initialisée à 1
- le code a été testé à l'aide d'un jeu d'essai élaboré sur la base de données de DEV
- le jeu d'essai comprend 6 comptes dont 2 sont en dépassement de seuil, en position 1 et 4 dans le tableau
- le test passe
Selon vous qui peut identifier ce problème le plus rapidement ?
A - le titulaire du portefeuille
B - un défenseur
C - un explorateur
D - un sourcier pratiquant la radiesthésie
🟢 Une entreprise a développé un ERP pour ses propres besoins en partant d'une suite open source, en agile. Ses équipes veulent allonger la durée du sprint parce que la phase dite de "non-régression", qui prend désormais plus de 4 jours, force à décaler les livraisons.
Selon vous quelle action serait la plus indiquée ?
A - recruter plus d'explorateurs
B - recruter un(e) automaticien(e)
C - demander aux défenseurs de passer explorateurs
D - limiter le nombre de users stories en entrée du sprint
🔵 Une équipe de 15 personnes réalise un projet de développement depuis un an sans avoir écrit un seul test automatisé. Son client exige désormais que l'application dispose de tests automatisés.
Selon vous à qui devrait-on confier cette tâche ?
A - aux explorateurs
B - aux défenseurs
C - à une société extérieure qui pourra le faire pour moins cher
D - à un outil à base de LLM pour encore moins cher
🔴 Le directeur financier de l'entreprise où vous travaillez vous demande : quel est le coût de ne pas faire de tests ?
Votre réponse :
A - Ça dépend de ce que vous entendez par "faire des tests"
B - Si l'équipe connaît son métier et sait ce qu'elle fait, le coût est marginal
C - Ça dépend de vos objectifs à moyen terme
D - Je n'ai pas la réponse à cette question
🟠 Votre cousin nouvellement diplômé vient d'entrer chez un éditeur de logiciel dont le CTO déclare "Pas de tests automatisés chez nous: lorsque le soft évolue il faut aussi faire évoluer les tests, et c'est trop lourd".
A - Votre cousin va faire un apprentissage intéressant
B - Vous vous inquiétez pour l'avenir professionnel de votre cousin
C - Cette entreprise vit sur une niche, votre cousin peut rester serein
D - Votre cousin mérite mieux que ça
publié sur Linked In le 29/09/2023
Il n'y a pas assez de testeurs·es dans les entreprises qui développent du logiciel. Et lorsqu'il s'en trouve, le processus de l'entreprise rend leur travail inefficace. C'est une évidence qui saute aux yeux. Mais lorsqu'on évoque le problème, on entend ces rationalisations :
C'est très complexe une application. 🤷♂️
On ne peut pas tout tester. 😅
Ce ne serait pas rentable de tester plus. 💸
"C'est très complexe"
Il est rare qu'une activité très complexe se généralise et s'étende à grande échelle : commercialement, ça ne tiendrait pas la route. Par ex. il y a plus de 5000 éditeurs logiciels en france. Editeur ou autre, chacun de nous a rencontré dans sa carrière des systèmes modérément compliqués, dont le code était défectueux, pas testé, et pas maintenable. Produit par des entreprises qui vont très bien commercialement, merci pour elles.
"On ne peut pas tout tester"
Mais apparemment on peut tout coder. C'est un problème. Vous ne devriez pas coder puis livrer quelque chose que vous ne savez pas tester. C'est comme si vous décidiez de lancer un produit sans vous soucier de son impact sur ceux qui vont l'utiliser. Vous allez me dire : si ça se trouve, ça marche, et sinon on pourra toujours corriger notre produit.👌
"Ce ne serait pas rentable"
Voilà l'argument le plus répandu. La qualité coûte cher. Donc c'est aux clients et aux utilisateurs de la payer de leur temps.
Si j'avais la fantaisie de me lancer dans la fabrication de chaises, je ne resterais pas longtemps sur le marché : mes chaises ne seraient pas belles, pas finies, pas stables, pas solides. Ce serait la faillite assurée. Si je veux un jour fabriquer et vendre de belles chaises, et concurrencer par exemple une grande entreprise scandinave, il faut que je me lève tôt, que je trouve un maître, et que j'apprenne ce métier pendant un certain temps.
Ce n'est pas le raisonnement que tient une entreprise qui se lance dans le logiciel. Pour elle, il suffit de :
- trouver une idée
- trouver des fonds
- trouver des gens qui savent coder
- se lever tôt (cette partie là, oui c'est pareil).
(à suivre)
PS: Voici ce que dit Boris Beizer (que je considère comme un maître en matière de tests) à propos du code non testé:
L'excuse que j'ai entendue le plus fréquemment pour mettre du code non testé en production est qu'il ne reste plus assez de temps ou plus assez d'argent pour tester. Par quelle magie le code non testé elimine t'il donc ses propres bugs ? S'il n'y avait pas assez de temps et d'argent pour tester le code, alors il n'y avait pas assez de temps et d'argent pour créer ce code en premier lieu. Car ce que vous appelez du code, avant qu'il ne soit proprement testé, n'est pas du code, mais une simple promesse de code. Non pas un programme, mais une parodie perverse de programme. Si vous mettez un tel truc dans votre système, ses bugs vont se voir, et parce qu'il n'y a pas eu de tests unitaires rigoureux, vous aurez du mal à trouver précisément ce qui a causé le bug.
publié sur Linked In le 02/10/2023
Travaillant dans le contexte de projets de développment depuis 35 ans, j'ai croisé plusieurs "générations" de développeurs et de managers. Leurs positions à propos des tests varie d'une génération à l'autre, avec quelques constantes :
🏝 le test est une activité mal connue, mal comprise, peu pratiquée, et très peu maîtrisée
🔧 on croit que l'essentiel de l'activité de test consiste à exécuter des tests
⛏ pour beaucoup, test = test manuel, un labeur réalisé par d'autres personnes moins qualifiées que les développeurs, qui eux, créent de la valeur
🤖 on place ainsi de l'espoir (et du budget) dans des outils permettant soi disant "d'automatiser les tests" mais qui n'automatisent que l'exécution des tests
🦾 cette confusion, pour des gens qui passent leur carrière à automatiser des traitements, fait sens
🦄 chaque génération arrive avec des raisons nouvelles de ne pas investir dans le test : progrès des langages, internet c'est différent, bientôt l'IA etc.
En lisant l'introduction de Software Testing Technique de Boris Beizer, publié il y a 40 ans, j'ai glané quelques idées intéressantes en regard de ces préjugés.
📖 Extrait 1 (sur le thème : à quoi servent les tests ?)
Le test et la conception des tests, comme composante de l'assurance qualité, devraient également traiter de la prévention des bugs. Pour autant que le test et la conception des tests ne prémunissent pas contre les bugs, ils devraient découvrir les symptômes causés par les bugs. Enfin, les tests deraient fournir des diagnostics clairs permettant de corriger facilement les bugs. La prévention des bugs est le but primordial du test. Un bug empêché est plus désirable qu'un bug détecté et corrigé, parce qu'alors il n'y a pas de code a corriger, ni de test à rejouer pour confirmer que la correction était valide, personne n'est embarrassé, il n'y a pas de consommation de ressources, et les bugs empêchés ne peuvent pas impacter négativement le calendrier. Plus que l'acte de tester, l'acte de concevoir les tests est un des meilleurs moyens connus de prévenir les bugs. La réflexion et l'analyse qui entrent dans la création d'un test utile peuvent identifier et éliminer les bugs avant qu'ils soient codés. En fait, la conception des tests permet de découvrir et d'éliminer les bugs à toutes les phases de la création d'un logiciel, depuis la conception, en passant par la spécification, la conception détaillée, le code, et le reste. À ce stade une activité idéale de conception des tests serait tellement fructueuse qu'il ne serait même pas nécessaire de lancer les tests, parce que tous les bugs auraient été trouvés et résolus pendant la conception des tests.
Malheureusement, cet idéal ne peut être atteint. En dépit de nos efforts, parce que nous sommes humains, il y aura des bugs. Pour autant que le test échoue dans son but primaire de prévenir les bugs, il doit atteindre son but secondaire qui est d'identifier clairement qu'il y a un bug.
Publié sur Linked In le 30/09/2023
La plupart des gens se font une idée très simplifiée ce que c'est que développer du logciel :
⌨️ développer du logiciel, c'est écrire du code ⌨️
Cet archétype, au sein même de l'industrie du développement et du conseil, omniprésent. Exemples :
🤖 on se demande si chatGPT (ou autre LLM) va remplacer les développeurs étant donnée la vitesse à laquelle ces outils peuvent produire du code relativement utile
📉 la performance des développeurs s'exprime en points de vélocité, une approximation de la quantité de code livrée en production, ou bien du temps passé à produire ce code
(pour vous en convaincre, proposez à une équipe d'ajouter à sa "definition of done" la documentation, la vérification ainsi que les tests : quelqu'un dans l'équipe vous opposera que cela risque de faire baisser la vélocité.)
🕳 en cas de retard, on préfère toujours livrer plus de code moins testé, moins vérifié et moins documenté, que livrer moins de code, mais du code testé, vérifié et documenté.
Sachant qu'il n'y a pas assez de testeurs·es dans les entreprises, et me demandant si on ne ferait pas bien d'écrire moins de code et plus de tests, en lisant l'introduction de Software Testing Techniques, j'ai eu envie de poser cette question :
À quel point faut-il distinguer testeur et programmeur ?
📖 La plupart des techniques présentées dans ce livre peuvent être utilisées à tous les niveaux de tests — depuis l'unité jusqu'au système. Lorsque la technique est utilisée au niveau du système, le concepteur et le testeur sont probablement des individus distincts. En revanche lorsque cette même technique est utilisée au niveau des tests unitaires, le testeur et le programmeur sont une seule et même personne, qui agit un temps comme programmeur et un temps comme testeur.
📖Vous devez être un schizophrène constructif. Ayez clairement en tête la différence entre votre rôle de programmeur et votre rôle de testeur. Le testeur en vous doit être méfiant, intransigeant, hostile, et compulsivement obsédé par la destruction, la destruction ultime, du logiciel du programmeur. Le testeur en vous est votre Mr Hyde — votre Incroyable Hulk. Le programmeur en vous essaie de réaliser une tâche de la manière la plus simple et la plus propre possible, à temps, et dans les budgets. Quelque fois vous y arrivez grâce à une idée géniale à propos du problème, laquelle réduit la complexité et l'effort, tout en étant presque correcte. Et avec ce testeur/Hulk tapi dans un recoin de votre esprit, il devient très utile de développer une saine paranoïa concernant les bugs. Rappelez-vous, par conséquent, que lorsque je me réfère au "concepteur de tests" et au "programmeur" en tant qu'individus distincts, le degré de séparation entre eux dépend du niveau de test et du contexte dans lequel la technique est appliquée.
publié sur Linked In le 05/10/2023
Beaucoup de développeurs considèrent l'option "No Code" comme une mauvaise idée. Disons, une idée qui va faire long feu. Cela se comprend, si l'on considère que pour le développeur l'écriture du code constitue son activité essentielle.
Si Wikipedia donne une présentation claire et raisonnée de ce choix techonologique, il n'en va pas de même bien sûr, des éditeurs :
🚀 Créez une belle UI, générez du code propre, et déployez vers les app stores ou le web en un clic. Totalement extensible avec du code customisé. 'Chose' rend la contruction d'appli mobile facile pour les designers, les développeurs et les entrepreneurs.
🛸 Construire de la tech est lent et coûteux. 'Truc' est la plateforme no-code la plus puissante pour créer des produits digitaux. Construisez mieux et plus vite. La Liberté de Donner Naissance à Vos Idées. Pas de Limites. Pas de Code.
D'un côté, je comprends la réticence — pour ne pas dire la résistance — des développeurs, ayant cotoyé de nombreux projets legacy bâtis sur des "solutions" initialement garanties sans code, dans lesquelles on a dû, wait for it, ajouter du code.
Dans l'entreprise on gère assez mal la qualité logicielle des technos "code centric". Sur une techno "code eccentric" à laquelle on a dû adjoindre du code après coup, c'est encore pire.
😞 Si vous n'aimez pas beaucoup le code legacy, vous allez carrément détester le code legacy sur une plateforme pas prévue pour le code. 😭
De l'autre côté, je me dis : pourquoi l'entreprise ne se lancerait elle pas dans le no code ? Après tout elle est déjà bien engagée et depuis longtemps dans le No Test.
🤹♀️No Test : Tester coûte cher, et c'est fastidieux, voire ennuyeux. Préservez la motivation et l'énergie de vos développeurs. Le code qui passe en prod marche instantanément. Et vous saurez le faire évoluer facilement. Inutile de chercher la petite bête. Libérez vous des esprits critiques.
Le No Test, cette profession de foi de ceux qui croient en leur chance et se remontent les manches même le dimanche, est probablement la technique de test la plus répandue dans toutes les entreprises aujourd'hui.
Répandue, oui, mais pas autant que le No Review.
🎭 No Review : Relire le code ensemble, c'est beaucoup de temps perdu à chicaner, et c'est prétexte à de nombreuses frictions. Adoucissez votre processus de développement ! Le code qui passe la porte pour aller en prod est parfait, lumineux. Ceux qui auront à le modifier plus tard (et qui sont encore à l'école primaire en ce moment) n'en reviendront pas.
Le No Review, comme pratique d'accélération des projets est très ancré dans l'entreprise, mais pas autant que le No Doc, qui lui est totalement généralisé.
🦄 No Doc : Pourquoi décrire quand on peut construire ? Grâce à No Doc, vos futurs développeurs accèdent en un coup d'œil sur la base de code à l'architecture de la solution, ils comprennent instantanément les enjeux métiers pour l'entreprise et savent exactement où coder leur modifications !
Publié sur Linked In le 02/10/2023
Code
- The Diamond Kata: a mix of TDD and PBT
- Scratching the surface of Monad Transformers
- What Problem Are You Solving Together?
- Coding Katas and Problem Solving
- The Bowling Score Kata
The Diamond Kata: a mix of TDD and PBT
d023-03-18
In this post I show an example of solving a coding kata the TDD way, while writing "property based testing" checks with QuickCheck.
1: Let's print diamonds
The diamond kata is a well known exercise. Here's a description copied from codingdojo.org
Given a letter print a diamond starting with 'A' with the supplied letter at the widest point.
The program, given the parameters A, C, and E respectively, should print the following patterns:
A A A
B B B B
C C C C
B B D D
A E E
D D
C C
B B
A
I want to rely on two heuristic while writing such a program:
- Test Driven Development:
- Write a test and make sure it is failing
- Write the simplest code that will make the test pass
- Refactor
- Property Based Testing:
- Define properties that should hold about the program's behavior
- Check the properties using generated data sets the program should be tested against
- Diagnose test failures and fix defects found in the program
Properties Todo List
{:height="250px" width="250px"}
Looking at the diamond examples above, we can find interesting properties about the program's output.
Given N the position of the (argument) letter in the alphabet,
| The upper left corner of the pattern is filled with a diagonal formed by the letters A,B,C etc. The letter A is in position N (starting from 1), B in position N-1, C, in position N-2, and so on. | | The pattern has horizontal symmetry, which means that flipping it horizontally yields the initial pattern. | | The pattern also has vertical symmetry. | | The height of the diamond is 2N-1. | | The maximum width of the diamond equals its height, also 2N-1. |
I want to write a program that satisfies these properties, starting with the one that is the easiest, and then adding new properties one after the other.
2: Stating a first property with QuickCheck
Let's create a test harness and put it in use with a first test. What is the simplest assertion we could hold true about a function diamond which given a letter, yields a pattern of chars in the shape of a diamond?
Well, we could try this:
|For any given letter, the pattern has a length of 2 * N - 1, where N is the position of the letter in the alphabet. |
-- Specs.hs
import Test.QuickCheck
import Diamond
main = do
quickCheck prop_DiamondLengthEquals2NMinus1
prop_DiamondLengthEquals2NMinus1 l =
length (diamond l) == 2 * n - 1
where
n = length ['A'..l]
We can force a test failure with this dummy implementation:
-- Diamond.hs
module Diamond
where
import Data.Char (ord)
diamond _ = []
And sure enough, the test fail:
runhaskell Specs.hs ⏎
*** Failed! Falsified (after 1 test and 1 shrink):
'a'
To make it pass, we can fake the property by creating a list of empty strings having the right length:
-- Diamond.hs
module Diamond
where
import Data.Char (ord)
diamond :: Char -> [String]
diamond l = replicate (2 * n - 1) ""
where n = length ['A'..l]
But our test still fails, and for a different reason:
runhaskell Specs.hs ⏎
*** Failed! Falsified (after 3 tests and 1 shrink):
'1'
This is because length ['A'..'1']
= 0, and replicate
used with a negative argument yields an empty list.
The problem is that our test data set is too broad for the function under test, which is expected to work only with capital letters. To solve this, we will use a generator. The function
choose :: System.Random.Random a => (a, a) -> Gen a
will let us generate a char within the legal range for our program, which is 'A'
to 'Z'
. Then we can combine this generator with the forAll
function so that the property get tested only with data from our generator:
-- Specs.hs
import Test.QuickCheck
import Diamond
letter = choose ('A','Z')
main = do
quickCheck (forAll letter prop_DiamondLengthEquals2NMinus1)
prop_DiamondLengthEquals2NMinus1 l =
length (diamond l) == 2 * n - 1
where
n = length ['A'..l]
runhaskell Specs.hs ⏎
+++ OK, passed 100 tests.
Now that the test passes, we can refactor the test code for better clarity during execution:
-- Specs.hs
import Test.QuickCheck
import Diamond
letter = choose ('A','Z')
check s p = do
putStr ("\n" ++ s ++ ": ")
quickCheck p
main = do
check "Diamond length equals 2N-1"
(forAll letter prop_DiamondLengthEquals2NMinus1)
prop_DiamondLengthEquals2NMinus1 l =
length (diamond l) == 2 * n - 1
where
n = length ['A'..l]
And the test results are a bit clearer:
runhaskell Specs.hs ⏎
Diamond length equals 2N-1: +++ OK, passed 100 tests.
3: Checking the diamond's diagonal
Now we can maybe add some more important properties. Given L, the supplied letter:
| The upper left corner of a the diamond should contain a diagonal formed by the letters A to L.|
"Fake" diagonal
The first property is a bit complicated to write, as it involves comparing each cell in the diagonal to the letters from A to L. For example, if the supplied letter is D, then the cells at positions (i.e. at row and column) {(0,3),(1,2),(2,1),(3,0)} should be filled with letters A, B, C, D.
-- Specs.hs
. . .
main = do
check "Diamond length equals 2N-1"
(forAll letter prop_DiamondLengthEquals2NMinus1)
check "Diamond contains a diagonal with letters A to l"
(forAll letter prop_DiamondContainsDiagonal)
. . .
prop_DiamondContainsDiagonal l =
diagonal (diamond l) == letters
where
diagonal d = [d !! i !! (n-1-i) | i <- [0..n-1]]
n = length letters
letters = ['A'..l]
Of course, the test fails, because the lines in the diamond are empty:
Diamond contains a diagonal with letters A to l:
*** Failed! Exception: 'Prelude.!!: index too large' (after 1 test):
'M'
We can "convince" our test that the property holds by filling the result with series of letters:
- the first N lines with be filled with strings of length N: AAAA.., BBBB.., and so on, until NNNN..
- the next N - 1 lines will be produced the same way, only removing one, so that our first property still holds
module Diamond
where
import Data.Char (ord)
diamond :: Char -> [String]
diamond l = map (replicate n) (letters ++ (tail letters))
where n = length letters
letters = ['A'..l]
Of course, trying this program gives curious results:
ghci Diamonds ⏎
putStr $ unlines $ diamond 'D' ⏎
AAAA
BBBB
CCCC
DDDD
BBBB
CCCC
DDDD
But we are getting closer to our final program.
Spaces
It is true that there is a diagonal formed by the letters A,B,C in the shape above, only it's not really visible! We should now state something more about the output if we want it to conform to the visual result of a diamond:
| Every cell of the corner that is not part of the diagonal contains a space.|
In other words, given N the position of the supplied letter in the alphabet, for any coordinate {ROW,COL} within the corner, if ROW ≠ N-1-COL then the cell in that position should be a space.
-- Specs.hs
. . .
main = do
check "Diamond length equals 2N-1"
(forAll letter prop_DiamondLengthEquals2NMinus1)
check "Diamond contains a diagonal with letters A to l"
(forAll letter prop_DiamondContainsDiagonal)
check "Diamond contains spaces in non diagonal cells"
(forAll letter prop_DiamondContainsSpaces)
. . .
prop_DiamondContainsSpaces l =
let n = length ['A'..l] in
forAll (choose (0,n-1)) $ \row ->
forAll (choose (0,n-1)) $ \col ->
(row /= (n-1-col)) == (diamond l !! row !! col == ' ')
Now we have to implement this diagonal and stop using fakes.
Fortunately we can use the tails
function which produces all the initial segments of a list:
ghci ⏎
import Data.List
tails "***" ⏎
["***","**","*",""]
This, combined with reverse
and zipWith
, can help us create the desired pattern:
let spacesAfter = reverse (tails " ") ⏎
zipWith (:) "ABCD" spacesAfter ⏎
["A","B ","C ","D "]
let spacesBefore = tails " " ⏎
zipWith (++) spacesBefore $ zipWith (:) "ABCD" spacesAfter ⏎
[" A"," B "," C ","D "]
Let's put these discoveries into our diamond
function:
-- Diamond.hs
module Diamond
where
import Data.Char (ord)
import Data.List (tails)
diamond :: Char -> [String]
diamond l = corner ++ tail corner
where corner = zipWith (++)
spacesBefore
(zipWith (:) letters spacesAfter)
spacesBefore = tails spaces
spacesAfter = reverse spacesBefore
spaces = replicate (n-1) ' '
n = length letters
letters = ['A'..l]
And now all the test pass. Let's try our code:
ghci Diamonds ⏎
putStr $ unlines $ diamond 'D'
A
B
C
D
B
C
D
We are getting closer to the final result!
4: Horizontal symmetry
Seeing this result helps us find the next property to test:
| The diamond has horizontal symmetry: flipping it should yield the same result |
-- Specs.hs
. . .
main = do
check "Diamond length equals 2N-1"
(forAll letter prop_DiamondLengthEquals2NMinus1)
check "Diamond contains a diagonal with letters A to l"
(forAll letter prop_DiamondContainsDiagonal)
check "Diamond contains spaces in non diagonal cells"
(forAll letter prop_DiamondContainsSpaces)
check "Diamond has horizontal symmetry"
(forAll letter prop_HorizontalSymmetry)
. . .
prop_HorizontalSymmetry l =
diamond l == reverse (diamond l)
The functions tail
and reverse
are our allied here:
-- Diamond.hs
module Diamond
where
import Data.Char (ord)
import Data.List (tails)
diamond :: Char -> [String]
diamond l = corner ++ tail (reverse corner)
where corner = zipWith (++)
spacesBefore
(zipWith (:) letters spacesAfter)
spacesBefore = tails spaces
spacesAfter = reverse spacesBefore
spaces = replicate (n-1) ' '
n = length letters
letters = ['A'..l]
A look at the result so far:
ghci Diamonds ⏎
putStr $ unlines $ diamond 'D' ⏎
A
B
C
D
C
B
A
5: Vertical symmetry
We are almost done! Here's a new property:
| The diamond has vertical symmetry: flipping all of its lines should yield the same result |
-- Specs.hs
. . .
main = do
check "Diamond length equals 2N-1"
(forAll letter prop_DiamondLengthEquals2NMinus1)
check "Diamond contains a diagonal with letters A to l"
(forAll letter prop_DiamondContainsDiagonal)
check "Diamond contains spaces in non diagonal cells"
(forAll letter prop_DiamondContainsSpaces)
check "Diamond has horizontal symmetry"
(forAll letter prop_HorizontalSymmetry)
check "Diamond has vertical symmetry"
(forAll letter prop_VerticalSymmetry)
. . .
prop_VerticalSymmetry l =
diamond l == map reverse (diamond l)
To make this test pass, we need to mirror each line of the corner containing the diagonal, i.e. to concatenate it with its reverse:
-- Diamond.hs
module Diamond
where
import Data.Char (ord)
import Data.List (tails)
diamond :: Char -> [String]
diamond l = half ++ tail (reverse half)
where half = map mirror corner
mirror s = s ++ reverse s
corner = zipWith (++)
spacesBefore
(zipWith (:) letters spacesAfter)
spacesBefore = tails spaces
spacesAfter = reverse spacesBefore
spaces = replicate (n-1) ' '
n = length letters
letters = ['A'..l]
We are getting close, but there is still a property that we should add, as is visible in this trial:
ghci Diamonds ⏎
putStr $ unlines $ diamond 'D' ⏎
AA
B B
C C
D D
C C
B B
AA
6: Diamond width
Let's make sure that:
| The diamond's width equals 2N-1 where N is the position of the letter. |
-- Specs.hs
. . .
main = do
check "Diamond length equals 2N-1"
(forAll letter prop_DiamondLengthEquals2NMinus1)
check "Diamond contains a diagonal with letters A to l"
(forAll letter prop_DiamondContainsDiagonal)
check "Diamond contains spaces in non diagonal cells"
(forAll letter prop_DiamondContainsSpaces)
check "Diamond has horizontal symmetry"
(forAll letter prop_HorizontalSymmetry)
check "Diamond has vertical symmetry"
(forAll letter prop_VerticalSymmetry)
check "Diamond width equals 2N-1"
(forAll letter prop_DiamondWidthEquals2NMinus1)
. . .
prop_DiamondWidthEquals2NMinus1 l =
maximum (map length (diamond l)) == 2 * n - 1
where
n = length ['A'..l]
Our mirror function should remove the first char of its argument:
-- Diamond.hs
module Diamond
where
import Data.Char (ord)
import Data.List (tails)
diamond :: Char -> [String]
diamond l = half ++ tail (reverse half)
where half = map mirror corner
mirror s = s ++ tail (reverse s)
corner = zipWith (++)
spacesBefore
(zipWith (:) letters spacesAfter)
spacesBefore = tails spaces
spacesAfter = reverse spacesBefore
spaces = replicate (n-1) ' '
n = length letters
letters = ['A'..l]
And some refactoring can occur here, since both horizontal and vertical symmetry can be obtain by mirroring:
-- Diamond.hs
module Diamond
where
import Data.Char (ord)
import Data.List (tails)
diamond :: Char -> [String]
diamond l = mirror (map mirror corner)
where mirror s = s ++ tail (reverse s)
corner = zipWith (++)
spacesBefore
(zipWith (:) letters spacesAfter)
spacesBefore = tails spaces
spacesAfter = reverse spacesBefore
spaces = replicate (n-1) ' '
n = length letters
letters = ['A'..l]
Et voilà! The diamond kata, built the TDD way with quickcheck.
ghci Diamonds ⏎
putStr $ unlines $ diamond 'Z' ⏎
A
B B
C C
D D
E E
F F
G G
H H
I I
J J
K K
L L
M M
N N
O O
P P
Q Q
R R
S S
T T
U U
V V
W W
X X
Y Y
Z Z
Y Y
X X
W W
V V
U U
T T
S S
R R
Q Q
P P
O O
N N
M M
L L
K K
J J
I I
H H
G G
F F
E E
D D
C C
B B
A
Scratching the surface of Monad Transformers
2020-05-22
Haskell makes it possible to write statically typed, purely functional programs. This gives us two interesting conveniences. The first one is that any incoherence in the type of our expressions and sequences can be spotted at compile time. The second one is that we can rule out the direct use of partial functions by wrapping their results in new data types and compose expressions with values of these types.
However, when a program has to process IO (as any useful program will), static typing and purity might seem to get in the way for a beginner. We use the IO
Monad to get IO
values, and the Either
Monad to deal with failures, but combining the two makes our programs cumbersome.
Monad Transformers can help us write simpler programs, by hiding the boilerplate code that this combination requires.
In this blog post I present how to chain monadic actions and controls with the ExceptT
Monad Transformer in Haskell through a small example, in 4 steps:
- writing a naïve implementation, which halts on IO exception
- improving its robustness with conditionals and pattern matching
- combining
IO
andEither
usingExceptT
- refactoring the program's chaining of actions
Program #1: A naïve solution
Let's say we want to write a program that reads a CSV file containing transactions, which are composed of a category and an amount, and prints the total spent for each category.
For instance, given a file transactions.csv
containing this data:
Groceries, 100.00
Savings, 500.00
Equipment, 32.00
Groceries, 42.00
Insurance, 38.17
Groceries, 30.00
Equipment, 179.00
the command summary transactions.csv
will output this:
Equipment, 211.0
Groceries, 172.0
Insurance, 38.17
Savings, 500.0
Our program will
- obtain the name of a file from the command line,
- read this file, splitting each line into category and amount, so as to create transactions,
- sort and group these transactions by category,
- sum these groups into summary lines,
- and finally print these lines.
After importing some standard functions, we define adequate data types for our program, starting with Category
.
import System.Environment ( getArgs )
import Data.List ( groupBy
, sortBy )
import Data.Function ( on )
data Category = Category { categoryLabel :: String }
deriving (Eq, Show)
Reading Categories
We need a way to read
a Category
from a String
, so let's make this type an instance of the Read
class. Parsing a category label amounts to reading alphanumeric chars, possibly some spaces, and rejecting everything else. For instance "Credit Cards Payments"
and "Credit 1"
can be used as a category label, while "Savings & Investing"
cannot.
readsPrec
is the function that we need to implement. It has the signature
Int -> String -> [(a,String)]
where the first argument is the precedence level (which we don't need to specify for our simple program), the second argument is the String
to be parsed, and the result is a list of possible results. Returning an empty list means that the input string could not be parsed to a value of type a
.
instance Read Category where
readsPrec _ s = if not (null label)
then return (Category label, rest)
else []
where
label = takeWhile (isLegal) s
rest = drop (length label) s
isLegal c = isAlphaNum c || c == ' '
The function takes all the legal characters in the input string s
, and returns a Category
value, coupled with the part of the input that remains to be parsed. Or it returns an empty list if no legal character was found at the beginning of the input string.
Let's try to read
a Category
using ghci:
$ ghci
> import Program1.hs
> read "Foo" :: Category
Category "Foo"
> read "*$!" :: Category
*** Exception: Prelude.read: no parse
(reads :: ReadS Category) "Bar, 42"
[(Category "Bar",",42")]
Reading Transactions
A Transaction
is composed with a Category
and a Double
. Since we want to read
transactions, we need to implement readsPrec
for this type as well.
data Transaction = Transaction { transactionCategory :: Category
, transactionAmount :: Double }
deriving (Eq,Ord,Show)
instance Read Transaction where
readsPrec _ line = do
(categ, rest1) <- reads line
(_, rest2) <- readComma rest1
(number, rest3) <- reads rest2
return $ (Transaction categ number, rest3)
where
readComma :: ReadS String
readComma s = case lex s of
((",",r):_) -> return (",",r)
_ -> []
This readsPrec
is a bit more complicated than the first one: it is chaining computations on the list monad, reading first a Category
, then a comma (and discarding it), then a Double
value. Chaining these three parsers ensures that the evaluation will result in an empty list as soon as one of them returns an empty list.
☞ To illustrate the effect of failure in a chain of list actions try this expression in ghci:
[1,2,3] >>= \n -> [n,n*10,n*100] >>= \m -> [m*m,m*m*m]
then try it again, replacing any of the three lists by the empty list.
Trying our parser on ghci:
$ ghci
> read "Foo, 42" :: Transaction
Transaction {transactionCategory = Category "Foo", transactionAmount = 42.0}
> read ", 42" :: Transaction
*** Exception: Prelude.read: no parse
> read "Bar, i42" :: Transaction
*** Exception: Prelude.read: no parse
>
Computing Summary Lines
Now for the summary: since a summary line has the exact same structure as a transaction, we choose to define it as a type synonym. Also we should be able to display
summary lines.
type SummaryLine = Transaction
display :: SummaryLine -> String
display t = categoryLabel (transactionCategory t)
++ ", " ++ show (transactionAmount t)
To summarize the transactions is to sort and group them by category, then for each group, create a SummaryLine
with the category and total amount of the group:
type SummaryLine = Transaction
summarize :: [Transaction] -> [SummaryLine]
summarize = map summary
. groupBy ( (==) `on` transactionCategory )
. sortBy ( compare `on` transactionCategory )
where
summary :: [Transaction] -> SummaryLine
summary txs = Transaction (category txs) (total txs)
where
category = transactionCategory . head
total = sum . map transactionAmount
Note how on
helps expressing the logic by composing the functions that are required by sortBy
and groupBy
.
Since
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
then
on compare :: (Ord b) => (a -> b) -> a -> a -> Ordering
and thus
on compare transactionCategory :: Transaction -> Transaction -> Ordering
which is conform to the type of function required by sortBy
. Similarly, on
composed with (==)
will create a function of the type required by groupBy
.
Reporting summary lines is done by mapping our display
function for each line, and then merging this list of String
s into one single String
:
report :: [SummaryLine] -> String
report = unlines . map display
The main program
We can now write our main function, which will get a file name on the command line, read that file, convert its content into a list of Transaction
s, and then compute and print the summary.
program1 :: IO ()
program1 = do
args <- getArgs
content <- readFile (head args)
let transactions = map read $ lines content
putStrLn $ report $ summarize transactions
And voilà, we have our program:
$ ghc --make program1.hs
$ program1 transactions.csv
Equipment, 211.0
Groceries, 172.0
Insurance, 38.17
Savings, 500.0
It is, indeed, a very naïve program. Let's see what could go wrong:
- we could forget to specify a file name when lauching the program from the command line
- we could specify a file name that doesn't correspond to an existing file
- the file could contain data that can't be read as comma separated transaction values
- the file could be empty, in which case nothing would be output
$ program1
program1: Prelude.head: empty list
$ program1 foo
program1: foo: openFile: does not exist (No such file or directory)
$ program1 wrong.csv
program1: Prelude.read: no parse
$ program1 empty.csv
None of these conditions is adequately managed. This means that given certain inputs some of the functions will not return a value and the program will halt. Let's change this.
Program #2: responding to failure conditions
Partial and total functions
We want to deal with failure conditions in a graceful way. Our program should not stop abruptly with a strange message like "empty list" or "no parse". Instead it should print a clear diagnostic and possibly propose a way for the user to remedy the problem.
What parts of the program should change? Well, every part where the program calls a function that is not total. A function is said to be total if it returns a value for each possible value of its argument.
The function head
, used in the expression content <- readFile (head args)
is not total and could halt the program with an "empty list" message.
The function read
is also partial: it will halt the program if the string it is supposed to convert into a value is not correct.
On the other hand, the function:
lookup :: Eq a => a -> [(a, b)] -> Maybe b
is an example of a total function. It will not interrupt the program, for all possible values of type a
and b
.
☞ head
is used inside the function summary
in the expression transactionCategory . head
. Does it constitute a risk of halting the program in case we apply it on an empty list? Why?
A data type to represent failure
If a function is not total, one safe way to use it is to combine it with a data type that can represent failure. The Either
type constructor is designed just for such representations, and we will use it. To make things a bit clearer, let's first define a type synonym for the String
used as messages.
type Message = String
Our most frequent concern will be about the CSV file data format, so let's create a reader function that will manage faulty data in a graceful way:
readTransaction :: String -> Either Message Transaction
readTransaction s =
case reads s of
[] -> Left $ "Error: incorrect CSV format : " ++ s
((t,_):_) -> Right t
This reader calls the reads
function (which in turn calls the readSprec
that we defined earlier) and wraps the result into an Either
context.
Parsing several transactions from a String
is a matter of applying readTransaction
to each line of the argument. This is done with mapM
:
mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
The function is used to chain a monadic action to the elements of a structure and return a single monadic value. Here, it transposes a [Either Message Transaction]
into an Either Message [Transaction]
.
readTransactions :: String -> Either Message [Transaction]
readTransactions = mapM readTransaction . lines
Another failure possibility resides in getting the first argument on the command line: what if there is none? Let's wrap getArgs :: IO [String]
into a IO Either Message FilePath
to be on the safe side:
getFileNameArg :: IO (Either Message FilePath)
getFileNameArg = do
args <- getArgs
return $ if null args
then Left "Error: no file name given"
else Right (args !! 0)
Dealing with IO Exceptions
What if the CSV file can't be open? Using Control.Exception
will help us dealing with such a situation:
getFileContent :: FilePath -> IO (Either Message String)
getFileContent fp = (fmap Right $ readFile fp) `catch` handle
where
handle :: IOException -> IO (Either Message String)
handle = return . Left . ("Error: " ++) . show
The function:
catch :: IOException e => IO a -> (e -> IO a) -> IO a
is our "graceful exit" instrument here: given an IO action and a handler function, it will catch any IO exception and apply the handler to it, which will yield a legit IO a
value.
In our case, what we want to do with the exception is:
show
it into aString
starting with"Error: "
- make this message a
Left
value return
this left value, making it anIO (Either Message String)
In the case when everything is fine with the file and no exception is triggered, readFile
will give us an IO String
value. We make that value an Either Message String
by mapping the Right
constructor to it.
Note that our function returns an IO (Either Message String)
value. Why not simply return a Either Message String
instead? Because there is no safe way to convert an IO value into a non-IO value. Any function dealing with IO is partial, not total, because IO actions are always prone to some failure condition. If we could compile a function with signature IO a -> a
then Haskell's type checker would be much less useful to detect problems in our constructions when dealing IOs, and we would be hiding to ourselves some crucial concern with our program reliability.
IO
is an inescapable context. However, the fact that getFileContent
returns an IO
value should not be a problem because it will be used within the context of an IO action and nowhere else.
☞ There is actually a function with type IO a -> a
. It's called unsafePerformIO
. Use it at your own risk
Here's the version 2 of the program. It will examine the values returned by get
... functions and branch accordingly instead of halting:
program2 :: IO ()
program2 = do
fileName <- getFileNameArg
case fileName of
Left msg -> putStrLn msg
Right fp -> do
content <- getFileContent fp
case (content >>= readTransactions) of
Left msg -> putStrLn msg
Right [] -> putStrLn $ "error: no transactions"
Right txs -> putStrLn $ report $ summarize txs
main :: IO ()
main = program2
This program is dealing with failures in a better way:
$ ghc --make program2.hs
$ program2 transactions.csv
Equipment, 179.0
Groceries, 172.0
Insurance, 38.17
Investment, 6007.0
Savings, 500.0
$ program2
Error: no file name given
$ program2 foo
Error: foo: openFile: does not exist (No such file or directory)
$ echo "foo,bar" >wrong.csv
$ program2 wrong.csv
Error: incorrect CSV format : Foo, bar
$ touch empty.csv
$ program2 empty.csv
Error: no transactions
3. Monadic actions as isolated contexts
The bind operator (>>=
) used in the case .. of
instruction:
...
content <- getfilecontent fp
case (content >>= readtransactions) of
left msg -> putstrln msg
right [] -> putstrln $ "error: no transactions"
right txs -> putstrln $ unlines $ map show $ summarize txs
can be chained with as many functions of the type a -> Either Message b
as we want over the initial value of content
. For instance we could add new controls to detect an empty transaction list or to check that no transaction in the list has amount of zero.
checkNotEmpty :: [Transaction] -> Either Message [Transaction]
checkNotEmpty [] = Left "Error: no transactions"
checkNotEmpty txs = Right txs
checkNonZero :: Transaction -> Either Message Transaction
checkNonZero (Transaction _ 0)
= Left "Error: amount equal to zero"
program2 :: IO ()
program2 = do
fileName <- getFileNameArg
case fileName of
Left msg -> putStrLn msg
Right fp -> do
content <- getFileContent fp
case (content >>= readTransactions
>>= checkNotEmpty
>>= mapM checkNonZero) of
Left msg -> putStrLn msg
Right txs -> putStrLn $ unlines $ map show $ summarize txs
This chaining of controls could give the impression that we've missed an opportunity to simplify the code of the whole function, which we could have done by equally chaining the values obtained by getFileNameArg
and getFileContent
. Instead we used explicit case ... of
branching.
Question: Could it be possible to chain all our Either Message a
functions like this ?
wrong_program2 :: IO () -- won't compile
wrong_program2 = do
case (getFileNameArg >>= getFileContent
>>= readTransactions
>>= checkNotEmpty
>>= mapM checkNonZero) of
Left msg -> putStrLn msg
Right txs -> putStrLn $ unlines $ map show $ summarize txs
Answer: No. The compiler has no less than 6 complaints about this change to the function. Here's the first one:
• Couldn't match type ‘Either Message String’ with ‘[Char]’
Expected type: Either Message String -> IO (Either Message String)
Actual type: FilePath -> IO (Either Message String)
case (getFileNameArg >>= getFileContent
In essence: we cannot chain monadic actions from the IO
monad to the Either
monad, and vice versa. Since the case ... of
is examining a value of type Either Message [Transaction]
, the expected type for actions leading to that value is a -> Either Message b
. But we are trying to somehow get to that value through actions of type a -> IO b
. That can't work.
We can always bind monadic actions to distinct types through the same monad, as these examples with Maybe
and IO
show:
ghci
> notNull l = if null l then Nothing else Just l
> notLong l = if length l > 10 then Nothing else Just l
> Just "foo" >>= notNull >>= notLong
Just "foo"
> Just "" >>= notNull >>= notLong
Nothing
> Just "this is too long" >>= notNull >>= notLong
Nothing
> getLine >>= putStrLn
foo
foo
but we can never bind monadic actions through different monadic types:
> getLine >>= notNull
<interactive>:16:13: error:
• Couldn't match type ‘Maybe’ with ‘IO’
Expected type: String -> IO [Char]
Actual type: [Char] -> Maybe [Char]
• In the second argument of ‘(>>=)’, namely ‘notNull’
In the expression: getLine >>= notNull
In an equation for ‘it’: it = getLine >>= notNull
> Just "foo" >>= putStrLn
<interactive>:17:16: error:
• Couldn't match type ‘IO’ with ‘Maybe’
Expected type: [Char] -> Maybe ()
Actual type: String -> IO ()
• In the second argument of ‘(>>=)’, namely ‘putStrLn’
In the expression: Just "foo" >>= putStrLn
In an equation for ‘it’: it = Just "foo" >>= putStrLn
>
We can always, as in program2
chain Either
actions inside expressions that are themselves produced inside IO
. But we cannot produce one single, simplified chaining as in please, chain all these actions and controls over my input data and signal any failure.
Where do we go from here?
4. Combining Monads with Monad Transformers
What we need in order to simplify the code that does all the controls and actions is the ability to chain, approximately speaking, Either
actions inside the IO
monad.
This is what the Control.Monad.Trans.Except
library offers:
Control.Monad.Trans.Except
This monad transformer extends a monad with the ability to throw exceptions.
A sequence of actions terminates normally, producing a value, only if none of the actions in the sequence throws an exception. If one throws an exception, the rest of the sequence is skipped and the composite action exits with that exception.
newtype ExceptT e m a
A monad transformer that adds exceptions to other monads.
ExceptT
constructs a monad parameterized over two things:
- e - The exception type.
- m - The inner monad.
The
return
function yields a computation that produces the given value, while>>=
sequences two subcomputations, exiting on the first exception.throwE :: Monad m => e -> ExceptT e m a
Signal an exception value e.
runExceptT (throwE e) = return (Left e) throwE e >>= m = throwE e
Pure values and input values
Let's experiment on ghci. We start with importing our program, and the module.
> import Program2.hs
> import Control.Monad.Trans.Except
Let's try to create a pure ExecptT Message IO [Transaction]
value using the ExceptT
constructor:
> value = ExceptT $ return $ Right $ [Transaction (Category "Groceries") 42.0]
> :type value
value :: Monad m => ExceptT e m [Transaction]
Now let's create a function to get a list of transactions from a file. That amounts to:
- reading the file and putting its content in an
IO String
- applying
readTransactions
to this value, which gets us aIO (Either Message String)
- wrapping this into an
ExceptT
value
> fromFile = ExceptT . fmap readTransactions . readFile
> :type fromFile
fromFile :: FilePath -> ExceptT Message IO [Transaction]
This seems promising: we get the same result type whether our value comes from a constant or from reading a file!
Extracting the value from an ExceptT
context is done via runExceptT
:
> runExceptT value
Right [Transaction {transactionCategory = Category {categoryLabel = "Groceries"}, transactionAmount = 42.0}]
> runExceptT $ fromFile "transactions.csv"
Right [Transaction {transactionCategory = Category {categoryLabel = "Groceries"}, transactionAmount = 100.0}
. . .
,Transaction {transactionCategory = Category {categoryLabel = "Equipment"}, transactionAmount = 179.0}]
Exceptions and interactions
Naturally our function doesn't handle exceptions yet:
> runExceptT $ fromFile "foo"
*** Exception: foo: openFile: does not exist (No such file or directory)
If we want it to return a Left
value, we have to provide a handler:
> handler = return . Left . show :: (IOException -> IO (Either Message [Transaction]))
> fromFile fp = ExceptT $ fmap readTransactions (readFile fp) `catch` handler
> runExceptT $ fromFile "foo"
Left "foo: openFile: does not exist (No such file or directory)"
And now our function handles exceptions correctly.
Another case where we want to have IO
and Either
working together seamlessly is about extracting the CSV file name from the arguments provided on the command line, returning a Left
if no argument was given. Could we instead prompt the user for a file name?
Let's write a prompt function:
> promptForFileName = putStrLn "please enter a file name:" >> getLine
when the empty list pattern is met, we prompt for a file name, in other cases, we extract the first argument from the list
> :{
| getFileName :: [String] -> ExceptT Message IO FilePath
| getFileName [] = ExceptT $ fmap Right $ prompt
| getFileName (arg:_) = ExceptT $ return $ Right arg
| :}
> runExceptT $ getFileName ["transactions.csv"]
Right "transactions.csv"
> runExceptT $ getFileName []
please enter a file name:
transactions.csv
Right "transactions.csv"
It works! In one case we convert an IO String
into an IO (Either Message String)
and then nest that value into an ExceptT
. In the other case we nest a Right
value into IO
(getting also an IO (Either Message String)
) and also nest that value into an ExceptT
.
But all this converting is tedious. First, since ExceptT
is a monad, it offers a return
function. Let' use it.
> :{
| getFileName :: [String] -> ExceptT Message IO FilePath
| getFileName [] = ExceptT $ fmap Right $ prompt
| getFileName (arg:_) = return arg
| :}
Secondly, the combination ExceptT . fmap Right
can be done using a general function found in Control.Monad.Trans.Class
:
lift :: Monad m => m a -> t m a
Lift a computation from the argument monad to the constructed monad.
import Control.Monad.Trans.Class
> :{
| getFileName :: [String] -> ExceptT Message IO FilePath
| getFileName [] = lift prompt
| getFileName (arg:_) = return arg
| :}
What we have seen so far:
- we can compose together the
Either
monad with theIO
monad, using theExceptT
monad transformer - we hold values in
ExceptT
and extract them when needed withrunExceptT
, yielding aRight
orLeft
value - we chain monadic functions on these values with the bind (
>>=
) operation just like we would withEither
values - when a function leads to failure the chaining is cut short and we get an exception value: extracting it will yield a
Left
- we also obtain values from IO operations
lift
ing these operations into theExceptT
monad - thanks to exception
catch
ing when a failure occurs on the IO operation we also get an exception value
Program #3: A chain of actions that can fail gracefully
Let's integrate what we learned into our program.
import Control.Monad.Trans.Except ( ExceptT (..)
, runExceptT
, throwE
)
import Control.Monad.Trans.Class ( lift )
Domain
is the type of values possibly acquired from IO operations, and that can indicate failure:
type Domain = ExceptT Message IO
We can rewrite our conversion and control functions, using throwE
instead of Left
:
readTransaction :: String -> Domain Transaction
readTransaction s =
case reads s of
[] -> throwE ("incorrect CSV format : " ++ s)
((t,_):_) -> return t
readTransactions :: String -> Domain [Transaction]
readTransactions = mapM readTransaction . lines
checkNotEmpty :: [Transaction] -> Domain [Transaction]
checkNotEmpty [] = throwE "no transactions"
checkNotEmpty txs = return txs
checkNonZero :: Transaction -> Domain Transaction
checkNonZero (Transaction _ 0) = throwE "amount equal to zero"
checkNonZero tx = return tx
Acquiring the CSV file name will follow the logic we experimented on ghci:
getFileNameArg :: Domain FilePath
getFileNameArg = do
args <- lift getArgs
if null args then lift promptForFileName
else return (args !! 0)
where
promptForFileName :: IO String
promptForFileName = putStrLn "please enter a file name:" >> getLine
Dealing with IO exceptions implies using and wrapping the catch
expression into the ExceptT
monad:
getFileContent :: FilePath -> Domain String
getFileContent fp = ExceptT $ (readFileE fp) `catch` handleE
where
readFileE :: FilePath -> IO (Either Message String)
readFileE filePath = Right <$> readFile filePath
handleE :: IOException -> IO (Either Message String)
handleE = return . Left . show
Note that we use the <$>
(an infix shortcut for fmap
) since we need to apply the Right
function into the IO value that readFile
acquired.
Chaining all of this together
Now we can chain all these acquiring and controlling functions into a single one:
getTransactions :: Domain [Transaction]
getTransactions = do
filePath <- getFileNameArg
content <- getFileContent filePath
unchecked <- readTransactions content
notEmpty <- checkNotEmpty unchecked
transactions <- mapM checkNonZero notEmpty
return $ transactions
Of course, using variables and left arrows is one way to make the chaining of action explicit. Another way is to use the bind operator:
getTransactions :: Domain [Transaction]
getTransactions = getFileNameArg
>>= getFileContent
>>= readTransactions
>>= checkNotEmpty
>>= mapM checkNonZero
Finally, we need a way to output the result of our program, be it a failure or a valid list of summary lines:
report :: Either Message [SummaryLine] -> String
report (Left msg) = "Error: " ++ msg
report (Right sums) = unlines $ map showSummaryLine sums
As usual the main program will get the transactions, summarize them, and print the report:
program3 :: IO ()
program3 = do
transactions <- runExceptT getTransactions
putStrLn $ report $ summarize <$> transactions
main :: IO ()
main = program3
The operator <$>
is used instead of $
in summarize <$> transactions
since this variable is bound to an Either Message [Transaction]
value. We have to map summarize
instead of just applying it.
$ ghc --make program3.hs
$ program3
please enter a file name:
transactions.csv
Equipment, 211.0
Groceries, 172.0
Insurance, 38.17
Savings, 500.0
Conclusion
In this blog post, we went from a naïve haskell program doing IOs, to a less naïve implementation that deals with exceptions and failures, while trying to keep the program flow simple and the amount of boiler plate to a minimum. I hope you enjoyed it and learned from it. I would greatly appreciate feedback! You can email me at cthibauttof@gmail.com or contact me on Twitter: @ToF_.
The program can be found on github
Enjoy!
THANK YOU Andrea Chiou for helping me to improve my writing. THANK YOU Arnaud Bailly for making Haskell easier to learn for me.
What Problem Are You Solving Together?
2020-07-22
”What problem are you solving together ?” is by far my preferred question at work, and probably the most powerful, too. It can be quite incisive, if the reactions it creates are any measure:
« What do you exactly mean by problem? »
« We are not specifically solving a problem here, we are [XYZ]. »
« Not sure there is only one problem... »
« Not sure we are solving it together... »
« Where are you going with that kind of questions anyway? »
Whenever I ask this question to a group, and they start giving answers, it’s like a large white table cloth being laid on a large table, and every person in the conversation starts putting objects on that white table. What kind of objects? Objects of any kind, big objects and small objects, useful and useless, practical or cumbersome objects. And what happens next? Then I begin to visualize distances and other spatial relationships, and I get to explore, via asking more questions, the “space” of the problem, whatever that means.
I work with teams that are stuck in some way or another. They are having a difficulty with regression testing, with bugs, or with their decision making, or they are trying to reconcile a tight schedule with improvements in code quality. They find that they have to negociate the amount of refactoring activity for the next ’sprint’. They fight over deciding if the issue X is a bug or a request for change. They are tempted, or asked, to go faster in a direction that seems barely established.
To summarize, they are trying to solve a problem together, and doing so, they keep exploring not only the ’solution’ (which, despite what expert reports, marketing brochures and roadmaps claim, probably doesn’t exist and certainly can't be implemented at that point), but also the problem space itself. My questions only help them put into words, sometimes in figures, the specific aspects of the problem on which, as they discover, they were not really agreeing. When this exploration work is done — it can take from two hours to two weeks maybe, depending on the dimensions of the endeavor — a lot of ways to improve their efficiency as a team start appearing.
Let’s define a problem as the difference between a perceived situation and a desired situation. Let’s add some key informations :
- who is having the problem? (who is perceiving, and desiring?)
- what are the objectives?
- what are the constraints?
- what resources are we allowed to use?
- what are heuristics we can apply here?
- what is our state of the art?
I have never met a team that was stuck and had a coherent, aligned answer for these questions. It seems that every time I ask: “what problem are you solving together?” there will be a variety of conflicting positions with regard to one or several of these characteristics. Once the question gets asked, the table cloth is spread on the table, and the various objects laid out, then the group is ready to move forward solving the problem together.
Coding Katas and Problem Solving
2020-08-24
For years I have been practicing around coding katas at the Developers Dojo in Paris. What I like about coding katas in the context of a programming Dojo is that these exercises are generally based on simple, well-defined problems that are easy to explore. In that way, they present us with an opportunity to improve our problem solving skills as well as our coding skills.
For instance: we want to implement a program that tells if a certain telephone number is included in a quite large list of numbers, using only a very limited amount of memory. Or the program has to compute that answer super fast, etc. At the outset of the programming session — or sometimes right in the midst of it — someone asks: are we allowed to change the number format ? Will there be more than one query? And so on. Every question we ask about the problem, the constraints, the resources (including the time we have for the coding session), the possible heuristics that we have at our disposal — or that we need to learn about — is a way of exploring the problem space of the kata. This exploration is at least as important as the coding involved in the session, and is core to any software development no matter its size or complexity.
The other day a colleague of mine signaled to our group that he had created a repository where “we can push the solutions to several katas, in Java, C#, JS”. As much as I use coding katas in my training sessions, I found myself questioning the utility of such repository. To me the point of a code kata is learning by doing, not getting to know what the code should look like once the kata is ’solved’. However, I don’t want to disparage what could still be a source of information about programming. So I responded : “you mean, some solutions?”
Coding katas are often criticized, being seen as problems that are too simple to present any educational value to a developer in “real life”. I personally would not mete out such a definitive judgment on coding katas and want to say to these detractors: it’s still better than the alternative, i.e being caught in real life programming situations that are complex beyond my capacity to solve them and learn from them. But also: there’s always the possibility of tweaking the problem statement to make the kata less simple.
Doing a code kata as a group — whether you are comparing approaches done by pairs or you are doing mob programming — brings a new dimension to the problem-solving situation. In effect, we need to understand each other and communicate in such manner that the group constitutes a problem-solving efficiency boost rather than an hindrance. (Spoiler alert: in both cases, you will learn a lot). I won't pretend that I could handle any development situation with outstanding problem-solving abilities, but I know what hundreds of weekly coding sessions at the Paris Developers Dojo specifically taught me. Over the years, I’ve learned to :
- keep calm and patient even in times when as a group we seem to be completely lost and ineffective;
- shut up and listen, especially when I think I understand the problem and feel an urge to intervene;
- explain something (that I think I understand) in the best possible way;
- put a finger on the parts I don’t understand, and ask for help;
- find, compare, and elect better names for all the things our code is made of;
- debrief the session, explicitly extracting what I learned, and how my mistakes obstructed the way;
- explore my feeling of frustration when the problem — or the code — seems to stare at us with a smirk on its face;
- defend and illustrate the principle that there is no such thing as a stupid question;
…All the while having great fun.
The Bowling Score Kata
2020-09-12
As I am currently rereading Leo Brodie's Thinking Forth, I am amazed about how most of the program design tips in this 1984 book are still relevant today. The author's first book, Starting Forth initiated a life-long love story with programming for me, and Forth is still one of my favorite languages. In this post I will try to convey a sense of the Forth philosophy while solving the popular Bowling Score Kata using gforth. Although doing TDD in Forth is very easy, I choose to not include the tests in this post in order to keep it short.
The Problem to Solve
Write a program which, given a series of rolls delivered by a Ten Pin Bowling player, computes the current score of this player. The roll values will be consistent with the game rules: no illegal values (such as -1, 11 or values totaling more than 10 in a frame). In test cases where not all rolls have been played, the resulting value should be the minimum score obtained (i.e the score value if all the subsequent rolls were 0).
Here is an excerpt of the game rules:
A game of bowling consists of ten frames. In each frame, the bowler will have two chances to knock down as many pins as possible with their bowling ball. In games with more than one bowler, as is common, every bowler will take their frame in a predetermined order before the next frame begins. If a bowler is able to knock down all ten pins with their first ball, he is awarded a strike. If the bowler is able to knock down all 10 pins with the two balls of a frame, it is known as a spare. Bonus points are awarded for both of these, depending on what is scored in the next 2 balls (for a strike) or 1 ball (for a spare). If the bowler knocks down all 10 pins in the tenth frame, the bowler is allowed to throw 3 balls for that frame. This allows for a potential of 12 strikes in a single game, and a maximum score of 300 points, a perfect game.
Specifications
To make the expected behavior of the program clearer, here are some specs, in the format usually displayed on the SPOJ online judge. The program will read the input stream and print results on the output stream.
Input
- t – the number of test cases, then t test cases follows.
- each test case consists in 2 lines:
- n - the number of rolls delivered, ( 0 < n ≤ 21 )
- r1,..rn - the rolls delivered ( 0 ≤ r ≤ 10 )
Output
For each test case output one integer: the score made by the player after they played all the rolls in the test case.
Example
Input
3
2
4 6
4
10 7 3 5
12
10 10 10 10 10 10 10 10 10 10 10 10
Output
10
40
300
Solving it with Forth
Main Routine
Let's pretend we have one of these bowling score sheets and use it to mark the points made as we receive the numbers: 10, 7, 3, 5:
10 : we mark a strike X
and are ready to use the next frame column on the sheet. The score for the frame is still not calculable given that the next frame throws are not known yet.
*7* : we mark a 7 on the first column of the frame. The score for frame 1 is still not known yet, as we are expecting two more rolls to determine it.
*3* : we mark a spare `/` and are ready to use the next frame column. The score for the first frame is 20, and the score for this frame is not known yet, as we are expecting a bonus from the next throw.
*5* : we mark a 5 on the first column of the frame. The score for frame 1 + frame 2 is 35.
So what we routinely do to keep the score is:
- mark the points made for the current frame
- keep track of the bonus generated by a strike or a spare
- collect the extra points when the roll corresponding to a bonus is being delivered and mark the score on the corresponding frame column
- decide, depending on the roll delivered, if we have to "close the frame", meaning go to a new frame column or play again in the current frame ("open frame")
- keep track of how many frame were already played in order to count the last supplementary rolls as part of the 10th frame, and not the beginning of a new frame.
- and of course, add the points (roll + extra) to the current score
This is basically what our main routine will have to do when given a value on the stack. The only difference is that our program will not need to mark the points and the score for each specific frame, just to keep the score updated. Here is some pseudo-code:
: ROLL+ ( #pins -- ) \ collect extra point from previous bonus applied to the #pins value ( frame count is between 0 and 9) IF ( add the roll value to the score ( check for bonus with this value given the current frame state ) ( close the frame or make it open depending on bonus found ) ( increase frame count if the frame is closed ) ;
Keeping the Score
The first thing we obviously need is a variable to memorize the player's score. Since that variable needs to be initialized, let's also create a definition to that effect:
VARIABLE SCORE : START 0 SCORE ! ;
Surely we will need to amend this definition to include several other variables.
Bonus
Let's interest ourselves in the bonus mechanism. When the player delivers a strike, their next roll and the following roll will be added as bonus. When the player delivers several strikes in a row, then the next roll will be added twice as a bonus.
roll 10 10 10 10 3
bonus 1 1+1 1+1
suppl 1 1 1
Bonus works like it is provided by a dispenser: we feed the dispenser with bonus points gained from a strike or a spare, and these bonus points generate a multiplication factor for the subsequent rolls that are added to the game. Once the bonus factor for a roll is consumed, the dispenser is ready to provide the bonus factor to be used with the next roll.
Since there are only 2 factors to consider and these are tiny values, we can store them in the same variable, which makes switching from bonus to supplementary bonus easy. The bonus part will occupy bits 0 to 1, while the supplementary part will be represented by bit 2.
VARIABLE SCORE VARIABLE BONUS : START 0 SCORE ! 0 BONUS ! ;
A spare creates a bonus factor of 1 and sets the next bonus factor to 0:
: SPARE \ set the bonus to 1, no supplement 1 BONUS ! ;
A strike increments the current bonus factor, and sets the next bonus factor (bit 3) to 1 with a bitwise OR
operation:
: STRIKE \ increase bonus, and set supplement to 1 BONUS @ 1+ 4 OR BONUS ! ;
Consuming the bonus consists in isolating the bonus value (bits 0 and 1) with a bitwise AND
, leaving that value on the stack and then right-shifting the bonus value by 2 positions on the right to make the next bonus (bit 2) the current bonus.
: BONUS> ( -- n ) \ produce bonus factor, get supplement ready BONUS @ DUP 3 AND SWAP 2/ 2/ BONUS ! ;
Now let's try our definitions.
START BONUS> . ⏎
0 ok
START SPARE BONUS> . BONUS> . ⏎
1 0 ok
START STRIKE BONUS> . BONUS> . ⏎
1 1 ok
START STRIKE BONUS> . STRIKE BONUS> . BONUS> . ⏎
1 2 1
We can see that our dispenser keeps track of the bonus factors to apply.
Collecting Bonus
Collecting the bonus can be done by multiplying the roll value by the bonus factor, and adding that to the score.
: COLLECT-BONUS ( #pins -- ) \ add extra points to score and advance bonus BONUS> * SCORE +! ;
Frame Count
Obviously we will have to remember how many frames the player has played. This requires another variable, and this variable should also be initialized at the outset of a game.
VARIABLE SCORE VARIABLE BONUS VARIABLE FRAME# : START 0 SCORE ! 0 BONUS ! 0 FRAME# ! ;
The frame count has to be incremented every time the player closes a frame (i.e delivers a strike or throw their second roll), but it will not go beyond 10:
: FRAME#> \ advance frame count FRAME# @ 1+ 10 MIN FRAME# ! ;
Frame State
When adding a roll to the game, how can we know if that roll is part of an open frame or if it starts a new frame? We have to keep track of the current frame state. If the frame is open, then we should be able to retrieve the first roll value from this frame.
Let's introducte another variable:
VARIABLE FRAMEA frame is either a new frame, meaning the player hasn't thrown her first roll yet, or an open frame, meaning the player has already thrown one roll. We can consider that when the value of the `FRAME` variable is 0, then it is a new frame, an open frame otherwise:
: OPEN-FRAME? ( -- ? ) FRAME @ ;: NEW-FRAME? ( -- ? ) OPEN-FRAME? 0= ;
The player "closes" the frame when she delivers a strike at first roll, or delivers the second roll. Marking the frame as closed can be done by setting the frame state to zero, and advancing the frame count.
: CLOSE-FRAME \ close frame and increment frame count 0 FRAME ! FRAME#> ;
The player "opens" the frame when the first roll is not a strike. Then the program has to store the value of this roll, and set the frame to open, i.e not zero. This can be done in a single step if we consider the value of the frame to equal the last roll + 1. Since the roll value can be a number from 0 to 9, a frame value between 1 and 10 means the frame is open and the last roll value is this frame value minus 1.
: OPEN-FRAME ( #pins -- ) \ open frame, saving 1st roll value+1 1+ FRAME ! ; : LAST-ROLL ( -- #pins ) \ retrieve the first roll value FRAME @ 1- ;
Again, we need to initialize the frame state before the game starts.
: START 0 SCORE ! 0 BONUS ! 0 FRAME# ! 0 FRAME ! ;
And now we can try our definitions.
START NEW-FRAME? . ⏎
-1 ok
7 OPEN-FRAME NEW-FRAME? . OPEN-FRAME? . LAST-ROLL . ⏎
0 -1 7 ok
3 OPEN-FRAME CLOSE-FRAME NEW-FRAME? . ⏎
-1 ok
Checking for Bonus
So far, we have word definitions to collect the bonus, declare a strike or a spare, increment the frame count, and update the frame state. What we need now is a word that will qualify the roll value that has been delivered, implementing the following rules:
-
We have a strike if the roll is a 10 and we are in a new frame. In that case, add points to the bonus and close the frame.
-
If the frame is new but we don't have a strike then open the frame, saving the roll value.
-
We have a spare if the frame is open and the sum of the rolls in the frame is equal to 10.
-
If the frame is open, wether we have a spare or not we have to close the frame.
Hence the words:
: CHECK-STRIKE ( #pins -- ) DUP 10 = IF DROP STRIKE CLOSE-FRAME ELSE OPEN-FRAME THEN ; : CHECK-SPARE ( #pins -- ) LAST-ROLL + 10 = IF SPARE THEN CLOSE-FRAME ; : CHECK-BONUS ( #pins -- ) NEW-FRAME? IF CHECK-STRIKE ELSE CHECK-SPARE THEN ;
Adding a Roll to the Current Score
We are almost done. Adding a roll to the game will execute these tasks of collecting bonus, adding the roll points to the score, checking for new bonus, and advancing the frame count. These last 3 tasks has to be executed only if the frame count is below 10, if it's not the case, then the roll value is dropped instead.
: ROLL+ ( #pins -- ) DUP COLLECT-BONUS FRAME# @ 0 10 WITHIN IF DUP SCORE +! CHECK-BONUS ELSE DROP THEN ;
Let's try our word!
START 4 ROLL+ SCORE ? ⏎
4 ok
6 ROLL+ SCORE ? ⏎
10 ok
3 ROLL+ 2 ROLL+ SCORE ? ⏎
18 ok
10 ROLL+ SCORE ? ⏎
28 ok
4 ROLL+ 2 ROLL+ SCORE ? ⏎
40 ok
10 ROLL+ SCORE ? ⏎
50 ok
10 ROLL+ SCORE ? ⏎
70 ok
6 ROLL+ 4 ROLL+ SCORE ? ⏎
96 ok
3 ROLL+ 5 ROLL+ SCORE ? ⏎
107 ok
10 ROLL+ SCORE ? ⏎
117 ok
8 ROLL+ 2 ROLL+ 7 ROLL+ SCORE ? ⏎
144 ok
: PERFECT START 12 0 DO 10 ROLL+ LOOP SCORE ? ; PERFECT ⏎
300 ok
Success!
Getting Numbers From the Input Stream
To get a number, we have to read the input stream character by character, skipping them until we find a digit, then reading characters while these are digits, accumulating them into the resulting number.
The standard word DIGIT? ( char -- n,-1|0 )
returns false if the character on the stack is not a digit, or true, preceded with the matching digit otherwise.
CHAR # DUP . DIGIT? . ⏎
35 0 ok
CHAR 2 DUP . DIGIT? . . ⏎
50 -1 2 ok
Here's a word to skip all input characters until a digit is met:
: SKIP-NON-DIGIT ( -- n ) BEGIN KEY DIGIT? 0= WHILE REPEAT ;
And here's a word to get a number:
: GET-NUMBER ( -- n ) 0 SKIP-NON-DIGIT BEGIN SWAP 10 * + KEY DIGIT? 0= UNTIL ;
GET-NUMBER . ⏎
foo4807 ⏎
4807 ok
Main program
Armed with this word, we can now add the top definition to our program:
: BOWLING GET-NUMBER 0 DO START GET-NUMBER 0 DO GET-NUMBER ROLL+ LOOP SCORE ? CR LOOP ;
The last commands in the program will execute our BOWLING
word and leave gforth:
BOWLING BYE
Testing
Let's put our program to test. Given the this input file:
# input.dat: a test file for Bowling.fs
5
4
3 5 2 7
6
10 5 4 10 5 2
12
10 10 10 10 10 10 10 10 10 10 10 10
20
3 5 3 5 3 5 3 5 3 5 3 5 3 5 3 5 3 5 3 5
3
10 10 10
The following result is obtained:
gforth Bowling.fs <input.dat ⏎
17
52
300
80
60
Et voilà! The Bowling Score Kata, in Forth.
The Program
The program and tests can be found here
\ Bowling.fs gforth Bowling.fs <input.dat VARIABLE SCORE VARIABLE BONUS VARIABLE FRAME# VARIABLE FRAME : START 0 SCORE ! 0 BONUS ! 0 FRAME# ! 0 FRAME ! ; : SPARE \ set the bonus to 1, no supplement 1 BONUS ! ; : STRIKE \ increase bonus, and set supplement to 1 BONUS @ 1+ 4 OR BONUS ! ; : BONUS> ( -- n ) \ produce bonus factor, get supplement ready BONUS @ DUP 3 AND SWAP 2/ 2/ BONUS ! ; : COLLECT-BONUS ( #pins -- ) \ add extra points to score and advance bonus BONUS> * SCORE +! ; : FRAME#> \ advance frame count FRAME# @ 1+ 10 MIN FRAME# ! ; : OPEN-FRAME? ( -- ? ) FRAME @ ; : CLOSE-FRAME \ close frame and increment frame count 0 FRAME ! FRAME#> ; : NEW-FRAME? ( -- ? ) OPEN-FRAME? 0= ; : OPEN-FRAME ( #pins -- ) \ open frame, saving 1st roll value+1 1+ FRAME ! ; : LAST-ROLL ( -- #pins ) \ retrieve the first roll value FRAME @ 1- ; : CHECK-STRIKE ( #pins -- ) DUP 10 = IF DROP STRIKE CLOSE-FRAME ELSE OPEN-FRAME THEN ; : CHECK-SPARE ( #pins -- ) LAST-ROLL + 10 = IF SPARE THEN CLOSE-FRAME ; : CHECK-BONUS ( #pins -- ) NEW-FRAME? IF CHECK-STRIKE ELSE CHECK-SPARE THEN ; : ROLL+ ( #pins -- ) DUP COLLECT-BONUS FRAME# @ 0 10 WITHIN IF DUP SCORE +! CHECK-BONUS ELSE DROP THEN ; : SKIP-NON-DIGIT ( -- n ) BEGIN KEY DIGIT? 0= WHILE REPEAT ; : GET-NUMBER ( -- n ) 0 SKIP-NON-DIGIT BEGIN SWAP 10 * + KEY DIGIT? 0= UNTIL ; : BOWLING GET-NUMBER 0 DO START GET-NUMBER 0 DO GET-NUMBER ROLL+ LOOP SCORE ? CR LOOP ; BOWLING BYE