Overblog
Editer l'article Suivre ce blog Administration + Créer mon blog
Laurent COCAULT

On ne vous dit pas tout

Le développement logiciel peut être défini comme le processus créatif permettant de répondre au besoin d'un groupe d'utilisateurs avec une solution logicielle. Ce processus est principalement basé sur la production et la transformation d'informations partant de la capture d'un besoin à sa satisfaction. De manière générale, il comprend différentes étapes qui peuvent être menées de manière séquentielle, selon une approche strictement linéaire ou itérative et incrémentale. Et dans le monde du développement logiciel, ces étapes sont souvent portées par des personnes différentes qui doivent échanger l'information produite et transformée. Cet article se propose d'exposer les enjeux de la gestion de l'information sur un développement logiciel ainsi que les solutions qui peuvent contribuer à la fiabiliser.

Processus et rôles

Les étapes classiques d'un développement logiciel consistent à :

  1. Définir une solution répondant au besoin des utilisateurs.
  2. Concevoir la solution.
  3. Réaliser la solution.
  4. Mettre la solution à disposition des utilisateurs. 

La capture d'un besoin est loin d'être triviale, notamment parce que les utilisateurs se font souvent une fausse idée de leur besoin, en se projetant souvent prématurément de l'espace du problème à celui de la solution. Pour illustrer cette difficulté, on cite souvent, à tort ou à raison, Henry Ford.

If I had asked people what they wanted, they would have said faster horses.

https://hbr.org/2011/08/henry-ford-never-said-the-fast

Dans un projet de développement logiciel, le rôle de l'analyste métier est justement de capturer le besoin des utilisateurs et de le traduire en une solution optimale. Le critère d'optimalité suggéré ici tient compte de différents facteurs allant, bien évidemment, de la satisfaction du besoin ressenti et exprimé, aux critères de coût et de disponibilité. Dans cette étape du processus, l'analyste métier doit répondre à deux questions: Pourquoi et Quoi.

  • Pourquoi est-il nécessaire de développer une nouvelle solution ? Cette question est celle qui doit justement permettre de capturer le besoin, d'identifier quelle est l'insatisfaction de l'utilisateur.
  • Quelle solution proposer pour répondre au besoin des utilisateurs? Cette question est celle qui permet de se projeter de l'espace du problème à celui de la solution et de spécifier ce qui doit être fourni en sortie du processus global.

Une fois la solution définie en termes de comportement cible, l'étape suivante du processus de création consiste à poser la question du Comment. Comment la solution proposée va-t-elle être réalisée et mise entre les mains des utilisateurs finaux. Deux rôles sont susceptibles d'entrer en jeu dans la définition du Comment.

  • L'architecte de la solution. De nombreuses solutions logicielles sont trop ambitieuses pour être réalisées sans un travail préparatoire permettant de décomposer le processus en plusieurs étapes. C'est le rôle de l'architecte de la solution de se pencher sur cette décomposition qui doit porter à la fois sur la solution elle-même et sur le processus qui va permettre sa réalisation.
  • L'ingénieur logiciel. C'est lui qui donne à la solution sa forme logicielle en détaillant la réponse à la question du Comment pour en éliminer toutes les imprécisions et ambiguïtés résiduelles.

Lorsque la solution logicielle est réalisée, il reste à la mettre à disposition des utilisateurs. Cette étape peut prendre des natures très diverses qu'on pourra distinguer en deux grandes familles :

  • Mettre à disposition le logiciel lui-même et confier le soin à l'utilisateur de le déployer, de le configurer et de le maintenir en état (en procédant régulièrement à des mises à jour),
  • Mettre à disposition le logiciel en tant que service accessible par des moyens communs dont disposent déjà les utilisateurs finaux (par exemple un navigateur Web).

Dans le second cas en particulier, il est nécessaire de gérer l'information permettant de garantir que le service est effectivement rendu aux utilisateurs et que les besoins identifiés sont satisfaits. 

Ce processus créatif est résumé dans la figure suivante.

On ne vous dit pas tout

Dans la plupart des cas, le processus de réalisation présenté ci-dessus implique plusieurs personnes. Il n'est pas rare que chacun des rôles présentés ci-dessus soit occupé par plusieurs personnes. Dans ces situations, il devient alors essentiel de fiabiliser la transmission de l'information entre les étapes du processus de développement.

Enjeux de la gestion de l'information dans le développement logiciel

Certaines des difficultés qu'on peut encore observer sur de nombreux projets sont une manifestation d'un problème de fiabilisation de cette chaîne de transmission de l'information :

  • Le faible taux d'utilisation effectif des logiciels (l'étude réalisée en 2019 par Pendo fait état de 24% de fonctions qui ne seraient jamais utilisées et 56% qui le seraient rarement) est une manifestation d'un problème de capture des besoins utilisateurs. Il peut certes exister de nombreuses raisons pour lesquelles une fonction reste légitime sans pour autant être utilisée (on pensera par exemple aux procédures de restauration du système), mais une mauvaise perception du besoin utilisateur ou sa mauvaise traduction dans les spécifications peut l'expliquer en partie.
  • Un autre exemple est celui de l'origine des anomalies constatées sur les logiciels. Selon les études, 45% à 64% des anomalies sont issues des phases de spécification ou de conception. Dans de nombreuses situations, l'implémentation est conforme à la spécification ou à la conception, mais a levé implicitement certaines ambiguïtés en prenant une décision contraire à la satisfaction des besoins utilisateurs. On peut également observer ce phénomène entre la phase de spécification et la phase de conception par une introduction de "fausses contraintes" de développement, par exemple une réponse à des besoins de performances qui n'ont pas été formulés.
  • Un autre exemple encore est celui des anomalies qui sont reportées à tort contre le logiciel en raison d'une erreur d'utilisation ou d'administration. Derrière la blague "Ce n'est pas un bug, c'est une fonctionnalité avancée" se cache le fait que les comportements logiciels sont parfois tellement complexes qu'il est difficile de cerner précisément ce qui est attendu du comportement d'un logiciel. Les défauts de documentation d'utilisation d'un logiciel peuvent notamment contribuer à créer ce flou entre comportement nominal et anomalie.

