Conception émergente

Le développement dirigé par les tests ou TDD, popularisé par eXtreme Programming, est une technique de développement logiciel très usitée au sein des personnes pratiquant les méthodes agiles. Son principe de base, "toujours écrire un test qui rate avant d'écrire le code qui permet de le faire passer", a pour avantage de focaliser l'attention du développeur sur l'écriture de code destiné exclusivement à remplir les fonctionnalités souhaitées pour le logiciel. Il participe ainsi à la mise en application d'un des principes du manifeste agile "Working software is the primary measure of progress".
Par ailleurs, son approche très séquentielle (un test après l'autre) et sécurisée (les tests déjà présents garantissent le bon fonctionnement de l'ensemble au fur et à mesure des modifications) fait écho à un principe non moins important : "Welcome changing requirements, even late in development".

Le TDD, de par son nom plutôt trompeur, est parfois considéré à tort comme une méthode de test. En réalité, il n'est rien de moins qu'une méthode de développement qui, par affinages successifs, guide la conception d'un logiciel.
Contrairement à d'autres méthodes qui prévoient une phase dite "de conception" où un grand nombre d'abstractions composant le logiciel sont imaginées et documentées en amont de l'écriture de code, le TDD favorise une conception au fil de l'eau au fur et à mesure que les abstractions recherchées apparaissent dans le code déjà écrit et testé. On parle alors de conception émergente.

Cette façon d'envisager le développement logiciel a donné lieu à de nombreuses controverses entre les partisans d'une quantité importante de conception avant le codage et ceux d'une progression plus incrémentale. Loin de moi l'idée de trancher ici un débat qui, à mon humble avis, a de beaux jours devant lui. Les discussions sur les méthodes de développement logiciel ont vocation à provoquer de manière récurrente des guerres de religion pour une raison très simple : le développement logiciel n'est pas une science comme peuvent l'être les mathématiques, la physique ou même certains aspects de l'informatique (algorithmique ou théorie des langages par exemple) qui ont été lourdement théorisés. Toutes les méthodes de développement logiciel, depuis les ancestraux cycles en V ou en cascade jusqu'aux plus récentes méthodes agiles en passant par les spirales, les MERISE ou autres RUP ne sont que des propositions d'organisation du travail fondées sur des constatations plus ou moins empiriques. On est là plus près de l'artisanat, avec toute la noblesse que peut revêtir ce mot, que de la science.
En fin de compte, les seuls arguments que peuvent avancer les promoteurs d'une méthode ou d'une autre sont la possibilité de voir fonctionner leur méthode chérie en grandeur nature et ainsi montrer que, dans au moins un ou deux cas, celle-ci donne de bons résultats. Encore faudrait-il pour cela que tout le monde puisse être d'accord sur des assertions telles que "sur le projet X, la méthode Y a été appliquée". On trouvera toujours quelqu'un pour venir affirmer que l'on n'a pas vraiment appliqué Y pour telle ou telle raison. Cette technique de dénégation marche d'ailleurs dans les 2 sens : pour tenter de prouver l'absence de bien fondé d'une méthode (dans le cas ou le projet est une réussite) et pour tenter de contrer cette pseudo-preuve (dans le cas où le projet est un plantage). Le manque de théorisation se fait ici cruellement sentir.