Ces quelques exemples, et il en existe bien d'autres, illustrent les impacts négatifs que peuvent avoir les problèmes de transmission de l'information au sein du processus de développement logiciel.

La difficulté et le risque sont pourtant bien connus, car inhérents à toute communication. Dans toute communication humaine, seule une partie de l'information est correctement échangée entre deux interlocuteurs. Sans pouvoir retrouver les chiffres, j'ai gardé en tête le taux de 60%. Pour comprendre d'où vient cette perte d'information, prenons un schéma de communication inspiré de celui de Jakobson.

On ne vous dit pas tout

Dans ce schéma :

  • Un individu souhaite transmettre une information et formule un message.
  • Ce message est formalisé en utilisant un langage apportant à la fois une grammaire et un lexique de base,
  • Le langage utilisé est "coloré" avec un référentiel qui apporte des précisions sémantiques sur certains éléments du lexique,
  • Le message s'inscrit dans un contexte qui peut implicitement être référencé par le message,
  • Le message est véhiculé jusqu'au destinataire en utilisant un canal qui peut par exemple être écrit, oral ou électronique.

Prenons un exemple : Alice travaille avec Bob sur le développement d'un site de e-commerce. Alice joue le rôle d'analyste métier tandis que Bob est l'architecte de la solution. Alice souhaite préciser à Bob une règle de fonctionnement du panier de commande. Elle crée ainsi un ticket sous Jira pour spécifier un nouveau comportement qu'elle décrit comme suit : "Le client peut supprimer un article de son panier à tout moment." Dans cet exemple :

  • Alice est l'émetteur du message.
  • Bob est le récepteur du message.
  • Le langage du message est le français.
  • Le contexte du message est celui de la spécification d'un site de e-commerce.
  • Le référentiel donne une sémantique particulière au mot panier qui décrit un ensemble de produit que le client s'apprête à acheter. Dans le contexte d'un système de gestion de matchs de basket, le mot panier aurait probablement porté une sémantique différente.
  • Le canal de communication est un outil informatique.

Dans un tel schéma de communication, il existe plusieurs raisons pour laquelle l'information que l'émetteur souhaite transmettre au récepteur soit dégradée :

  • L'émetteur ne parvient pas à formuler un message complet. Il omet par exemple certaines informations qu'il pense triviales et qu'il ne pense pas à inclure dans son message.
  • L'émetteur dégrade l'encodage de son message par un manque de maîtrise du langage utilisé. Ce cas de figure se produit assez souvent lorsque les parties prenantes d'un projet communiquent dans une langue qui n'est pas leur langue maternelle. Par ailleurs, la structure grammaticale de certains langages naturels prête davantage à des risques d’ambiguïtés ou de contre-sens.
  • L'émetteur fait référence à des termes du référentiel qui sont insuffisamment définis et qui portent en eux-mêmes une part d’ambiguïté. Un risque classique dans ce domaine consiste pour l'émetteur à inclure des termes de son champ de compétence technique plutôt que du domaine métier ; le risque étant maximal lorsque le même mot existe dans les deux.
  • L'émetteur et le récepteur ne partagent pas une vision commune du contexte dans le cadre duquel l'échange a lieu.
  • L'émetteur utilise un canal bruité. Par exemple, une communication orale dans un environnement bruyant, dans une langue étrangère, ou impliquant un interlocuteur avec une surdité partielle.

Lorsque vous êtes récepteur d'un message, vous pouvez légitimement penser qu'on ne vous dit pas tout. Ou plus exactement, que vous n'entendez pas tout.

La difficulté posée par la déperdition d'information dans un développement informatique est qu'elle implique une chaîne de transmission de l'information qui peut comporter de nombreux interlocuteurs. Et si seuls 60% d'une information passent dans un échange direct, seuls 36% passent lorsque l'échange est indirect. Avec une chaîne de transmission comportant 4 interlocuteurs successifs, ce sont à peine plus de 20% de l'information qui parviennent au destinataire final. C'est le principe sur lequel s'appuie le jeu du téléphone arabe.

Comment, dans ce cas, fiabiliser la transmission et la consolidation de l'information au cours du processus de développement logiciel ?

De la nécessité de communiquer, et de bien communiquer

Tout seul on va plus vite, ensemble on va plus loin

Proverbe Africain

Le meilleur moyen d'éviter la déperdition d'information reste encore de ne pas avoir à la transmettre. Ceux qui ont à la fois mené certains développements en autonomie, notamment des "side projects", et des développements en équipe, peuvent en mesurer l'écart de complexité. Mais la nécessité de collaborer pour développer des logiciels est une réalité de notre métier : notamment parce qu'on développe rarement un logiciel pour soi, mais pour un client et pour un groupe d'utilisateurs. Et surtout parce que l'ampleur du travail à réaliser et son échéance permettent rarement un développement en solo. Ainsi, dans le schéma proposé en introduction de cet article, il faut considérer que chacun des rôles (utilisateur, analyste, architecte, ingénieur logiciel et opérationnel) est potentiellement joué par plusieurs personnes qui doivent également communiquer pour consolider une vision commune de l'information qu'ils doivent transmettre aux autres rôles.

Partant de cette nécessité de devoir impliquer plusieurs personnes pour mener le projet à son terme, une approche pour minimiser la déperdition progressive d'information consiste à privilégier les échanges directs et éviter les intermédiaires. Autrement dit, favoriser des échanges directs entre toutes les personnes occupant le même rôle, toutes les personnes occupant des rôles voisins dans la chaîne de transmission de l'information, voire toutes les personnes du projet. C'est ainsi qu'on peut décider de réunir très régulièrement tous les participants du projet. Malheureusement, cette approche nous expose à une autre difficulté : la loi de Brooks évoquée dans cet article: "Pensez à votre bermuda". L'explosion combinatoire des canaux de communication dans une équipe où chacun communique avec tout le monde nous invite à considérer une segmentation des échanges ; elle nous invite à organiser le projet pour que certaines personnes n'aient pas à communiquer de manière étroite et régulière.

Enfin, pour avoir une vision globale du problème considéré, il faut le projeter dans le temps. L'équipe évoquée dans le paragraphe précédent n'est jamais stable. Certaines personnes vont la quitter et emporter avec eux de la connaissance ; tandis que d'autres vont la rejoindre en cours de projet, en n'ayant aucune connaissance de l'historique du projet et des échanges qui se sont tenus préalablement à leur arrivée. La transmission d'information ne doit donc pas seulement être considérée comme un problème de communication instantanée mais également comme un problème de pérennisation et de dépréciation des informations produites.

Le problème étant posé, commençons à considérer les éléments de solution que nous avons à notre disposition pour fiabiliser la transmission d'informations au sein d'une équipe. Les axes principaux sont les suivants :

  1. Le schéma global de communication,
  2. La nature des canaux de communication,
  3. Le contexte et le référentiel,
  4. Le protocole d'échange et les acquittements.

Schéma global de communication

Commençons par le schéma global de communication avec deux principes clés :

  1. Minimiser le nombre de personnes ayant à interagir,
  2. Organiser l'équipe pour que ces personnes aient besoin d'échanger le moins possible.

Concernant le premier point, il est important de considérer l'approche dans la durée du projet. Il ne s'agit donc pas simplement de respecter la loi de Brooks en considérant le nombre de personnes impliquées à un instant donné, mais également de stabiliser l'équipe. 

Le second point a des implications fortes sur les choix d'organisation de l'équipe et, par application de la loi de Conway, sur les choix d'architecture de la solution. Lorsque la taille de l'équipe nécessaire à la réalisation du projet, dans le délai imposé, dépasse les 6 à 7 personnes, il devient nécessaire de constituer plusieurs équipes dont on cherchera à maximiser les échanges internes et minimiser les échanges externes. Cette prescription est analogue au principe de couplage faible et cohésion forte qu'on trouve au niveau des architectures logicielles.

Ces deux sujets sont particulièrement riches et je ne prétends pas pouvoir les adresser exhaustivement dans le cadre de cet article. La lecture d'ouvrages tels que "Team Topologies" de Matthew Skelton et Manuel Pais permet d'explorer en détails les options d'organisation permettant d'atteindre ces objectifs.

Canaux de communications

La nature des canaux de communication doit également être considérée avec soin, et leur usage doit être retenu en tenant compte du contexte de l'échange. Listons pour commencer quelques canaux de communication utilisés sur des projets de développement :

On ne vous dit pas tout

Cette liste ne se prétend pas exhaustive mais permet déjà d'identifier quelques caractéristiques qui les distinguent :

  • L'oral et l'écrit. La communication orale et la communication écrite se distinguent par le caractère instantané auquel l'écrit échappe en partie. Lorsque vous êtes dans un échange oral, vous avez peu de temps pour préparer et délivrer votre message, là où l'écrit vous donne l'occasion de retravailler votre message avant de le délivrer. Du point de vue du récepteur, l'oral contraint à un traitement en temps réel de l'information sans possibilité de rejeu immédiate, alors que l'écrit vous permet de relire le message pour vous assurer d'une bonne compréhension. La contrepartie des avantages de l'écrit est celui d'un débit d'information plus lent qu'à l'oral. Le choix entre oral et écrit peut donc tout à fait considérer le trade-off, classique en matière d'architecture, entre fiabilité et débit.
  • Le présentiel et le distanciel. Cette alternative vaut pour un échange oral. Elle suggère que toute l'information transmise entre émetteur et récepteur n'est pas nécessairement verbalisée. Avoir la capacité d'apprécier le langage non verbal de l'émetteur au moment où il délivre un message permet parfois de mieux interpréter l'intention derrière le message. De plus, des études ont démontré que notre capacité de mémorisation d'une information est liée à l'émotion ressentie lors de la réception de l'information ; un échange en distanciel est généralement plus "froid" qu'un échange en présentiel et on peut s'attendre à ce que cette différence joue dans la mémorisation du message.
  • Le volatile et le permanent. Il n'est pas toujours nécessaire de mémoriser l'information. En tous cas, il n'est pas toujours important de le faire sur le long terme. Certains messages ont en effet un contenu qui périme rapidement quand d'autres ont vocation à rester vrai et pertinent dans la durée. Cette caractéristique du message est aussi une caractéristique du canal de communication : certains canaux sont sans mémoire tandis que d'autres pérennisent l'information. Il est essentiel d'aligner correctement la durée de vie du message avec la persistance du canal de communication.
  • Le synchrone et l'asynchrone. Cette alternative vaut généralement pour un échange écrit (même si on ne doit pas exclure de nos réflexions la possibilité de laisser des messages vocaux ou des enregistrements de sessions d'échanges). Communication synchrones et asynchrones se différencient par la capacité à fiabiliser l'échange et par la contrainte organisationnelle qu'elles induisent. En effet, assurer un échange synchrone offre la possibilité pour l'émetteur de recevoir un acquittement de la part du récepteur. Mais cette possibilité exige des deux interlocuteurs qu'ils contraignent leur emploi du temps pour échanger directement.
  • Le ponctuel et le structuré. Certaines informations ne sont pas destinées à intégrer un contenu global dont la construction s'étend dans la durée. D'autres informations en revanche ne sont qu'une pierre de plus à un édifice dont la vision globale est nécessaire à la compréhension du message. Dans le premier cas, on pourra se permettre de recourir à des canaux de communication non structurés qui présentent les informations de manière séquentielle. Dans le second cas, on privilégiera des supports de communication structurés permettant de venir compléter un contenu préexistant.