Dans un tel contexte, il serait vain de vouloir présenter la conception émergente comme une valeur sure prouvée, vérifiée, certifiée et systématiquement plus efficace qu'une grosse conception en amont. Pour les raisons évoquées précédemment, aucun argument en ce sens ne pourrait sérieusement tenir la route. Seul un menteur peut prétendre prouver qu'une méthode de développement donne de meilleurs résultats qu'une autre. Je ne vais donc pas essayer de prouver quoi que ce soit. Les seuls objectifs valables sont d'essayer de mettre en lumière certains points auquel on ne pense pas toujours quand on fait du logiciel et d'apporter, à travers quelques exemples, une vision de ce que peut être une conception émergente.
Une chose qui m'a souvent frappé dans le développement logiciel, c'est à quel point des techniques issues de domaines totalement différents pouvaient être assimilées à mauvais escient. Je ne sais si on peut identifier avec certitude l'origine d'une séparation et d'un phasage entre conception, codage, tests, etc. Il y a probablement là des pratiques héritées de domaines d'ingénierie (batiment, automobile, ...) où le dessin de plans avant la réalisation concrète permet d'avoir une vision très proche du résultat final tout en profitant de très bas coûts grace à la faible qualification des personnes chargées de la réalisation concrète. Il y a surement aussi un usage datant d'une époque où matériel et logiciel étaient développés en parallèle. Ainsi, quand le codage doit attendre la disponibilité effective du matériel, date à laquelle il devient le chemin critique, on a tout intérêt à occuper utilement le temps de conception du matériel à une définition extrêmement détaillée (la moindre fonction avec le moindre paramètre) sur papier des logiciels à venir. Quand le matériel devient disponible, le codage consistera en une simple opération de saisie quasi-mécanique.
A titre personnel, j'estime que de telles pratiques ne bénéficient d'aucune justification sérieuse avec les outils de développement d'aujourd'hui qui permettent des cycles de conception-code-test de moins d'une minute.

Dans une série de billets à venir, je vais essayer de montrer, étape par étape, ce que peut donner la réalisation d'un logiciel par TDD en essayant de mettre en évidence les éléments de conception de ce logiciel qui émergeront au fil des étapes.
Je vais pour cela tenter de réaliser un logiciel d'abonnement et d'écoute de podcasts en appliquant les principes suivants :

  • développement en TDD (écriture de test avant le code, refactorings, ...)
  • minimisation des responsabilités des composants interagissant avec le monde extérieur (utilisateur, internet, ...) avec notamment l'utilisation de patterns tels que le humble dialog box.
  • définition d'interfaces claires entre les composants de manière à simuler au mieux les interaction externes lors de la réalisation des composants représentant le coeur du logiciel.
  • forte cohésion et faible couplage des composants ce qui en pratique suppose des interfaces entre composants réduites à leur minimum mais les plus expressives possibles quant à leur intention.
  • DTSTTCPW
  • étapes de développement définies par les scénarios utilisateur (1étape = 1 scénario)
  • en début d'étape formalisation du scénario sous la forme d'un diagramme de séquence le plus simple possible : il ne s'agit pas de décrire toutes les classes entrant en jeu mais de proposer un découpage initial en composants qui sert de trame pour le premier test de l'étape.
  • en fin d'étape, le scénario utilisateur fonctionne ainsi que tous les scénarios implémentés précédemment.
  • utilisation adéquate des possibilités offertes par la technologie utilisée. En l'occurrence, le développement sera fait en C# avec les principe généraux suivants : tout composant utilisant un autre lui fait ses appels à travers une interface; tout composant utilisé par un autre remonte des informations en utilisant des évènements.

Pour ce logiciel d'écoute de podcast, je vais me baser sur les scénarios suivants en les implémentant l'un après l'autre :

  1. L'utilisateur s'abonne à un flux de podcast et visualise la liste de ses éléments.
  2. L'utilisateur sélectionne un élément de podcast dans la liste et l'écoute.
  3. L'utilisateur s'abonne à un flux de podcast, quitte l'application puis la relance : l'abonnement au podcast est conservé.
  4. L'utilisateur s'abonne à un ensemble de flux de podcast et visualise l'ensemble de leurs éléments.
  5. L'utilisateur recherche un élément de podcast en donnant une partie de son titre.

Restez abonnés à ce blog pour connaître la suite des évènements ! (on peut même désormais s'abonner par courrier électronique)
Les prochains billets seront intégralement dédiés à la description détaillée des diverses étapes de développement :

  1. 16/08/2007 TDD sur page blanche
  2. 21/08/2007 Intégration
  3. 24/08/2007 Finalisation avant 1ère livraison
  4. 02/09/2007 Nouveau scénario
  5. 12/09/2007 Deuxième livraison
  6. 20/09/2007 Persistance