Pour illustrer les cas d'usage des canaux de communication selon le contexte de l'échange, on pourra considérer les exemples suivants :

  • Une session de "brainstorming", ou toute autre activité collective de production d'information, aura tout intérêt à être menée en présentiel avec des échanges oraux. Ces sessions produisent en effet de nombreuses informations temporaires qu'il est important de ne pas conserver. De plus le langage non verbal est essentiel dans ces situations pour percevoir la façon dont une proposition est reçue par le ou les destinataires. En complément d'une communication orale, une communication avec un support visuel, par exemple un tableau blanc, s'avère souvent utile.
  • Un échange ponctuel ou collectif pour s'aligner sur une décision organisationnelle peut tout à fait passer par une communication orale en distanciel ou par un outil de chat. Si vous cherchez à trouver un créneau pour un échange en présentiel ou pour en esquisser l'ordre du jour, il n'est pas nécessaire de se réunir physiquement et il est inutile de conserver une trace des échanges de coordination.
  • L'exposé d'un sujet et le questionnement d'un ou plusieurs interlocuteurs sur sa pertinence peuvent faire l'objet d'un échange de courriels. Passer par l'écrit permet ici à l'émetteur de prendre le temps de synthétiser son exposé et au lecteur de l'analyser. Le caractère asynchrone laisse aux récepteur le choix du moment opportun, moment où il aura la disponibilité mentale nécessaire pour analyser le sujet et faire part de son avis. La pérennisation de l'information échangée n'est pas nécessaire à ce stade puisque le contenu exposé est soumis à commentaires, donc à modifications à court terme.
  • Les informations consolidées par échanges de courriels peuvent tout à fait trouver leur place sur un support de communication plus pérenne tel qu'un outil de gestion de connaissance. Cet outil présente l'avantage de proposer l'état actuel des connaissances ou des décisions sur le projet. Le caractère structuré de l'information permet un enrichissement progressif avec une nécessité de cohérence à terme.
  • Les documents sont un bon moyen de capturer l'état instantané d'une partie des connaissances du projet. Avant la généralisation des Wikis, les documents étaient souvent utilisés comme un moyen de construire la connaissance du projet. Actuellement, il est plus pertinent de les utiliser comme une capture à un instant donnée d'une partie de la base de connaissance, cette capture étant notamment échangeable avec des parties prenantes externes à l'équipe.
  • Les informations relatives à l'état d'avancement du projet ou utiles à la coordination des activités de l'équipe ont tout intérêt à être gérées dans un outil de gestion de tickets. Les informations ainsi gérées ont une durée de vie plus courte que les connaissances sur le "Pourquoi", le "Quoi" et le "Comment" de la solution et sont généralement moins structurées. Je ne prétends pas ici que les tickets d'une base Jira n'ont aucun intérêt à être reliés, mais que leur contenu reste assez ponctuel et qu'ils s'inscrivent dans un réseau d'informations moins fortement structuré que ne peut l'être l'inventaire des fonctions d'un logiciel ou l'organisation de ses composants.

Le référentiel et le contexte

Après la nature du canal de communication, la question du référentiel et du contexte est à prendre en considération. Qu'il s'agisse d'une communication orale ou écrite, le message échangé est en effet basé sur une grammaire et un lexique. Le cas de la grammaire suppose évidemment que l'émetteur et le récepteur partagent une langue commune, ce qui est également vrai pour le lexique. Les projets menés dans un contexte international rencontrent souvent des problèmes de ce point de vue puisque tous les participants ne maîtrisent pas la langue du projet, en général l'anglais, avec le même niveau de compétence.

Mais au-delà de la question de la langue naturelle utilisée, se pose la question de la sémantique propre au projet qui peut être attribuée à un mot du lexique. La difficulté est plus grande encore lorsque cette sémantique n'est pas constante et peut dépendre du contexte de l'échange. Il est alors essentiel de:

  1. Partager un glossaire des termes utilisées avec une définition, contextuelle au projet ou à la nature de l'échange, de chaque mot ayant une sémantique différente de son acception commune.
  2. Préciser, pour chaque échange, le contexte dans lequel il a lieu et invoquant certaines définitions particulières dans le glossaire du projet.

Protocoles et acquittements

Enfin, le quatrième point mentionné ci-dessus est celui du protocole de communication et des acquittements. La notion d'acquittement est primordiale pour sécuriser la bonne réception du message. Cet acquittement peut prendre plusieurs formes et porter une quantité d'information variable :

  • Dans un échange oral en présentiel, l'acquittement pourra prendre la simple forme d'un hochement de tête du récepteur par lequel il indique qu'il estime que le message a été reçu dans de bonnes conditions et est bien compris. Il est également possible de lister les points clés du message en fin d'échange pour s'assurer d'avoir perçu la totalité du contenu. Toujours dans le même contexte, l'acquittement peut être enrichi d'une reformulation partielle du message : "Si j'ai bien compris, tu veux dire que..." La transformation du message d'origine est, dans ce contexte, essentielle : reformuler le message dans les mêmes termes ne permet pas à l'émetteur de qualifier la bonne compréhension du fond.
  • Le cas des échanges écrits est différent dans le sens où plusieurs risques peuvent être écartés: canal bruité, manque d'attention à la réception... Dans ce cas, l'acquittement sera soit très sommaire ("bien reçu"), soit détaillé pour valider la compréhension sur le fond. Il sera ici inutile de lister les points clés comme cela est fait à l'oral ; l'écrit offre la possibilité au destinataire du message de le relire à plusieurs reprises pour s'assurer de ne rien avoir oublié.

Notons que la notion d'acquittement est le maillon faible des approches dites "cycle en V", avec un effet tunnel de plusieurs semaines à plusieurs mois au cours duquel l'équipe échange peu ou pas avec les utilisateurs finaux ou leurs représentants. Le fait que l'acquittement soit un élément clé d'une communication fiable explique que la notion de "feedback" utilisateur soit mise au cœur de nombreuses méthodologies depuis les années 1990, à commencer par les méthodes agiles et leur extension DevOps.

Outils et méthodes favorisant une communication de qualité

Cette réflexion nous amène à nous questionner sur les outils et méthodes dont les équipes de développement disposent aujourd'hui pour fiabiliser leur communication et favoriser le succès d'un projet. La figure suivante propose quelques-uns de ces outils (le sujet étant particulièrement vaste, cette vision ne se prétend pas exhaustive):

On ne vous dit pas tout
  • Ubiquitous Language: la base pour toute communication efficace est de s'accorder sur un vocabulaire commun. Rédiger un glossaire dès le début de projet, et le maintenir tout au long du cycle de vie du produit, est une activité à forte valeur ajoutée. Elle permet aux parties prenantes de s'accorder sur la sémantique spécifiques des termes du lexique qui vont supporter la quasi-totalité des échanges. Dans son ouvrage Domain Driven Design, Eric Evans nous propose cet alignement sur un vocabulaire commun pour chaque contexte ("bounded context") du produit à réaliser. Il utilise le terme de langage ubiquitaire (ou "Ubiquitous Language") pour désigner ce langage qui doit servir à l'ensemble de l'équipe de communiquer : il ne s'agit pas ici seulement d'aligner les analystes métiers avec les utilisateurs mais bien de proposer un langage métier qui trouvera une transcription jusque dans le code. Les architectes utilisent ainsi le langage ubiquitaire du projet pour nommer les artefacts de conception et les ingénieurs logiciel l'utilisent pour implémenter le logiciel. Le travail d'analyse permettant d'établir le lexique de ce langage ubiquitaire est essentiel pour deux raisons : il permet de lever les ambiguïtés sur les termes employés d'une part; et il permet d'identifier des doublons, des synonymes, d'autre part. Pour illustrer la plus-value de cette analyse, j'aime évoquer une mésaventure que j'ai connu sur mon premier projet professionnel : le client avait utilisé les termes d'ordre, de commande et de livraison dans ses spécifications. En travaillant sur la conception de la solution, je n'ai pas perçu le fait que ces trois termes désignaient le même concept et j'ai donc introduit des classes distinctes. Lors de l'implémentation, et puisque le travail de développement consiste à lever toute ambiguïté pour atteindre une forme exécutable par une machine, j'ai été amené à dupliquer beaucoup de code entre ces concepts, à chercher à les mutualiser progressivement par héritage, pour finalement me rendre compte que je n'avais qu'un concept et une seule classe. Les efforts de "refactoring" qu'il m'a fallu consentir pour arriver à cette conclusion auraient pu être évités avec un travail d'analyse du lexique du client. A l'inverse, il peut arriver qu'un même terme soit utilisé pour désigner des concepts différents, ou tout du moins des concepts proches qui ont des raisons de diverger à terme. Identifier ces divergences sémantiques est la bonne façon d'approcher le principe de responsabilité unique de SOLID (cf. mon article consacré à la duplication de code légitime).
  • Behavior Driven Development: l'alignement sur un lexique ne suffit pas à se comprendre. Lorsqu'un analyste métier cherche à synthétiser et formaliser un besoin pour permettre, avec l'architecte, l'élaboration d'une solution, il est nécessaire de travailler sur une formulation du comportement du logiciel la moins ambiguë possible. Le Behavior Driven Development est l'une des techniques permettant de supporter le dialogue entre les utilisateurs, l'analyste métier et l'architecte de la solution. Cette approche consiste à formaliser par écrit le comportement du logiciel en suivant un motif d'écriture standardisé. Par exemple, le langage Gherkin propose de formuler chaque comportement du logiciel en trois temps, chaque temps étant introduit par un "mot clé" : GIVEN ("Etant donné") précise le contexte dans lequel le comportement du logiciel s'inscrit, WHEN ("Quand") explicite une action ou événement qui déclenche le comportement, et THEN ("Alors") spécifie le résultat produit ou l'état dans lequel se trouve finalement le logiciel. En reprenant l'exemple du panier de commande évoqué plus haut, on pourra formuler un comportement du logiciel comme suit : "Etant donné un utilisateur affichant les articles de son panier, Quand il clique sur le bouton de suppression et confirme son action, Alors le panier est mis à jour sans l'article supprimé". Une telle approche de spécification peut s'avérer moins ambiguë encore lorsqu'elle s'appuie sur des exemples précis. La technique de la spécification par l'exemple (ou "Example Mapping") permet ainsi d'illustrer les comportements en identifiant les acteurs ou les données manipulées. Ainsi un même comportement peut être illustré avec des exemples différents. Cette technique permet à la fois d'éliminer les ambiguïtés et de constituer des scénarios utilisables pour valider le comportement du logiciel une fois développé. Si l'idée initiale reste de spécifier les comportements en langage naturel afin que toutes les parties prenantes, y compris les contributeurs non techniques, puissent s'aligner, le recours à un formalisme ouvre la possibilité d'une interprétation par un outil. C'est précisément de cette opportunité que tirent profits des outils tels que Cucumber qui peuvent "exécuter les spécifications". La capacité de produire une documentation testable est un facteur contribuant à sa maintenabilité. En effet, la documentation fait partie de la production logicielle, mais présente souvent l'inconvénient d'être difficilement maintenable dans la mesure où, contrairement au code logiciel, elle est rarement vérifiable automatiquement. Une solution permettant de répondre à cette difficulté consiste à minimiser la production documentaire ; une alternative consiste à produire une documentation testable.
  • 3 amigos: dans des projets de taille modeste, il est souhaitable de réunir l'équipe de réalisation le plus largement possible. Le travail de spécification peut alors impliquer les ingénieurs logiciel en charge de réaliser une fonctionnalité du logiciel et les testeurs en charge de vérifier les comportements correspondants. L'atelier des "3 amigos" consiste à réunir trois rôles pour spécifier un comportement cible : l'utilisateur (ou un représentant des utilisateurs), l'ingénieur logiciel en charge de la réalisation, et le testeur qui devra valider le comportement produit. On notera que cette déclinaison des rôles est légèrement différente de celle proposée en introduction de cet article, mais on peut considérer que les quatre premiers rôles du schéma ci-dessus recouvrent les responsabilités des trois amis. La raison pour laquelle on souhaite réunir ces trois amis lors de la spécification d'une fonction logicielle, est de confronter trois points de vue assez différents: le point de vue utilisateur sera focalisée sur la plus-value de la fonction développée, le point de vue de l'ingénieur logiciel sera concentré sur la faisabilité de la fonction, et le point de vue du testeur sur sa capacité à valider le comportement cible. L'atelier des trois amis doit permettre d'assurer qu'il sera possible de délivrer la plus-value métier attendue de l'utilisateur avant d'entamer des travaux de réalisation. Elle permet également de s'assurer d'une compréhension mutuelle des objectifs sur l'ensemble du processus de réalisation.
  • Maquette et Prototype: l'approche Behavior Driven Development est très efficace pour s'aligner sur un comportement cible. Elle présente néanmoins l'inconvénient de rester textuelle. Or, la reformulation vers des conventions d'écriture différentes offre la possibilité d'identifier des incompréhensions que la manipulation de texte n'élimine pas. Les techniques de maquettage et de prototypage font partie des moyens auquel il est possible de recourir pour changer de point de vue sur le logiciel à développer. Cette technique permet de travailler à la fois sur le comportement du logiciel, sur le rendu visuel (UI - User Interface) et sur l'expérience d'utilisation (UX - User Experience). Il est important de souligner ici le caractère généralement éphémère des maquettes et prototypes ; contrairement aux spécifications logicielles qu'il est utile de maintenir tout au long du projet, il est en général contre-productif de chercher à maintenir ces éléments qui servent plutôt de support à l'exploration dans les phases amont du développement. Notons également une différence entre maquette et prototype ; si on prend l'exemple d'un avion, une maquette permet d'appréhender la géométrie de l'objet, mais pas nécessairement sa dimension et une maquette ne vole pas. Un prototype en revanche sera proche de l'objet final et doit pouvoir voler. Il en va de même pour les logiciels : vous pouvez utiliser un outil tel que Figma pour représenter l'interface utilisateur et l'enchaînement des écrans; mais vous ne pourrez pas interagir avec cette maquette. Un prototype, en revanche, est une version préliminaire du logiciel proposant un visuel avec la technologie cible et proposant quelques interactions clés. Très vite, les premières versions du logiciel viennent supplanter la représentativité de ces artefacts de construction. Néanmoins, passer par ces étapes aura permis d'obtenir un retour utilisateur en investissant moins d'effort qu'un développement opérationnel.
  • UML et les Design Patterns : la nécessité de s'aligner sur une compréhension commune ne concerne pas seulement le comportement du logiciel. Il concerne aussi sa structure. Autrement dit, si les méthodes listées ci-dessus adressent le WHAT, celle-ci adresse le HOW. La responsabilité principale de l'architecte solution, et plus encore de l'architecte applicatif, consiste à définir la structure du logiciel. Cette structure aura un impact sur l'organisation des travaux de développement et de maintenance. In fine, ce sont les ingénieurs logiciel qui donnent corps à la structure définie par l'architecte. Il est donc essentiel que l'intention de l'architecte soit claire pour être traduite fidèlement. Pour ce faire, une description textuelle de la solution est incontournable, mais elle est rarement suffisante. Deux techniques viennent compléter l'approche textuelle : les diagrammes et la référence à des conventions.
    • Un diagramme est un vecteur puissant de communication des informations techniques relatives à la structure logicielle et à la façon dont cette structure supporte le comportement attendu. Ce constat n'est pas récent et de nombreux formalismes de description visuels ont été développés dans les années 1980 et 1990. Face à la multiplicité des formats, un travail de rationalisation a été entrepris sur la fin des années 1990 par les auteurs des formalismes alors dominants. Leurs efforts ont donné naissance à l'Unified Modeling Language qui proposait, dans sa première version, 9 diagrammes offrant une représentation de la structure ou du comportement du logiciel. Incontournable au début des années 2000, le langage UML n'est plus systématiquement utilisé aujourd'hui. Il présente pourtant l'avantage d'être un langage standardisé et de proposer des conventions non ambiguës pour représenter les détails d'une conception logicielle.
    • Les conventions sont en effet un moyen efficace de s'aligner sur une compréhension mutuelle de la structure à mettre en place. C'est l'un des avantages, insuffisamment invoqué, des Design Patterns. Ces motifs de solution réutilisables sont évoqués comme des moyens de ne pas réinventer la roue, d'adopter une solution ayant fait ses preuves pour répondre à un besoin commun. Mais la standardisation de ces briques de solution réutilisable présente un autre avantage : ils sont nommés, tout comme les constituant de la solution qu'ils proposent. Ainsi, la simple évocation par un architecte du Design Pattern ou de l'un de ses constituants, suffit à véhiculer l'intention de réalisation et la problématique adressée.
  • L'alignement de l'ingénieur logiciel: ce qu'on attend de l'ingénieur logiciel, c'est qu'il produise le code source du logiciel à réaliser. Cette étape du processus permet de produire un contenu non ambigu par définition. En effet, la sortie de cette étape est destinée à être exécutée par une machine qui ne supportera pas la moindre imprécision ou ambiguïté. Toute imprécision ou ambiguïté non résolue en amont donnera lieu à une résolution, consciente ou inconsciente. Il est donc important pour l'ingénieur logiciel de s'assurer de la qualité de l'information qu'il manipule et de la forme qu'il donne au code qui prendra vie dans la machine. C'est pour cette raison qu'on ne doit pas considérer que le rôle de l'ingénieur logiciel consiste à "pisser du code". L'ingénieur logiciel doit maîtriser le langage du domaine, connaître le comportement attendu et comprendre l'intention de structure de l'architecte pour produire le logiciel attendu. Pour s'assurer de prendre les bonnes décisions lorsqu'il interprète ses spécifications et qu'il les traduit en code source, il peut s'appuyer sur quelques disciplines individuelles ou collectives :
    • Test Driven Development : cette technique consiste à répéter un cycle de réalisation comportant trois étapes. La première étape consiste à rédiger un test unitaire qui spécifie un comportement élémentaire attendu et qui échoue ; la deuxième étape consiste à intervenir sur le code du produit pour faire passer les tests ; la troisième étape consiste à prendre un pas de recul pour adapter la forme ou rééquilibrer la structure du logiciel lorsque nécessaire. La première étape de ce cycle permet à l'ingénieur logiciel de se questionner lui-même sur sa compréhension du comportement attendu, sans polluer prématurément sa réflexion avec les questions de solution, d'implémentation. C'est lors de cette étape qu'il doit avoir la lucidité pour constater une imprécision ou détecter une ambiguïté. Pour mieux comprendre ce mécanisme, on pourra se référer à l'article : Suivez le lapin blanc... et le TDD.
    • Pair Programming : même en appliquant le Test Driven Development et en s'appliquant consciencieusement sur l'analyse du besoin technique lors de la première étape d'un cycle, l'ingénieur logiciel peut interpréter inconsciemment. Son cerveau peut combler les blancs s'en qu'il s'en rende compte. Une technique qui permet de compenser ce risque est la programmation en binôme (ou "Pair Programming"). Cette technique consiste à faire travailler deux cerveaux sur une réalisation, avec un seul clavier. L'ingénieur logiciel qui tient le clavier est appelé "pilote" ; l'autre ingénieur logiciel, appelé "navigateur", est celui qui guide la réalisation. Le navigateur explique au pilote ce qu'il doit réaliser. La nécessité d'oraliser la consigne de réalisation est, pour le navigateur lui-même, un levier puissant pour détecter un raccourci dans son raisonnement (un peu comme oraliser un problème avec la technique du Rubber Duck permet souvent d'invoquer une solution). De plus, la perception du pilote est un filtre efficace qui va permettre de confirmer que l'expression de la consigne est claire, que le raisonnement est complet et qu'il est lui-même aligné sur l'objectif.
    • Revue de pair : la revue de pair (ou "Peer Review") est une activité menée après la réalisation; c'est donc une activité de contrôle par nature. Mais c'est aussi une activité d'alignement, et c'est dans cet alignement que réside l'apport principal de cette pratique. Le principe consiste ici pour un ingénieur logiciel à soumettre un code réalisé à relecture par un autre ingénieur logiciel de l'équipe. La relecture dans ce contexte asynchrone permet de tester la lisibilité du code produit. N'oublions pas que le code source du logiciel est un élément de communication : entre l'ingénieur logiciel et la machine, mais également entre ingénieurs logiciels. Et comme le dit Martin Fowler : "N'importe qui peut écrire du code compréhensible par une machine; seuls les bons programmeurs savent écrire du code lisible par un humain". La lisibilité du code est ainsi vérifiée, dans le cadre du processus de développement, et permet d'identifier immédiatement des défauts en la matière, des maladresses de nommage par exemple, qui vont nuire à la compréhension collective de la base de code et pénaliser sa maintenabilité.
  • DevOps : on serait tenté de penser qu'une fois le logiciel réalisé, les ambiguïtés ont été levées et le reste du processus ne sert plus qu'à accompagner le logiciel en production. Il faut plutôt voir la suite de la production du code source comme une course pour aller chercher du "feedback". On va chercher à vérifier que les éléments développés s'intègrent correctement entre eux, avec leur écosystème et que le tout propose le comportement spécifié et un comportement qui réponde aux besoins des utilisateurs. On va chercher un maximum boucles de retour d'information sur la qualité de ce qui a été produit, le plus vite possible ; on va aller chercher les acquittements qui valideront les activités amont du développement logiciel. C'est l'essence du DevOps que de casser le mur entre les activités de développement et les activités opérationnelles: en faisant en sorte que le logiciel passe le plus rapidement possible du poste de l'ingénieur logiciel à l'environnement de production (c'est le sens des chaînes de CI/CD - Continuous Integration & Continuous Deployment) et que les retours utilisateurs (qu'il s'agisse de non conformités ou de nouvelles fonctionnalités) parviennent le plus rapidement possible entre les mains des ingénieurs logiciels. Le DevOps est certainement le mouvement qui illustre le mieux la quête entreprise au début des années 2000 avec l'agilité et qu'on retrouve dans le principe agile : "plus que suivre un plan, s'adapter au changement". Cette quête des boucles de "feedback" a d'abord amené les équipes de développement à casser les parois étanches du cycle en V pour finalement casser les murs entre le monde du développement et le monde opérationnel. Cette transformation est la démonstration d'une nécessité de fiabiliser la communication de bout en bout par une multiplication de boucles de "feedback" toujours plus rapides.

L'IA générative, ennemie et alliée ?

En ce début d'année 2024, l'attention du monde de l'IT est tournée vers l'IA générative. On nous promet que ces technologies vont révolutionner la façon de réaliser les logiciels, à la fois dans leur composition et dans le processus qui permet de les élaborer. Les solutions de GenAI doivent permettre de générer des spécifications, de générer des éléments de conception, de générer le code de nos logiciels. Est-ce que les capacités de ces outils rendent obsolètes les réflexions que je porte dans cet article ? Est-ce qu'il est inutile de se poser la question de la communication dans la mesure où les humains laisseront une place plus importante à la machine dans les processus de développement ? Je suis convaincu du contraire.

Le principe de fonctionnement des IA générative est celui d'une extrapolation probabiliste. L'IA produit un contenu à partir de ce qu'on lui a donné et d'un référentiel propre à son entraînement. Ce fonctionnement est un atout formidable pour produire une information synthétique à partir d'une base de connaissance et pour transformer la représentation de l'information. Mais elle n'est, par nature, pas créative ; même les hallucinations dont elle fait preuve ne sont en rien un indice de créativité mais simplement une conclusion statistique avec une probabilité dégradée restant néanmoins acceptable. Or, le propos de cet article est justement d'évoquer les problématiques d'imprécision et d’ambiguïté que nos cerveaux humains ont tant de mal à gérer. Nos prompts sont et resteront imprécis et ambigus. Et c'est de la qualité de ces prompts que dépend la qualité des sorties de l'IA. Le titre de cet article est ce qu'une IA générative pourrait penser, si elle avait une conscience, car on ne leur dit pas tout.

Les outils d'IA génératives vont certainement changer nos métiers en profondeur et apporter des leviers d'efficacité redoutables, mais en l'état actuel de leur fonctionnement, il est important de garder à l'esprit les risques qu'elles peuvent aussi nous faire courir. Le dispositif humain qui mène un projet s'est progressivement doté d'outils lui permettant de s'assurer que chacun s'est compris, que l'information est claire, que l'information est complète. On se méfie de nos interprétations inconscientes et on se dote de méthodes pour lutter contre elles. L'IA générative risque de ne pas en faire autant et de livrer une hallucination que nous pourrions accepter comme un fait. Vient avec ce fonctionnement, le risque d'intégrer une fausse spécification, d'intégrer à la conception de fausses contraintes, de développer des comportements incomplets ou invalides.

La question que toute une profession se pose depuis plus d'un an n'est donc ni anodine, ni triviale : comment utiliser la GenAI pour développer les solutions logicielles de demain ? Si cet usage vient renforcer notre capacité à synthétiser l'information et à produire, pour l'humain, des représentations alternatives lui permettant de fiabiliser la transmission de l'information et la détection d'incomplétudes ou d’ambiguïtés, alors le bénéfice pourra être gigantesque. Si cet usage vise seulement à remplacer l'humain par la machine, elle conduira à des désastres.

Partager cet article
Repost0
Pour être informé des derniers articles, inscrivez vous :
Commenter cet article