IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Les Tests en Trois Temps (3T) en pratique

3T
Thierry

« 3T » est une version simplifiée des incontournables TDD (Test Driven Development), une méthode dans laquelle on commence par écrire des tests pour aider (guider) le développement des fonctionnalités. Ce second article sur le sujet propose une illustration de « 3T » en action sous forme d'un miniroman. 9 commentaires Donner une note à l´article (5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Suite à la publication de mon article sur les Tests en Trois temps (« 3T »)Présentation de 3T et aux différentes questions pratiques que j'ai reçues, je me suis lancé dans la rédaction d'un second article facile à lire. Je ne voulais pas paraphraser le premier article et, en même temps, je voulais utiliser un ton léger. Pour cela je me suis décidé à présenter « 3T » sous la forme d'un miniroman, en m'inspirant de mes collègues passés pour inventer les personnages, et des problématiques courantes pour illustrer un projet fictif.

Pour rappel, « 3T » est une version simplifiée (et une vision personnelle) des TDD (les Développements Guidés par les Tests). Je suis parti du constat que les TDD sont souvent accusés, à tort, de ralentir les projets, d'être complexes et de couter cher. Le principe de base de « 3T » est de mécaniser le processus de développement en subdivisant les interventions et les rôles. Chaque sous-partie devient d'autant plus simple ; il suffit la plupart du temps de recopier le cahier des charges. Au prix de quelques légères entorses aux TDD, les développeurs peuvent alors concentrer leur énergie sur la qualité de leurs productions, tout en ayant une vitesse de développement élevée et un retour sur investissement fort.

Le premier article à propos de « 3T » est disponible sur le site de developpez à l'adresse suivante : https://thierry-leriche-dessirier.developpez.com/tutoriels/java/methode-3t/Présentation de 3T

Les codes présentés dans l'article sont volontairement simplifiés pour faciliter la lecture. Les codes réels sont disponibles dans le fichier Zip.

Zip avec les sources utilisées (projet « Boutique du Chien-Copain ») pour cet article : boutique-chien-copain.zip.

I-A. D'où vient « 3T » ?

Il est important de noter que « 3T » n'est en aucun cas une méthode « officielle », contrairement aux TDD. « 3T » est une proposition de simplification des TDD qui devrait suffire à la plupart des équipes. En effet, mon expérience personnelle, liée à l'utilisation de Xp, de Scrum et bien entendu des TDD, me conduit à croire que les développeurs n'utilisent pas tout (certains aspects des TDD sont difficiles à faire et mangent beaucoup de temps), mais se concentrent sur certains points importants dont « 3T » est un résumé cadré. On peut voir « 3T » comme la formulation d'une pratique de simplification dont l'objectif est de gagner du temps (et de l'argent). Dans cet article, « 3T » est associée à Scrum, ce qui permet d'en suivre la mise en place à travers un projet fictif. C'est une simple illustration.

I-B. Lexique rapide

« 3T » n'invente rien ; c'est seulement un résumé cadré d'autres méthodes. Les termes employés dans cet article ne sont pas nouveaux. Voici néanmoins quelques définitions rapides.

Scrum et Xp : ce sont deux méthodes agiles, souvent associées.

Sprint : dans Scrum, un Sprint correspond à une période (généralement 2-4 semaines) durant laquelle on doit développer un ensemble donné de fonctionnalités.

Dashborad : dans Scrum, il s'agit d'un tableau comportant trois colonnes : à faire, en cours et fait. Les fonctionnalités à développer durant le sprint sont indiquées sur des Post-It. Ces derniers changent de colonne en fonction de l'avancement. À la fin du sprint, tous les Post-It doivent être passés de la colonne des choses à faire à la colonne des choses faites.

Le sprint backlog : Il s'agit simplement du nom Scrum de la colonne des choses à faire dans le dashboard. Cette colonne est généralement positionnée à gauche.

II. Histoire

Cet article présente les Tests en Trois Temps (3T)Article sur les Tests en Trois Temps sur le site developpez.com sous la forme d'un miniroman. Les rôles des personnages et leurs interactions sont volontairement décrits de manière naïve. Pour cela, j'ai allègrement pioché dans les clichés les plus courants. Mais finalement, je crois que ça rend les acteurs plus touchants et plus proches. D'ailleurs j'ai le sentiment que chacun y retrouvera le portrait de ses propres collègues.

II-A. La société et son projet

La société « Chien-Copain » commercialise une gamme moderne de produits canins fabriqués dans ses usines dans le respect de l'environnement. L'enseigne s'est constitué une clientèle fidèle et régulière.

À l'occasion de l'ouverture de son vingtième magasin, la société « Chien-Copain » souhaite se doter d'un service de vente en ligne dont le nom sera « la Boutique du Chien-Copain ». L'entreprise dispose déjà d'outils de comptabilité et de gestion de ses stocks ainsi qu'un site vitrine sur Internet.

La Web Agency « Green Soft », qui avait déjà réalisé le site « www.chien-copain.fr » et dont les prestations avaient été appréciées, a naturellement été choisie pour développer la nouvelle application.

Dans le cadre de cet article, pour simplifier l'explication, on ne s'intéressera qu'à une sous-partie de la boutique en ligne : la génération d'un mot de passe et son cryptage.

II-B. Les personnages

Pour illustrer l'utilisation de « 3T » et les phases préparatoires, cet article met en scène une poignée d'acteurs. Certains sont des personnages principaux tandis que d'autres ont un rôle symbolique.

Je me suis attaché à bien séparer les rôles (responsabilités) pour mettre en évidence les possibilités de la méthode, notamment en termes de parallélisation des tâches. On gardera toutefois en tête que, dans la vraie vie, les membres de l'équipe rempliront plusieurs fonctions.

II-B-1. La cliente (Claire)

Claire est salariée de « Chien-Copain ». C'est d'ailleurs la seule de cette histoire ; tous les autres personnages travaillent pour « Green Soft ». Claire est en charge de la boutique en ligne. Elle écrit et gère le cahier des charges. Elle a pouvoir de décision.

Claire
Claire, la cliente

II-B-2. L'architecte (Laurent)

Laurent possède une solide expérience du développement. Il fréquente assidument les blogs des grandes SSII et les conférences. Pour lui, la réussite d'un projet passe nécessairement par les tests et il prend son rôle d'évangélisation au sérieux.

Laurent
Laurent, l'architecte

II-B-3. Le chef (Michel)

Michel a lui aussi de la bouteille. Il déjeune souvent avec Laurent, mais trouve que les TDD (Développement Dirigé par les Tests) sont trop complexes, d'autant qu'il a du mal à les faire accepter par sa hiérarchie pour des raisons budgétaires et à les imposer au sein de ses équipes. Il a découvert « 3T »sur developpez.com et compte bien l'appliquer sur le projet de la « Boutique du Chien-Copain ». C'est aussi un adepte des méthodes agiles et plus particulièrement de Scrum depuis qu'il a lu le livre « Scrum et Xp depuis les tranchées » sur Internet.

Michel
Michel, le chef de projet

II-B-4. Les développeurs (Julie, Sébastien et John)

Sébastien, Julie et John écrivent le code de l'application. Ils ont des expériences différentes.

Pour pimenter le tout, disons que Julie est la fiancée de Laurent (l'architecte) et que ce dernier lui décrit régulièrement les bienfaits des TDD. Julie va tout faire pour plaire à son amoureux.

Sébastien
Sébastien

Julie
Julie

John
John

 

II-B-5. La secrétaire (Vanessa)

Vanessa ne joue pas un rôle important dans l'histoire. Elle ne fait même pas partie du projet. Elle incarne l'élément perturbateur : ses passages dans le bureau font chuter dramatiquement le niveau général de concentration et la productivité de l'équipe. Il faut préciser que Vanessa est charmante.

Vanessa
Vanessa, la secrétaire

II-B-6. Le testeur (Bernard)

Arrivant en bout de chaine, lors de la phase de qualification, Bernard s'assure que le logiciel livré est conforme au cahier des charges dont Claire lui a envoyé une copie. Si tout est bon, il appose son cachet sur le bon de livraison, mais sinon il répond par un refus franc au chef de projet.

Bernard
Bernard, le testeur

III. Action

L'histoire commence lorsque Claire (la cliente) envoie le cahier des charges de « la boutique du Chien-Copain », qu'elle vient d'écrire, à Michel (le chef de projet). Ce dernier en prend rapidement connaissance puis transmet le document à Sébastien, Julie et John (les développeurs) ainsi qu'à Laurent (l'architecte) pour obtenir leurs remarques.

III-A. Les Post-It

Après une prompte analyse, l'équipe se réunit pour définir un jeu de Post-It, relatif aux fonctionnalités décrites dans le cahier des charges. En effet, Michel (le chef de projet) a choisi d'appliquer « 3T » lors du développement du projet (cf. les conversations en annexes) et souhaite travailler avec les outils les plus simples (i.e. les Post-It), ce qui aura un avantage plus tard lors des « Sprints Scrum ».

III-A-1. Les Post-It généraux (jaunes)

À la sortie de la réunion, Michel repart avec 72 Post-It jaunes représentant les demandes identifiées dans le cahier des charges. Parmi ces Post-It, on retrouve les Post-It, portant les références « RG023 » et "RG024, constituant le sous-ensemble de l'application auquel cet article va se limiter : la génération d'un mot de passe (RG023) et son cryptage (RG024).

Les numéros des Post-It n'ont pas d'importance. Dans le cas présent, ils indiquent que vingt-deux autres Post-It ont été écrits avant, sans rien indiquer sur d'éventuels successeurs. L'équipe a simplement numéroté les Post-It par ordre d'arrivée.

Pour identifier ces deux Post-It, l'équipe est partie du cahier des charges. Un des chapitres indiquait que « le système permettra de générer un nouveau mot de passe et que ce dernier devra être crypté pour des raisons évidentes de sécurité ». L'équipe a décomposé ce paragraphe en deux besoins distincts, ce qui a donc conduit à la création des deux Post-It.

Les deux Post-It qui nous intéressent sont les suivants :

RG023

[Post-It RG023]
Le système peut générer un mot de passe.

RG024

[Post-It RG024]
Le système peut crypter un mot de passe.

III-A-2. Les Post-It détaillés (bleus)

Les Post-It généraux (jaunes) ne suffisent évidemment pas pour développer l'application, car il subsiste de nombreuses questions. Michel (le chef de projet) organise donc une réunion avec Claire (la cliente) et son équipe. Une série de questions a été transmise quelques jours en avance à Claire et des Post-It bleus, correspondant aux réponses attendues, ont été préremplis en laissant des vides pour les informations manquantes.

Les Post-It bleus, ainsi définis et liés aux précédents Post-It jaunes, sont les suivants :

RG023.1

[Post-It RG023.1]
Le mot de passe généré sera composé de 8 digits.
Exemple a : RESULT football
Exemple b : RESULT voitures

RG023.2

[Post-It RG023.2]
Le mot de passe généré sera composé des 26 lettres de l'alphabet, en majuscules et/ou en minuscules, et des chiffres de 0 à 9.

Exemple a :
RESULT abcd1234

Exemple b :
RESULT Hello012

RG024.1

[Post-It RG024.1]
Les mots de passe seront cryptés à l'aide de l'algorithme MD5.

Exemple a :
PARAM password = « football »
RESULT « 37b4e2d82900d5e94b8da524fbeb33c0 »

Exemple b :
PARAM password = « Hello012 »
RESULT « 00dd4826e068dad5be5e95ef692f62e6 »

III-A-3. Les Post-It techniques (orange)

En plus des Post-It généraux jaunes et des Post-It détaillés bleus, l'équipe a écrit des Post-It techniques orange. Ces derniers définissent des règles techniques, qui n'intéressent pas particulièrement Claire (la cliente), relatives aux mécanismes mis en œuvre au sein de l'application. Plus concrètement, les Post-It techniques (orange) concernent des points spécifiques liés à Java, ou à la base de données, ou au réseau, etc.

Le Post-It orange ainsi créé est le suivant :

RG024.2

[Post-It RG024.2]
On ne peut pas crypter un mot de passe vide. Si on essaie, ça doit lancer une erreur.

Exemple a :
PARAM password = ""
RESULT IllegalArgumentException

Exemple b :
PARAM password = null
RESULT IllegalArgumentException


Note : ce Post-It est orange vif, même si ça ne se voit pas bien à l'écran.

III-A-4. Le cahier des charges modifié

Lorsque tous les Post-It sont écrits, John (le développeur) les prend en photos avec son « iPhone » et les sauvegarde sur le réseau, dans un dossier réservé au projet de la boutique.

Une fois que tous les Post-It sont écrits, et présentés sous forme de tableau comme dans cet article (cf. ci-dessus), il devient très simple de les intégrer (reporter) dans le cahier des charges. Les Post-It ne seront utilisés qu'en guise de support de travail facile à manipuler.

Bien entendu, si on ne se limite pas au sous-ensemble de fonctionnalités de génération de mot de passe et de cryptage, il faut créer de nombreux Post-It. Il faut donc mettre à jour le cahier des charges de manière conséquente.

Pour finir, l'équipe agrafe les Post-It bleus et orange aux Post-It jaunes. Cela permet de les avoir facilement à portée de main. Bien entendu, chaque développeur peut consulter le cahier des charges, mis à jour, sur le réseau.

III-B. Premier temps (T1) : écriture des interfaces

Chaque membre de l'équipe choisit un (ou plusieurs) Post-It à traiter sur le « dashboard ». Dans le cadre de cet article, l'illustration va se limiter aux Post-It présentés ci-dessus. Disons que Julie prend le Post-It « RG023 » et que Sébastien prend le Post-It « RG024 ». Quant à John, il s'occupe d'un Post-It qui n'est pas présenté dans cet article.

Dashboard
Dashboard

Conformément aux pratiques de « Green Soft », chaque développeur colle une gommette, à sa couleur, sur le Post-It dont il a pris possession.

RG023

[Post-It RG023]
Le système peut générer un mot de passe.

Julie (Julie)

RG024

[Post-It RG024]
Le système peut crypter un mot de passe.

Sébastien (Sébastien)

Pour commencer, Julie crée l'interface « PasswordGenerator » correspondant au Post-It « RG023 » et y ajoute la méthode « generate() ». Elle documente son code en recopiant les numéros de Post-It. L'opération ne dure que quelques minutes.

Interface du générateur de mot de passe, par Julie
Sélectionnez
package fr.chiencopain.boutique.service.credentials;

/**
 * Outil de generation de mot de passe.
 * 
 * REGLE RG023
 * 
 * @author Julie
 * 
 */
public interface PasswordGenerator {

    /**
     * Genere un mot de passe.
     * 
     * REGLE RG023
     * 
     * @return
     */
    String generate();
}

Pour bien faire, Julie crée aussi la classe « DefaultPasswordGenerator » qui servira d'implémentation pour le service qu'elle vient de définir.

Implémentation (par défaut) vide du générateur de mot de passe, par Julie
Sélectionnez
package fr.chiencopain.boutique.service.credentials;

/**
 * Outil de generation de mot de passe.
 * 
 * REGLE RG023, RG023.1, RG023.2
 * 
 * @author Julie
 * 
 */
public class DefaultPasswordGenerator implements PasswordGenerator {

    /**
     * REGLE RG023, RG023.1, RG023.2
     * 
     * {@inheritDoc}
     */
    public String generate() {
        // TODO Cette methode n'est pas encore developpee.
        throw new UnsupportedOperationException("Cette methode n'est pas encore developpee.");
    }
}

Julie crée la classe « DefaultPasswordGenerator » de sorte qu'elle compile mais elle ne remplit pas les méthodes.

Finalement, Julie indique sur le Post-It que sa partie est réalisée. Pour simplifier le travail de la personne qui prendra le relais (cf. plus bas), Julie ajoute quelques remarques au verso des Post-It.

RG023

[Post-It RG023] RECTO
Le système peut générer un mot de passe.

Julie (Julie) OK, le 19/09/2011

RG023

[Post-It RG023] VERSO
(I) PasswordGenerator
+ generate


Note : ce Post-It est jaune, même si ça ne se voit pas bien à l'écran.

RG023.1

[Post-It RG023.1] VERSO
(C) DefaultPasswordGenerator
T1 : 19/09/2011

RG023.2

[Post-It RG023.2] VERSO
T1 : 19/09/2011

Le Post-It peut retourner dans le « sprint backlog » (la colonne de gauche du « dashboard »).

De son côté, Sébastien réalise un travail, équivalent à celui de Julie, pour le Post-It « RG024 ». Il commence par créer l'interface « Encryptor ».

Interface du cryptage, par Sébastien
Sélectionnez
package fr.chiencopain.boutique.util.encryption;

/**
 * Outil de cryptage.
 * 
 * REGLE RG024
 * 
 * @author Sebastien
 * 
 */
public interface Encryptor {

    /**
     * Crypte le message passe en parametre. <br/>
     * 
     * REGLE RG024
     * 
     * @param message
     * @return
     */
    String encrypt(String message);
}

Ensuite il crée l'implémentation vide « MD5Encryptor » qui recevra le code pour le cryptage MD5.

Implémentation (MD5) vide du cryptage, par Sébastien
Sélectionnez
package fr.chiencopain.boutique.util.encryption;

/**
 * Outil de cryptage.
 * 
 * REGLE RG024, RG024.1
 * 
 * @author Sebastien
 * 
 */
public class MD5Encryptor implements Encryptor {

    /**
     * REGLE RG024, RG024.1
     * 
     * {@inheritDoc}
     */
    public String encrypt(String message) {
        // TODO Cette methode n'est pas encore developpee.
        throw new UnsupportedOperationException("Cette methode n'est pas encore developpee.");
    }
}

Puis, comme Julie, il met à jour ses Post-It en indiquant son avancement.

RG024

[Post-It RG024] RECTO
Le système peut crypter un mot de passe.

Sébastien (Sébastien) OK le 19/09/2011

RG024

[Post-It RG024] VERSO
(I) Encryptor
+ encrypt()
30 minutes

RG024.1

[Post-It RG024.1] VERSO
(C) MD5Encryptor
T1 : 19/09/2011
5 secondes

RG024.2

[Post-It RG024.2] VERSO
T1 : 19/09/2011

III-C. Premier reporting

À partir du code source ainsi écrit, ne comportant pour l'instant que des interfaces, on peut générer un peu de documentation, et notamment des rapports.

Dans la configuration du projet Maven (cf. pom.xml en annexes), j'ai inclus plusieurs plugins spécialisés dans le reporting. Deux d'entre eux vont immédiatement servir à Michel (le chef de projet) bien que peu d'éléments aient été réalisés.

D'abord le plugin « Tag list » permet de répertorier toutes les références aux règles dans le code ainsi que les travaux (programmés) restant à faire à ce stade.

Image non disponible
Tag list (cliquer pour agrandir)

Ensuite, le plugin « Cobertura » mesure la couverture du code (c'est-à-dire la quantité de tests). À ce stade, les résultats indiquent en toute logique un score de zéro.

Image non disponible
Cobertura (cliquer pour agrandir)
Image non disponible
Cobertura (cliquer pour agrandir)
Image non disponible
Cobertura (cliquer pour agrandir)

Note : Ces données peuvent être consultées tout au long du projet. Il n'est pas nécessaire d'attendre que les phases successives de « 3T » soient terminées, d'autant que plusieurs Post-It, dans des phases différentes, peuvent être traités simultanément, comme le laisse deviner le « dashboard » suivant.

Dashboard en cours d'utilisation
Dashboard en cours d'utilisation

III-D. Deuxième temps (« T2 ») : écriture des tests

Maintenant que plusieurs Post-It ont franchi le cap de « T1 » (c'est-à-dire le premier temps), les développeurs qui piochent dans le « sprint backlog » peuvent choisir entre des Post-It « vierges » et des Post-It à faire évoluer vers « T2 ». Bien évidemment, c'est ce second choix que va illustrer cet article.

Disons que Julie prend en charge l'écriture des tests pour les Post-It « RG024.x » et que John s'occupe de « RG023.x ». De son côté, Sébastien travaille sur d'autres Post-It, non présentés dans cet article, ou alors il est en RTT, ou encore il prend une pause. Bref il fait autre chose.

Bien que ce ne soit pas prohibé dans « 3T », il vaut mieux que les développeurs ne travaillent pas sur deux temps consécutifs d'un même Post-It. Plus concrètement, si Julie écrit l'interface d'un Post-It (i.e. « T1 ») alors c'est mieux si elle ne s'occupe pas de la rédaction des tests (i.e. « T2 »).

Pour commencer, comme lors de « T1 » et toujours en accord avec les habitudes chez « Green Soft », les développeurs apposent des gommettes à leurs couleurs sur les Post-It qu'ils prennent en charge.

RG023

[Post-It RG023] RECTO
Le système peut générer un mot de passe.

Julie (Julie) OK, le 19/09/2011

John (John)

RG024

[Post-It RG024] RECTO
Le système peut crypter un mot de passe.

Sébastien (Sébastien) OK le 19/09/2011

Julie (Julie)

John prend donc en charge les Post-It « RG023.x » pour lesquels il doit écrire les tests unitaires. Globalement, il suffit de se concentrer sur les deux Post-It bleus « RG023.1 » et « RG023.2 ».

Tests de DefaultPasswordGenerator (RG023)
Sélectionnez
package fr.chiencopain.boutique.service.credentials;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.junit.Before;
import org.junit.Test;

/**
 * Tests de DefaultPasswordGenerator.
 * 
 * REGLE RG023, RG023.1, RG023.2
 * 
 * @author John
 * 
 */
public class DefaultPasswordGeneratorTest {
    /**
     * PasswordGenerator
     */
    PasswordGenerator passwordGenerator;

    /**
     * DefaultPasswordGenerator
     */
    @Before
    public void doBefore() {
        passwordGenerator = new DefaultPasswordGenerator();
    }

    /**
     * Le mot de passe genere sera compose de 8 digits. <br/>
     * 
     * REGLE RG023.1 <br/>
     * 
     * RESULT : length = 8 <br/>
     * 
     * Exemple a : football <br/>
     * Exemple b : voitures
     */
    @Test
    public void testGenerate_RG023_1() {
        // Param
        final int tailleAttendue = 8;

        // Appel
        final String password = passwordGenerator.generate();

        // Tests
        assertNotNull(password);
        assertEquals(tailleAttendue, password.length());
    }

    /**
     * Le mot de passe genere sera compose des 26 lettres de l'alphabet, en
     * majuscules et/ou en minuscules, et des chiffres de 0 à 9. <br/>
     * 
     * REGLE RG023.2 <br/>
     * 
     * Exemple a : abcd1234 <br/>
     * Exemple b : Hello012
     */
    @Test
    public void testGenerate_RG023_2() {

        final String lettresAutoriseesRegex = "[a-zA-Z0-9]+";

        // Appel
        final String password = passwordGenerator.generate();

        // Tests
        assertNotNull(password);
        assertTrue(verifyRegex(lettresAutoriseesRegex, password));

    }

    /**
     * Verifie si le message "match" la regex.
     * 
     * @param regex
     * @param message
     * @return true si ca match, false sinon.
     */
    private boolean verifyRegex(String regex, String message) {

        final Pattern pattern = Pattern.compile(regex);
        final Matcher matcher = pattern.matcher(message);

        return matcher.matches();
    }
}

Lorsqu'on écrit des tests, il est recommandé de suivre toujours le même formalisme pour faciliter la lecture. Dans le cadre de « 3T » il est plus particulièrement conseillé de suivre la méthode « triple A » ou AAA, de l'anglais « Arrange-Act-Assert » (traduction personnelle : « Préparer-Agir-Tester »), et à propos de laquelle on peut lire quelques lignes sur le Web à l'adresse http://www.arrangeactassert.com/why-and-what-is-arrange-act-assert/ ou encore sur http://c2.com/cgi/wiki?ArrangeActAssert et surtout sur le blog de William C. Wake.

Lorsqu'il lance les tests JUnit depuis Eclipse, John constate qu'ils sont tous rouges, ce qui est tout à fait normal ; c'est le résultat attendu.

Tests (rouges) de RG023
Tests (rouges) de RG023

John n'a plus qu'à indiquer son avancement et/ou ses remarques sur les Post-It, puis les remettre dans le « sprint backlog ».

RG023

[Post-It RG023] RECTO
Le système peut générer un mot de passe.

Julie (Julie) OK, le 19/09/2011

John (John) OK, le 21/09/2011

RG023

[Post-It RG023] VERSO
(I) PasswordGenerator
+ generate

Tests dans DefaultPasswordGenerator [Test]


Note : ce Post-It est jaune, même si ça ne se voit pas bien à l'écran.

RG023.1

[Post-It RG023.1] VERSO
(C) DefaultPasswordGenerator
T1 : 19/09/2011

T2 : 21/09/2011
1 test

RG023.2

[Post-It RG023.2] VERSO
T1 : 19/09/2011

T2 : 21/09/2011
1 test

De son côté, Julie écrit les tests pour les règles « RG024.x », c'est-à-dire le Post-It bleu « RG024.1 » et le Post-It orange « RG024.2 ». C'est relativement rapide puisqu'il suffit, là encore, de recopier les Post-It.

Tests de MD5Encryptor (RG024)
Sélectionnez
package fr.chiencopain.boutique.util.encryption;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;

import org.junit.Before;
import org.junit.Test;

/**
 * Tests de MD5Encryptor : Le systeme peut crypter un mot de passe.
 * 
 * REGLE RG024, RG024.1, RG024.2
 * 
 * @author Julie
 * 
 */
public class MD5EncryptorTest {

    /**
     * Encryptor
     */
    private Encryptor encryptor;

    /**
     * MD5Encryptor
     */
    @Before
    public void doBefore() {
        encryptor = new MD5Encryptor();
    }

    /**
     * Les mots de passe seront cryptes à l'aide de l'algorithme MD5. <br/>
     * 
     * REGLE RG024.1-a <br/>
     * 
     * PARAM password = "football" <br/>
     * RESULT "37b4e2d82900d5e94b8da524fbeb33c0"
     */
    @Test
    public void testEncrypt_RG024_1a() {
        // PARAM
        final String password = "football";
        final String passwordCrypteAttendu = "37b4e2d82900d5e94b8da524fbeb33c0";

        // Appel
        doTestEncrypt(password, passwordCrypteAttendu);
    }

    /**
     * Les mots de passe seront cryptes à l'aide de l'algorithme MD5. <br/>
     * 
     * REGLE RG024.1-b <br/>
     * 
     * PARAM password = "Hello012" <br/>
     * RESULT "00dd4826e068dad5be5e95ef692f62e6"
     */
    @Test
    public void testEncrypt_RG024_1b() {
        // PARAM
        final String password = "Hello012";
        final String passwordCrypteAttendu = "00dd4826e068dad5be5e95ef692f62e6";

        // Appel
        doTestEncrypt(password, passwordCrypteAttendu);
    }

    /**
     * On ne peut pas crypter un mot de passe vide. Si on essaie, ça doit lancer
     * une erreur. <br/>
     * 
     * REGLE RG024.2-a <br/>
     * 
     * PARAM password = "" <br/>
     * RESULT IllegalArgumentException
     */
    @Test(expected = IllegalArgumentException.class)
    public void testEncrypt_RG024_2a() {
        // PARAM
        final String password = "";
        final String passwordCrypteAttendu = "...";

        // Appel
        doTestEncrypt(password, passwordCrypteAttendu);
    }

    /**
     * On ne peut pas crypter un mot de passe vide. Si on essaie, ça doit lancer
     * une erreur. <br/>
     * 
     * REGLE RG024.2-b <br/>
     * 
     * PARAM password = null <br/>
     * RESULT IllegalArgumentException
     */
    @Test(expected = IllegalArgumentException.class)
    public void testEncrypt_RG024_2b() {
        // PARAM
        final String password = null;
        final String passwordCrypteAttendu = "...";

        // Appel
        doTestEncrypt(password, passwordCrypteAttendu);
    }

    /**
     * REGLE RG024.x
     */
    private void doTestEncrypt(String password, String passwordCrypteAttendu) {

        // Appel
        final String passwordCrypte = encryptor.encrypt(password);

        // Tests
        assertNotNull(passwordCrypte);
        assertEquals(passwordCrypteAttendu, passwordCrypte);
    }

}

Comme John, Julie constate que ses tests passent tous au rouge lorsqu'elle lance JUnit depuis Eclipse.

Tests (rouges) de RG024
Tests (rouges) de RG024

À son tour, Julie met également à jour ses Post-It.

RG024

[Post-It RG024] RECTO
Le système peut crypter un mot de passe.

Sébastien (Sébastien) OK le 19/09/2011

Julie (Julie) OK le 20/09/2011

RG024

[Post-It RG024] VERSO
(I) Encryptor
+ encrypt()
30 minutes

(C) MD5EncryptorTest
RG024.1 : 2 tests
RG024.2 : 2 tests

RG024.1

[Post-It RG024.1] VERSO
(C) MD5Encryptor
T1 : 19/09/2011
5 secondes

T2 : 20/09/2011
2 tests

RG024.2

[Post-It RG024.2] VERSO
T1 : 19/09/2011

T2 : 20/09/2011
2 tests

III-E. Deuxième reporting

Durant le « sprint », Michel (le chef de projet) consulte régulièrement les métriques du projet. Chez « Green Soft », l'outil d'intégration continue est « Hudson ». Il est configuré pour compiler l'application, à l'aide de Maven, dix minutes après chaque « commit » dans gestionnaire de sources Subversion (SVN). Hudson est également réglé de sorte qu'il génère la documentation (reporting inclus) tous les soirs. Ainsi Michel peut prendre connaissance de l'avancement du projet chaque matin.

L'intervalle de dix minutes avant de lancer le « build » Maven permet aux développeurs de corriger des petites inattentions ou des oublis de fichier par exemple.

Romain Linsolas nous propose un très bon article à propos de « L'intégration Continue avec Hudson » sur le site de developpez.com à l'adresse : https://linsolas.developpez.com/articles/hudson/Intégration Continue avec Hudson

Hudson est un produit d'Oracle (qui a acheté Sun). Le site d'Hudson est visible à l'adresse : http://hudson-ci.org/Hudson

Hudson (builds en cours)
Hudson (builds en cours)
Hudson (plugin Eclipse)
Hudson (plugin Eclipse)

Pour commencer, Michel voit que la liste des tags a évolué. Les références, déjà indiquées dans les interfaces, ont été reportées dans les classes de test.

Tag list
Tag list (cliquer pour agrandir)

Il constate ensuite que la couverture de code, qui était de zéro pour cent en « T1 », s'est améliorée. Dans l'exemple, Cobertura donne une note de 100 %, ce qui est excellent.

Cobertura
Cobertura

Un score de 100 % est rarement atteint. Peu d'équipes ont les moyens d'y arriver sur des projets complexes. Une des forces de « 3T » est d'encourager un tel objectif.

Enfin, Michel peut consulter la liste des tests ayant été écrits. Le rapport indique le nombre et l'emplacement des tests. À la fin de « T2 », tous les nouveaux tests doivent échouer (i.e. être rouges). Ce n'est qu'à la fin de « T3 » qu'ils seront verts.

Surefire (JUnit)
Surefire (JUnit)

Comme aucun nouveau « vrai code » n'a été écrit, les anciens tests ne doivent pas changer de couleur.

III-F. Troisième temps (« T3 ») : écriture du vrai code

Une fois de plus, et pour la dernière fois, les développeurs piochent des Post-It dans le « sprint backlog ». Bien entendu, l'illustration va se faire sur les Post-It « RG023 » et « RG024 ». Disons que Julie s'occupe des règles « RG023.x » et que John choisit « RG024.x ». Sébastien, quant à lui, est encore en vacances ou s'occupe d'autres Post-It, etc.

RG023

[Post-It RG023] RECTO
Le système peut générer un mot de passe.

Julie (Julie) OK, le 19/09/2011

John (John) OK le 21/09/2011

Julie (Julie)

RG024

[Post-It RG024] RECTO
Le système peut crypter un mot de passe.

Sébastien (Sébastien) OK le 19/09/2011

Julie (Julie) OK le 20/09/2011

John (John)

Dans l'exemple, le Post-It « RG023 » aura été pris en charge par Julie et John uniquement. Le Post-It « RG024 » aura été traité par tous les membres de l'équipe. Julie aura donc travaillé deux fois sur « RG023 », mais sur des temps (de « 3T ») non successifs.

Julie commence donc à coder la classe « DefaultPasswordGenerator » qu'elle avait elle-même initialisée lors de « T1 ». Elle programme ses Post-It dans l'ordre. Tout d'abord, elle doit générer un mot de passe de huit caractères.

DefaultPasswordGenerator (1re version)
Sélectionnez
package fr.chiencopain.boutique.service.credentials;

import java.util.Random;

/**
 * Outil de generation de mot de passe.
 * 
 * REGLE RG023, RG023.1, RG023.2
 * 
 * @author Julie (T1 et T3)
 * 
 */
public class DefaultPasswordGenerator implements PasswordGenerator {

    /**
     * REGLE RG023, RG023.1, RG023.2
     * 
     * {@inheritDoc}
     */
    public String generate() {

        final StringBuilder sb = new StringBuilder();

        // REGLE RG023.1
        for (int i = 0; i < 8; i++) {
            final char digit = '\0';
            sb.append(digit);
        }

        return sb.toString();
    }

}

Contente d'elle, Julie lance une première batterie de tests. Elle constate que la règle « RG023.1 » a correctement passé le test. Elle peut donc passer à la suite (i.e. la règle « RG023.2 ») qui reste rouge.

JUnit
JUnit (un des tests reste rouge)

Julie aime tester au fur et à mesure. Certains développeurs préfèrent tout programmer d'un coup et, donc, tout tester d'un coup. Ce n'est pas le cas de Julie. Dans le cadre de « 3T », il est recommandé de laisser les tests guider les développements, et donc de tester au fur et à mesure.

Maintenant que le générateur produit un mot de passe de huit digits, Julie doit faire en sorte que les caractères soient choisis parmi les 26 lettres de l'alphabet et/ou les chiffres.

DefaultPasswordGenerator (2e version)
Sélectionnez
/**
 * Outil de generation de mot de passe.
 * 
 * REGLE RG023, RG023.1, RG023.2
 * 
 * @author Julie (T1 et T3)
 * 
 */
public class DefaultPasswordGenerator implements PasswordGenerator {

    /**
     * Caracteres autorises.
     * 
     * REGLE RG023.2
     */
    private static final String CARACTERES_AUTORISES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    /**
     * REGLE RG023, RG023.1, RG023.2
     * 
     * {@inheritDoc}
     */
    public String generate() {

        final StringBuilder sb = new StringBuilder();

        // REGLE RG023.1
        for (int i = 0; i < 8; i++) {
            // REGLE RG023.2
            final char digit = generateOneDigit();
            sb.append(digit);
        }

        return sb.toString();
    }

    /**
     * Selection un caractere au hasard dans la liste des caracteres autorises.
     * 
     * REGLE RG023.2
     * 
     * @return un caractere au hasard.
     */
    private char generateOneDigit() {
        final Random random = new Random();
        final int position = random.nextInt(CARACTERES_AUTORISES.length());
        final char digit = CARACTERES_AUTORISES.charAt(position);
        return digit;
    }
}

Une fois satisfaite, Julie relance les tests. Elle constate, comme prévu, que tous les tests passent au vert.

JUnit
JUnit (tous les tests passent au vert)

Julie peut donc, en toute bonne foi, se dire qu'elle a terminé la fonctionnalité. Par acquit de conscience elle lance aussi les tests des fonctionnalités pouvant être impactées par son code (ici, il n'y en a aucune) pour vérifier qu'elle n'a pas engendré de régression.

Chez « Green Soft », le logiciel Hudson est configuré pour lancer régulièrement l'ensemble des tests de l'application, pour vérifier complètement la non-régression, ce qui peut prendre du temps. Les développeurs peuvent donc se concentrer sur leurs périmètres.

Si tout est bon, elle peut mettre à jour ses Post-It. Cette fois, contrairement à « T1 » et « T2 », le Post-It ne retourne pas dans le « sprint backlog », mais va dans la colonne des fonctionnalités terminées.

RG023

[Post-It RG023] RECTO
Le système peut générer un mot de passe.

Julie (Julie) OK, le 19/09/2011

John (John) OK le 21/09/2011

Julie (Julie) OK le 21/09/2011

RG023

[Post-It RG023] VERSO
(I) PasswordGenerator
+ generate

Tests dans DefaultPasswordGenerator [Test]


Note : ce Post-It est jaune, même si ça ne se voit pas bien à l'écran.

RG023.1

[Post-It RG023.1] VERSO
(C) DefaultPasswordGenerator
T1 : 19/09/2011

T2 : 21/09/2011
1 test

T3 : 21/09/2011

RG023.2

[Post-It RG023.2] VERSO
T1 : 19/09/2011

T2 : 21/09/2011
1 test

T3 : 21/09/2011

De son côté, John travaille sur « RG024.x ». Contrairement à Julie, qui traite les Post-It par ordre numérique, John préfère commencer par les Post-It techniques (i.e. orange). Il commence donc son développement par le Post-It « RG024.2 ».

MD5Encryptor (1re version)
Sélectionnez
package fr.chiencopain.boutique.util.encryption;

/**
 * Outil de cryptage.
 * 
 * REGLE RG024, RG024.1
 * 
 * @author Sebastien, John
 * 
 */
public class MD5Encryptor implements Encryptor {

    /**
     * REGLE RG024, RG024.1
     * 
     * {@inheritDoc}
     */
    public String encrypt(String message) {
        
        // REGLE RG024.2
        if(message == null || message.length() == 0) {
            throw new IllegalArgumentException("Le param 'message' ne peut pas etre vide.");
        }
        
        // TODO Cette methode n'est pas encore developpee. 
        throw new UnsupportedOperationException("Cette methode n'est pas encore developpee.");
    }

}

John lance ses tests. Il constate que les tests « RG024.2-x » passent au vert, mais que les autres tests, pour lesquels il n'a encore rien programmé, restent rouges.

JUnit
JUnit (deux tests restent rouges)

John passe à la suite : le cryptage du mot de passe en MD5.

Un petit rebondissement se produit dans cette histoire ; Vanessa (la secrétaire sexy) entre dans le bureau des développeurs. Elle vient discuter (cf. conversations en annexes) des derniers ragots avec Julie. Automatiquement, la concentration de John baisse dramatiquement et cela va se ressentir sur la qualité de son code.

Vanessa

Image non disponible

Julie

MD5Encryptor (2e version)
Sélectionnez
/**
 * Outil de cryptage.
 * 
 * REGLE RG024, RG024.1
 * 
 * @author Sebastien, John
 * 
 */
public class MD5Encryptor implements Encryptor {

    /**
     * MD5
     * 
     * REGLE RG024.1
     */
    public final static String ALGO_MD5 = "MD55";

    /**
     * REGLE RG024, RG024.1
     * 
     * {@inheritDoc}
     */
    public String encrypt(String message) {

        // REGLE RG024.2
        if (message == null || message.length() == 0) {
            throw new IllegalArgumentException("Le param 'message' ne peut pas etre vide.");
        }

        // REGLE RG024.1
        try {
            final byte[] uniqueKey = message.getBytes();
            final byte[] hash = MessageDigest.getInstance(ALGO_MD5).digest(uniqueKey);

            final StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hash.length; i++) {
                String hex = Integer.toHexString(hash[i]);
                if (hex.length() == 1) {
                    sb.append('0');
                    sb.append(hex.charAt(hex.length() - 1));
                } else {
                    sb.append(hex.substring(hex.length() - 2));
                }
            }
            final String encrypt = sb.toString();
            return encrypt;
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

}

Quand John relance ses tests, il découvre qu'ils sont restés rouges.

JUnit
JUnit (deux tests restent encore rouges)

Que se passe-t-il ? John, perturbé par la présence de la charmante Vanessa, a fait une faute de frappe. Il a ainsi écrit « MD55 » alors qu'il voulait utiliser l'algorithme « MD5 » avec un seul « 5 ». L'erreur est simple à corriger, mais elle serait très probablement passée inaperçue s'il n'y avait pas eu de test pour la détecter.

Une petite correction, d'une demi- seconde, devrait suffire.

MD5Encryptor (3e version)
Sélectionnez
    /**
     * MD5
     * 
     * REGLE RG024.1
     */
    public final static String ALGO_MD5 = "MD5";

Cette fois, les tests deviennent bien (tous) verts. Il s'en est fallu de peu…

JUnit
JUnit (tous les tests passent au vert)

John lance les autres tests de l'application pour s'assurer qu'il n'a pas, lui non plus, apporté de régression. Comme tout est bon, il peut légitimement penser que sa fonctionnalité est prête. Il ne reste plus qu'à compléter ses Post-It.

RG024

[Post-It RG024] RECTO
Le système peut crypter un mot de passe.

Sébastien (Sébastien) OK le 19/09/2011

Julie (Julie) OK le 20/09/2011

John (John) OK le 21/09/2011

RG024

[Post-It RG024] VERSO
(I) Encryptor
+ encrypt()
30 minutes

(C) MD5EncryptorTest
RG024.1 : 2 tests
RG024.2 : 2 tests

Attention : NoSuchAlgorithmException a gérer

RG024.1

[Post-It RG024.1] VERSO
(C) MD5Encryptor
T1 : 19/09/2011
5 secondes

T2 : 20/09/2011
2 tests

T3 : 21/09/2011

RG024.2

[Post-It RG024.2] VERSO
T1 : 19/09/2011

T2 : 20/09/2011
2 tests

T3 : 21/09/2011

Je me suis attaché à employer une écriture et un style différents pour chaque développeur intervenant sur les Post-It. Pour les débuts de « 3T » sur la boutique, chacun se crée ses propres habitudes.

III-G. Troisième reporting

Comme lors des temps précédents, Michel peut consulter la liste des tags du code. Il constate que la liste des choses à faire s'est vidée. Il peut en profiter pour vérifier le bon report des numéros de règle dans le code.

Tag list
Tag list

Michel peut également consulter le rapport Surefire (JUnit) qui indique désormais que tous les tests sont OK. À ce stade, il est en droit de penser, puisqu'il a utilisé « 3T » que le développement de l'application est terminé.

Surefire (JUnit) : tous les tests sont OK
Surefire (JUnit) : tous les tests sont OK

En vérifiant le rapport Cobertura, Michel (le chef de projet) constate que le niveau de couverture du code a légèrement baissé.

Cobertura
Cobertura

Immédiatement, un peu inquiet, il clique pour voir les détails. Le rapport lui indique très précisément les points faibles dans le code.

Cobertura (détails)
Cobertura (détails)

Ici, ce n'est pas difficile de revenir à 100 %. Michel demandera simplement à John de compléter les tests, voire de créer un Post-It technique (orange) additionnel, dès qu'il aura un peu de temps.

Globalement, Michel est très content, car le développement des fonctionnalités a été hyper rapide. En effet, les développeurs ont pu s'appuyer sur les Post-It la plupart du temps et avancer par itérations, en construisant l'application sur des bases de plus en plus solides. Les tests ont permis aux membres de l'équipe d'avoir une confiance élevée dans les codes produits. Les reportings ont permis à Michel de suivre l'avancement des travaux en fournissant des métriques fiables que Michel peut remonter à sa hiérarchie et au client.

III-H. Inspection surprise

Laurent (l'architecte) profite d'un moment de flottement, en fin de « sprint », pour improviser une revue de code. En temps normal, les développeurs s'autoorganisent déjà dans ce sens, mais Laurent souhaite constater/vérifier lui-même l'impact de « 3T » sur la qualité du code. Il a quelques craintes à propos de la méthode. Tout semble si simple qu'il a peur que les développeurs se soient laissé entrainer par cette apparente simplicité pour « bâcler » le travail. En outre, il sait que Michel (le chef de projet) se sent principalement concerné par les tests et la qualité visible de l'application.

Chez « Green Soft », on utilise les logiciels « Check style » et « PMD » pour mesurer la qualité du code. Combinés avec une revue manuelle du code, ces outils fournissent de bonnes indications. Pour sa part, Laurent travaille principalement avec « Check style » directement depuis Eclipse. Michel, quant à lui, préfère consulter les rapports édités depuis Maven.

Laurent s'installe donc avec les développeurs, à tour de rôle, et active les vérifications « Check style » lorsqu'elles n'étaient pas déjà activées. En tout, il ne trouve qu'une vingtaine de petites violations aux règles « Check Style » de « Green Soft » (mots clés dans le mauvais ordre, paramètres non déclarés finaux, Javadoc incomplète, etc.), qu'il fait corriger directement par les développeurs concernés. C'est plutôt pas mal.

Le code source, dans le fichier Zip, est déjà corrigé.

Globalement, Laurent n'a rien à dire, à part les détails indiqués ci-dessus, car le principe d'écriture de « 3T » conduit naturellement à écrire du code propre, à proscrire les duplications, à avoir une forte couverture de test, à séparer les responsabilités, à respecter les standards, etc. En fait, puisque « 3T » apporte un processus simple où les étapes sont décomposées et guident les développeurs, ces derniers peuvent se concentrer sur la qualité de leurs travaux, ce qui n'est pas toujours le cas dans des projets classiques.

III-I. La qualification

Arrivant en fin de projet (et/ou de « sprint »), Bernard (le responsable de la Qualif) doit s'assurer que le produit fabriqué est conforme aux attentes du client. Il a reçu les versions successives du cahier des charges et se tient prêt à vérifier les livrables.

Par habitude, Bernard sait qu'il va rejeter la première (et même les suivantes) tentative de livraison après seulement quelques heures de test. En effet, il trouve toujours quelque chose à redire sur la conformité du produit. Pour se faire, il teste scrupuleusement tous les points spécifiés dans le cahier des charges.

Le plus dur de son travail consiste à mettre en place les jeux de test nécessaires, à dérouler lesdits tests, puis à consigner les anomalies dans Mantis (l'outil de « bug tracking » open source utilisé par « Green Soft »). D'ailleurs, Bernard en a ras le bol de créer des fiches Mantis à longueur de journée. Il aimerait bien se concentrer sur la mise en place de tests puissants, allant bien au-delà des besoins exprimés, et qui contribueraient à asseoir la réputation de « Green Soft ».

Quelle va donc être sa surprise lorsque, après avoir lancé ses batteries de tests, Bernard ne détecte aucune anomalie ? Ça n'est jamais arrivé jusque-là. Il croit d'abord à une mauvaise manipulation et relance entièrement sa série de tests. Mais là encore, rien à signaler ! Interloqué, il appose son tampon de validation et envoie un email de félicitations au chef de projet (Michel) et au DSI.

En réalité, lorsque « 3T » est appliqué sur un projet, son principe premier veut que les développements soient réalisés en partant des tests, eux-mêmes écrits à partir du cahier des charges. Or il est probable que les tests écrits par l'équipe de développement soient très proches de ceux de Bernard.

IV. Évolutions

Nous avons constaté que « 3T » est efficace immédiatement, mais « 3T » est également intéressante sur le long terme. Pour le comprendre, revenons à « la Boutique du Chien-Copain », un an plus tard.

Les choses ont bien changé depuis la mise en production de « la Boutique du Chien-Copain ». Environ un an s'est écoulé. L'enseigne a ouvert quinze nouveaux magasins en France, en Suisse et en Belgique. La société canine devient une multinationale. Et les projets sont nombreux. D'ailleurs, l'un des premiers projets que « Chien-Copain » veut lancer est une évolution (dans la suite on parlera de « v2 ») de la boutique en ligne. La collaboration avec « Green Soft » ayant été fructueuse, c'est naturellement à Michel (le chef de projet de la boutique chez « Green Soft ») que cette nouvelle version a été directement confiée.

De son côté, la Web Agency « Green Soft » s'est également agrandie. Elle a remporté de nombreux contrats en France et en Europe. L'utilisation de « 3T » initiée sur « la Boutique du Chien-Copain » est maintenant une pratique de plus en plus orchestrée, au moins sur les nouveaux projets.

IV-A. Les nouveaux Post-It

Claire (la cliente) a une liste de nouvelles demandes qu'elle souhaite voir développées en « v2 ». Dans le cadre de cet article, on ne va évidemment illustrer que les besoins liés à la génération et le cryptage de mot de passe, pour faire suite aux chapitres précédents.

Tout d'abord, Claire souhaite que les mots de passe générés soient de taille variable. Pour des raisons de sécurité, elle veut également que les mots de passe générés ne soient plus uniquement composés de lettres et/ou de chiffres, mais qu'ils contiennent aussi des caractères de ponctuation. Enfin, Claire a découvert, en écoutant l'excellent podcast « Techno IT »podcast Techno IT que le cryptage « SHA-1 » a remplacé le « MD5 ». Bien qu'elle n'ait pas compris les raisons de ce changement, elle souhaite que « Green Soft » l'accompagne dans ce sens.

De nouveau, Michel (le chef de projet) réunit son équipe pour analyser le nouveau cahier des charges. Après discussion avec Claire, l'équipe part sur les Post-It suivants. Les Post-It « 023.3 », « 023.4 » et « 024.3 » sont nouveaux.

RG023.3

[Post-It RG023.3]
Remplace RG023.1
Le mot de passe généré sera composé de 6 à 10 digits.

Exemples :
a : « pommes »
b : « ananas »
c : "cocacola

Nouveau

RG023.4

[Post-It RG023.4]
Remplace RG023.2
Le mot de passe généré sera composé des 26 lettres en majuscules et/ou en minuscules, des chiffres et des ponctuations simples ou doubles.


Exemple :
a : « pommes »
b : « abc1234 »
c : « Maison! »
d : « coca-cola; »

Nouveau

RG024.2

[Post-It RG024.2]
On ne peut pas crypter un mot de passe vide. Si on essaie, ça doit lancer une erreur.

Exemple a :
PARAM password = ""
RESULT IllegalArgumentException

Exemple b :
PARAM password = null
RESULT IllegalArgumentException

RG024.3

[Post-It RG024.3]
Remplace RG024.1
Le système doit crypter les mots de passe en SHA-1.

Nouveau

De manière générale, quand le sujet d'un Post-It évolue, on peut soit mettre à jour le Post-It, en en gérant les versions successives, soit « annuler » le Post-It et le remplacer par un nouveau. C'est donc ce second choix qui a été retenu chez « Green Soft ». Les Post-It « 023.1 », « 023.2 » et « 024.1 » sont marqués comme annulés.

RG023.1 ANNULE

[Post-It RG023.1]
Le mot de passe généré sera composé de 8 digits.
Exemple a : RESULT football
Exemple b : RESULT voitures

ANNULE

RG023.2 ANNULE

[Post-It RG023.2]
Le mot de passe généré sera composé des 26 lettres de l'alphabet, en majuscules et/ou en minuscules, et des chiffres de 0 à 9.

Exemple a :
RESULT abcd1234

Exemple b :
RESULT Hello012

ANNULE

RG024.1 ANNULE

[Post-It RG024.1]
Les mots de passe seront cryptés à l'aide de l'algorithme MD5.

Exemple a :
PARAM password = « football »
RESULT « 37b4e2d82900d5e94b8da524fbeb33c0 »

Exemple b :
PARAM password = « Hello012 »
RESULT « 00dd4826e068dad5be5e95ef692f62e6 »

ANNULE

Les Post-It (fonctionnels) jaunes de la « v1 », quant à eux, sont simplement remplacés par de nouveaux Post-It jaunes pour la « v2 ». Les nouveaux Post-It sont prêts à suivre un nouveau « processus 3T » couplé à Scrum.

RG023 v2

[Post-It RG023] v2
Le système doit générer un mot de passe.

Nouveau

RG024 v2

[Post-It RG024] v2
Le système doit crypter le mot de passe.

Nouveau

IV-B. Évolution de l'équipe

En une année, l'équipe de développement a beaucoup évolué. Tout d'abord, Laurent (l'architecte) et Julie se sont mariés. Une grande fête a été organisée dans les bureaux de « Green Soft » pour célébrer l'événement. Une chose en entrainant une autre, Julie est désormais en congé maternité et ne participera donc pas au développement des évolutions de « la boutique du Chien-Copain ». John (le développeur barbu) travaille désormais en Belgique, en tant que « team leader » sur un projet du gouvernement dont « Green Soft » a remporté l'appel d'offres.

De l'équipe initiale, il ne reste donc plus que Sébastien. Ce dernier a rapidement été rejoint par William et Nathalie, puis par Luc un peu plus tard.

William
William

Luc
Luc

Nathalie
Nathalie

Sébastien
Sébastien

William et Nathalie reviennent d'un projet Web, pris en charge par « Green Soft », chez un opérateur de télécom, où ils travaillaient en « pair programming » dans le cadre d'une méthodologie « XP ». Luc, quant à lui, a été remercié d'un autre projet dans lequel il s'ennuyait. Michel, avec qui il était resté en contact, lui a proposé de rejoindre l'équipe pour découvrir les bienfaits de « 3T » et redécouvrir des bases de travail motivantes.

Un point intéressant des TDD, est la capacité de prise en main rapide que la méthode offre aux nouveaux développeurs du projet. En effet, puisque les tests sont documentés et guident le code source des programmes, il suffit de repartir des tests pour comprendre ce que fait le programme. Les développeurs peuvent donc s'appuyer sur leurs compétences techniques pour s'immerger dans le fonctionnel de l'application. En outre, puisque « 3T » s'inspire directement du cahier des charges, la démarche est d'autant plus simplifiée.

Dans l'histoire, Sébastien est le seul développeur restant à posséder une connaissance à la fois technique et fonctionnelle de « la Boutique du Chien-Copain ». Son rôle ne va pas être de transmettre cette connaissance, mais de guider les nouveaux membres de l'équipe à travers les TDD et « 3T » pour qu'ils accèdent progressivement au même niveau de compétence (cf. conversations en annexes).

IV-C. Les trois temps

Sans surprise, puisque c'est l'objet de cet article, les développements de la « v2 » de la boutique en ligne vont suivre les trois temps de « 3T ».

Cette partie ne sera pas illustrée à chaque étape à l'aide de Post-It scannés. Cela occupe trop de place et prend (en toute franchise) trop de temps dans le logiciel d'imagerie. Seuls les scans des Post-It finals (c'est-à-dire après « T3 ») seront présentés plus bas.

Les phases d'évolution de l'application diffèrent légèrement des phases de création dans la mesure où il faut revenir (c'est-à-dire annuler,modifier) sur l'existant pour l'adapter aux nouvelles demandes.

IV-C-1. Les interfaces (T1)

Dans un premier temps, disons que Sébastien s'occupe des interfaces de génération et de cryptage des mots de passe. Il n'y a pas grand-chose à faire. Plus exactement, il n'y a rien (ou presque) du tout à faire au niveau des interfaces Java puisque les contrats de service n'ont pas changé.

PasswordGenerator (aucun changement)
Sélectionnez
/**
 * Outil de generation de mot de passe.
 * 
 * REGLE RG023
 * 
 * @author Julie
 * 
 */
public interface PasswordGenerator {

    /**
     * Genere un mot de passe.
     * 
     * REGLE RG023
     * 
     * @return Un mot de passe genere.
     */
    String generate();
}
Encryptor (aucun changement)
Sélectionnez
/**
 * Outil de cryptage.
 * 
 * REGLE RG024
 * 
 * @author Sebastien
 * 
 */
public interface Encryptor {
    /**
     * Crypte le message passe en parametre. <br/>
     * 
     * REGLE RG024
     * 
     * @param message
     *            Le message a crypter.
     * @return une version cryptee du message.
     */
    String encrypt(String message);
}

En revanche, on peut créer une classe vide spécifique pour l'implémentation du cryptage SHA-1 et une classe vide pour la nouvelle implémentation du générateur de mot de passe. À cette étape, Sébastien ne doit pas modifier le code plus que ça.

AdvancePasswordGenerator (vide)
Sélectionnez
package fr.chiencopain.boutique.service.credentials;

/**
 * Outil de generation de mot de passe.
 * 
 * REGLE RG023
 * 
 * @author Sébastien
 * 
 */
public class AdvancePasswordGenerator implements PasswordGenerator {
    /**
     * REGLE RG023
     * 
     * {@inheritDoc}
     */
    public final String generate() {
        // TODO Cette methode n'est pas encore developpee.
        throw new UnsupportedOperationException("Cette methode n'est pas encore developpee.");
    }
}
Sha1Encryptor (vide)
Sélectionnez
package fr.chiencopain.boutique.util.encryption;

/**
 * Outil de cryptage.
 * 
 * REGLE RG024
 * 
 * @author Sebastien
 * 
 */
public class Sha1Encryptor implements Encryptor {

    /**
     * REGLE RG024
     * 
     * {@inheritDoc}
     */
    public final String encrypt(final String message) {
        // TODO Cette methode n'est pas encore developpee.
        throw new UnsupportedOperationException("Cette methode n'est pas encore developpee.");
    }
}

IV-C-2. Les tests (T2)

Durant ce deuxième temps, disons que Nathalie et William vont écrire, en « pair programming », les tests de « RG023 » et que Luc va s'occuper de « RG024 ».

Lorsqu'on écrit du code pour la première fois, c'est relativement simple puisqu'il suffit de partir de zéro. On est libre d'aller dans la direction qui nous intéresse sans contrainte. En revanche, lorsqu'on fait évoluer du code, comme c'est le cas ici, par ajout de nouvelles règles, il faut s'intégrer dans l'existant. L'objectif est de s'inspirer de ce que les développeurs précédents ont réalisé, tout en complétant/modifiant le code. Dans le cas présent, en ce qui concerne les tests unitaires et l'addition de nouveaux tests qui ressemblent aux anciens, cela se traduit par un peu de réorganisation, et notamment par de la factorisation et de l'héritage.

Conformément aux Post-It, certains tests sont annulés. Ils devraient donc être supprimés du code. Toutefois, dans la mesure où de nouvelles classes ont été prévues pour accueillir les évolutions, et que ces dernières (programmées ainsi) ne sont pas incompatibles avec l'existant, l'équipe décide de tout conserver. En outre, cela m'arrange pour l'illustration de cet article.

Nathalie et William vont donc créer une classe de test abstraite et réorganiser la classe existante pour qu'elle utilise la nouvelle classe.

AbstractPasswordGeneratorTest
Sélectionnez
package fr.chiencopain.boutique.service.credentials;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 
 * @author Nathalie et William
 * 
 */
public abstract class AbstractPasswordGeneratorTest {
    /**
     * Verifie si le message "match" la regex.
     * 
     * @param regex
     *            la regex de controle.
     * @param message
     *            le message a valider.
     * @return true si ca match, false sinon.
     */
    protected final boolean verifyRegex(final String regex, final String message) {

        final Pattern pattern = Pattern.compile(regex);
        final Matcher matcher = pattern.matcher(message);

        return matcher.matches();
    }
}
DefaultPasswordGeneratorTest (modifiée)
Sélectionnez
/**
 * Tests de DefaultPasswordGenerator.
 * 
 * REGLE RG023, RG023.1, RG023.2
 * 
 * @author John, puis Nathalie et William (v2)
 * 
 */
public class DefaultPasswordGeneratorTest extends AbstractPasswordGeneratorTest {
    /**
     * PasswordGenerator
     */
    private PasswordGenerator passwordGenerator;

    /**
     * DefaultPasswordGenerator
     */
    @Before
    public final void doBefore() {
        passwordGenerator = new DefaultPasswordGenerator();
    }

    /**
     * Le mot de passe genere sera compose de 8 digits. <br/>
     * 
     * REGLE RG023.1 <br/>
     * 
     * RESULT : length = 8 <br/>
     * 
     * Exemple a : football <br/>
     * Exemple b : voitures
     */
    @Test
    public final void testGenerate_RG023_1() {
        // Param
        final int tailleAttendue = 8;

        // Appel
        final String password = passwordGenerator.generate();

        // Tests
        assertNotNull(password);
        assertEquals(tailleAttendue, password.length());
    }

    /**
     * Le mot de passe genere sera compose des 26 lettres de l'alphabet, en
     * majuscules et/ou en minuscules, et des chiffres de 0 à 9. <br/>
     * 
     * REGLE RG023.2 <br/>
     * 
     * Exemple a : abcd1234 <br/>
     * Exemple b : Hello012
     */
    @Test
    public final void testGenerate_RG023_2() {

        final String lettresAutoriseesRegex = "[a-zA-Z0-9]+";

        // Appel
        final String password = passwordGenerator.generate();

        // Tests
        assertNotNull(password);
        assertTrue(verifyRegex(lettresAutoriseesRegex, password));

    }
}
AdvancePasswordGeneratorTest
Sélectionnez
package fr.chiencopain.boutique.service.credentials;

import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;

/**
 * Tests de AdvancePasswordGenerator.
 * 
 * REGLE RG023, RG023.3, RG023.4
 * 
 * @author Nathalie et William
 * 
 */
public class AdvancePasswordGeneratorTest extends AbstractPasswordGeneratorTest {
    /**
     * PasswordGenerator
     */
    private PasswordGenerator passwordGenerator;

    /**
     * AdvancePasswordGenerator
     */
    @Before
    public final void doBefore() {
        passwordGenerator = new AdvancePasswordGenerator();
    }

    /**
     * Le mot de passe genere sera compose de 6 à 10 digits. <br/>
     * 
     * REGLE RG023.3 <br/>
     * Test en boucle a cause du comportement aleatoire. <br/>
     * 
     * PARAM nbDigitMin = 6 <br/>
     * PARAM nbDigitMax = 10
     * 
     */
    @Test
    public final void testGenerate_RG023_3_boucle() {
        // Param
        final int nbDigitMin = 6;
        final int nbDigitMax = 10;

        // Boucle car on cherche a tester plein de cas.
        for (int i = 0; i < 1000; i++) {
            // Appel
            final String password = passwordGenerator.generate();

            // Tests
            assertNotNull(password);
            final int passwordLength = password.length();
            assertTrue(nbDigitMin <= passwordLength);
            assertTrue(passwordLength <= nbDigitMax);
        }
    }

    /**
     * Le mot de passe genere sera compose des 26 lettres en majuscules et/ou en
     * minuscules, des chiffres et des ponctuations simples ou doubles. <br/>
     * 
     * REGLE RG023.2 <br/>
     * 
     * Exemple a : abcd1234 <br/>
     * Exemple b : Hello012
     */
    @Test
    public final void testGenerate_RG023_4() {

        // Param
        // regex : [a-zA-Z0-9,.'";:!?\-]+
        final String lettresAutoriseesRegex = "[a-zA-Z0-9,.'\";:!?\\-]+"; 

        // Appel
        final String password = passwordGenerator.generate();

        // Tests
        assertNotNull(password);
        assertTrue(verifyRegex(lettresAutoriseesRegex, password));

    }
}

Durant le développement, Nathalie et William doivent vérifier qu'ils ne modifient pas le comportement des anciens tests. Bien entendu, après « T2 », les nouveaux tests doivent échouer (i.e. être rouges).

Luc va adopter la même stratégie pour les nouveaux tests dont il s'occupe.

AbstractEncryptorTest
Sélectionnez
package fr.chiencopain.boutique.util.encryption;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;

import org.junit.Test;

/**
 * REGLE RG024.2
 
 * @author Luc
 * 
 */
public abstract class AbstractEncryptorTest {
    /**
     * Encryptor
     */
    protected Encryptor encryptor;

    /**
     * REGLE RG024.x
     * 
     * @param password
     *            Le mot de passe en clair.
     * @param passwordCrypteAttendu
     *            Le mot de passe crypte attendu.
     */
    protected final void doTestEncrypt(final String password, final String passwordCrypteAttendu) {

        // Appel
        final String passwordCrypte = encryptor.encrypt(password);

        // Tests
        assertNotNull(passwordCrypte);
        assertEquals(passwordCrypteAttendu, passwordCrypte);
    }

    /**
     * On ne peut pas crypter un mot de passe vide. Si on essaie, ça doit lancer
     * une erreur. <br/>
     * 
     * REGLE RG024.2-a <br/>
     * 
     * PARAM password = "" <br/>
     * RESULT IllegalArgumentException
     */
    @Test(expected = IllegalArgumentException.class)
    public final void testEncrypt_RG024_2a() {
        // PARAM
        final String password = "";
        final String passwordCrypteAttendu = "...";

        // Appel
        doTestEncrypt(password, passwordCrypteAttendu);
    }

    /**
     * On ne peut pas crypter un mot de passe vide. Si on essaie, ça doit lancer
     * une erreur. <br/>
     * 
     * REGLE RG024.2-b <br/>
     * 
     * PARAM password = null <br/>
     * RESULT IllegalArgumentException
     */
    @Test(expected = IllegalArgumentException.class)
    public final void testEncrypt_RG024_2b() {
        // PARAM
        final String password = null;
        final String passwordCrypteAttendu = "...";

        // Appel
        doTestEncrypt(password, passwordCrypteAttendu);
    }
}
MD5EncryptorTest (modifiée)
Sélectionnez
/**
 * Tests de MD5Encryptor : Le systeme peut crypter un mot de passe.
 * 
 * REGLE RG024, RG024.1, RG024.2
 * 
 * @author Julie, puis modifiée par Luc en v2.
 * 
 */
public class MD5EncryptorTest extends AbstractEncryptorTest {

    /**
     * MD5Encryptor
     */
    @Before
    public final void doBefore() {
        encryptor = new MD5Encryptor();
    }

    /**
     * Les mots de passe seront cryptes à l'aide de l'algorithme MD5. <br/>
     * 
     * REGLE RG024.1-a <br/>
     * 
     * PARAM password = "football" <br/>
     * RESULT "37b4e2d82900d5e94b8da524fbeb33c0"
     */
    @Test
    public final void testEncrypt_RG024_1a() {
        // PARAM
        final String password = "football";
        final String passwordCrypteAttendu = "37b4e2d82900d5e94b8da524fbeb33c0";

        // Appel
        doTestEncrypt(password, passwordCrypteAttendu);
    }

    /**
     * Les mots de passe seront cryptes a l'aide de l'algorithme MD5. <br/>
     * 
     * REGLE RG024.1-b <br/>
     * 
     * PARAM password = "Hello012" <br/>
     * RESULT "00dd4826e068dad5be5e95ef692f62e6"
     */
    @Test
    public final void testEncrypt_RG024_1b() {
        // PARAM
        final String password = "Hello012";
        final String passwordCrypteAttendu = "00dd4826e068dad5be5e95ef692f62e6";

        // Appel
        doTestEncrypt(password, passwordCrypteAttendu);
    }
}
Sha1EncryptorTest
Sélectionnez
package fr.chiencopain.boutique.util.encryption;

import org.junit.Before;
import org.junit.Test;

/**
 * Tests de Sha1Encryptor : Le systeme peut crypter un mot de passe.
 * 
 * REGLE RG024, RG024.2, RG024.3
 * 
 * @author Luc
 * 
 */
public class Sha1EncryptorTest extends AbstractEncryptorTest {
    /**
     * Sha1Encryptor
     */
    @Before
    public final void doBefore() {
        encryptor = new Sha1Encryptor();
    }
    
    
    /**
     * Le système doit crypter les mots de passe en SHA-1.  <br/>
     * 
     * REGLE RG024.3 <br/>
     * 
     * PARAM password = "football" <br/>
     * RESULT "2d27b62c597ec858f6e7b54e7e58525e6a95e6d8"
     */
    @Test
    public final void testEncrypt_RG024_3() {
        // PARAM
        final String password = "football";
        final String passwordCrypteAttendu = "2d27b62c597ec858f6e7b54e7e58525e6a95e6d8";

        // Appel
        doTestEncrypt(password, passwordCrypteAttendu);
    }
}

Finalement, les anciens tests doivent rester verts et les nouveaux tests, conçus pour échouer au sens de « 3T », doivent être rouges, ce que les développeurs peuvent vérifier directement depuis Eclipse.

JUnit global
JUnit global (les nouveaux tests sont rouges)

IV-C-3. Les développements (T3)

Les Post-It arrivent désormais dans le dernier temps pour cette « v2 » et le plus gros du travail a déjà été réalisé en « v1 », un an auparavant. Les nouveaux développements vont pouvoir s'appuyer allègrement sur l'existant, en plus des tests qui vont guider l'écriture. Comme pour l'ajout de tests lors de « T2 », les nouveaux codes (en « T3 ») vont entrainer un peu de réorganisation.

Disons que Luc prend en charge le développement de « RG023 » et que Sébastien s'occupe de « RG024 ».

Luc s'inspire largement des tests, pour lesquels l'équipe a identifié un besoin de « refactoring », laissant supposer que cette action aura une réponse similaire dans le cadre du développement final. Luc crée donc une classe abstraite et adapte les anciens codes. Enfin, il code la classe qui va générer des mots de passe avec les nouvelles règles.

AbstractPasswordGenerator
Sélectionnez
package fr.chiencopain.boutique.service.credentials;

import java.util.Random;

/**
 * REGLE RG023.2
 * 
 * @author Luc
 * 
 */
public abstract class AbstractPasswordGenerator implements PasswordGenerator {

    /**
     * Selection un caractere au hasard dans la liste des caracteres autorises.
     * 
     * REGLE RG023.2
     * 
     * @param caracteresAutorises
     *            les caracteres qui sont autorises.
     * @return un caractere au hasard.
     */
    protected final char generateOneDigit(final String caracteresAutorises) {
        final Random random = new Random();
        final int position = random.nextInt(caracteresAutorises.length());
        final char digit = caracteresAutorises.charAt(position);
        return digit;
    }
}
DefaultPasswordGenerator (modifiée)
Sélectionnez
/**
 * Outil de generation de mot de passe.
 * 
 * REGLE RG023, RG023.1, RG023.2
 * 
 * @author Julie (T1 et T3), Luc en v2.
 * 
 */
public class DefaultPasswordGenerator extends AbstractPasswordGenerator implements PasswordGenerator {

    /**
     * Caracteres autorises.
     * 
     * REGLE RG023.2
     */
    private static final String CARACTERES_AUTORISES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    /**
     * REGLE RG023, RG023.1, RG023.2
     * 
     * {@inheritDoc}
     */
    public final String generate() {

        final StringBuilder sb = new StringBuilder();

        // REGLE RG023.1
        final int nombreDigit = 8;
        for (int i = 0; i < nombreDigit; i++) {
            // REGLE RG023.2
            final char digit = generateOneDigit();
            sb.append(digit);
        }

        return sb.toString();
    }

    /**
     * Selection un caractere au hasard dans la liste des caracteres autorises.
     * 
     * REGLE RG023.2
     * 
     * @return un caractere au hasard.
     */
    private char generateOneDigit() {
        return generateOneDigit(CARACTERES_AUTORISES);
    }
}
AdvancePasswordGenerator
Sélectionnez
package fr.chiencopain.boutique.service.credentials;

import java.util.Random;

/**
 * Outil de generation de mot de passe.
 * 
 * REGLE RG023
 * 
 * @author Sébastien (T1), Luc (T3)
 * 
 */
public class AdvancePasswordGenerator extends AbstractPasswordGenerator implements PasswordGenerator {
    
    /**
     * Caracteres autorises.
     * 
     * lettres : a-z et A-Z <br/>
     * chiffres : 0-9 <br/>
     * Ponctuations : ,.'";:!- (virgule, point, apostrophe, guillemet,
     * point-virgule, deux-point, point d'exclamation, point d'interrogation,
     * tiret)
     * 
     * REGLE RG023.4
     */
    private static final String CARACTERES_AUTORISES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,.'\";:!?-";

    
    /**
     * REGLE RG023, RG023.3, RG023.4
     * 
     * {@inheritDoc}
     */
    public final String generate() {
        final StringBuilder sb = new StringBuilder();
        
        
        final Random random = new Random();
        final int nb = random.nextInt(5);
        // REGLE RG023.1
        final int nombreDigit = 6 + nb;
        for (int i = 0; i < nombreDigit; i++) {
            // REGLE RG023.4
            final char digit = generateOneDigit(CARACTERES_AUTORISES);
            sb.append(digit);
        }
        
        return sb.toString();
    }
}

Pour des raisons purement techniques, Sébastien commence par ajouter des constantes (non prévues) dans l'interface. Il crée ensuite une classe abstraite pour factoriser une partie des traitements, et adapte la classe spécifique au cryptage MD5 en fonction. Il n'a plus, finalement, qu'à compléter la nouvelle classe pour SHA-1, ce qui ne prend que quelques instants.

Encryptor (modifiée)
Sélectionnez
/**
 * Outil de cryptage.
 * 
 * REGLE RG024
 * 
 * @author Sebastien
 * 
 */
public interface Encryptor {
    /**
     * MD5
     */
    String ALGO_MD5 = "MD5";
    
    /**
     * SHA-1
     */
    String ALGO_SHA1 = "SHA-1";

    /**
     * Crypte le message passe en parametre. <br/>
     * 
     * REGLE RG024
     * 
     * @param message
     *            Le message a crypter.
     * @return une version cryptee du message.
     */
    String encrypt(String message);
}
AbstractSimpleEncryptor
Sélectionnez
package fr.chiencopain.boutique.util.encryption;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Outil de cryptage.
 * 
 * REGLE RG024
 * 
 * @author Sebastien
 * 
 */
public abstract class AbstractSimpleEncryptor implements Encryptor {

    /**
     * REGLE RG024
     * 
     * {@inheritDoc}
     */
    protected final String doEncrypt(final String message, final String algo) {
        // REGLE RG024.2
        if (message == null || message.length() == 0) {
            throw new IllegalArgumentException("Le param 'message' ne peut pas etre vide.");
        }

        // REGLE RG024.1, RG024.3
        try {
            final byte[] uniqueKey = message.getBytes();
            final byte[] hash = MessageDigest.getInstance(algo).digest(uniqueKey);

            final StringBuilder sb = new StringBuilder();
            for (int i = 0; i < hash.length; i++) {
                String hex = Integer.toHexString(hash[i]);
                if (hex.length() == 1) {
                    sb.append('0');
                    sb.append(hex.charAt(hex.length() - 1));
                } else {
                    sb.append(hex.substring(hex.length() - 2));
                }
            }
            final String encrypt = sb.toString();
            return encrypt;
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }
}
MD5Encryptor (modifiée)
Sélectionnez
/**
 * Outil de cryptage.
 * 
 * REGLE RG024, RG024.1
 * 
 * @author Sebastien, John, Sebastien (v2)
 * 
 */
public class MD5Encryptor extends AbstractSimpleEncryptor implements Encryptor {

    /**
     * MD5
     * 
     * REGLE RG024.1
     */
    public static final String ALGO_CRYPTAGE = ALGO_MD5;

    /**
     * REGLE RG024, RG024.1
     * 
     * {@inheritDoc}
     */
    public final String encrypt(final String message) {

        return doEncrypt(message, ALGO_CRYPTAGE);
    }
}
Sha1Encryptor
Sélectionnez
package fr.chiencopain.boutique.util.encryption;

/**
 * Outil de cryptage.
 * 
 * REGLE RG024, RG024.2, RG024.3
 * 
 * @author Sebastien
 * 
 */
public class Sha1Encryptor extends AbstractSimpleEncryptor implements Encryptor {
    
    /**
     * SHA-1
     * 
     * REGLE RG024.3
     */
    public static final String ALGO_CRYPTAGE = ALGO_SHA1;
    
    /**
     * REGLE RG024.3
     * 
     * {@inheritDoc}
     */
    public final String encrypt(final String message) {
        
        return doEncrypt(message, ALGO_CRYPTAGE);
    }
}

Un des grands avantages de « 3T », et plus particulièrement du travail divisé en temps, est de permettre aux développeurs de se concentrer sur des petites tâches. Par conséquent, durant le troisième temps, ils peuvent consacrer de l'énergie sur du « refactoring continu » et ainsi avoir une qualité qui augmente au fur et à mesure.

Maintenant que tous les développements sont réalisés, tous les nouveaux tests doivent passer au vert. On doit bien penser à vérifier que les anciens tests, limités aux tests non annulés, continuent d'être verts.

JUnit global
JUnit global (tout est vert)

IV-C-4. Les Post-It scannés

Voici un récapitulatif final de l'ensemble des nouveaux Post-It. Il ne faut pas oublier que le Post-It orange « RG023.2 » est toujours d'actualité pour cette seconde version de la boutique.

RG023 v2

[Post-It RG023] v2
Le système doit générer un mot de passe.

Image non disponible T1 : OK le 05/07/2012

Image non disponibleImage non disponible T2 : OK le 05/07/2012

Image non disponible T3 : OK le 06/07/2012

RG023 v2 verso

[Post-It RG023] v2 VERSO

Sébastien
(I) PasswordGenerator
(C) AdvancePAsswordGenerator

Nathalie et William
(A) AbstractGeneratorTest
(C) AdvancePasswordGeneratorTest
(C) DefaultPasswordGeneratorTest

Luc
(A) AbstractPasswordGenerator
(C) DefaultPasswordGenerator
(C) AdvancePasswordGenerator

RG023.3 verso

[Post-It RG023.3] VERSO

T1 : OK le 05/07/2012 par Sébastien

T2 : OK le 05/07/2012 par Nathalie et William

T3 : OK le 06/07/2012 par Luc

RG023.4 verso

[Post-It RG023.3] VERSO

T1 : OK le 05/07/2012 par Sébastien

T2 : OK le 05/07/2012 par Nathalie et William

T3 : OK le 06/07/2012 par Luc

RG024 v2

[Post-It RG024] v2
Le système doit crypter le mot de passe.

Image non disponible T1 : OK le 05/07/2012

Image non disponible T3 : OK le 05/07/2012

Image non disponible T3 : OK le 07/07/2012

RG024 v2 verso

[Post-It RG024] v2 verso

Sébastien
(I) Encryptor
(C) Sha1Encryptor

Luc
(A) AbstractEncryptorTest
(C) Sha1EncryptorTest
(C) MD5EncryptorTest

Sebastien
(A) AbstractSimpleEncryptor
(C) MD5Encryptor
(C) Sha1Encryptor
(I) Encryptor

RG024.2 verso (v1)

[Post-It RG024.2] verso (v1)

T1 : 19/09/2011

T2 : 20/09/2011
2 tests

T3 : 21/09/2011

RG024.3 verso

[Post-It RG024.3] VERSO

T1 : OK le 05/07/2012 par Sébastien

T2 : OK le 05/07/2012 par Luc

T3 : OK le 07/07/2012 par Sébastien

À travers ce récapitulatif des Post-It de la seconde version de « la Boutique du Chien-Copain », on voit un détail que je voulais mettre en avant dans cet article et qui concerne les habitudes de mise à jour des Post-It. Comme pour les Post-It de la « v1 », j'ai utilisé une écriture différente pour chaque développeur. Pour le coup, sur cette « v2 », Sébastien est le seul à encore employer des gommettes, car Vanessa, qui est responsable des fournitures, n'a pas renouvelé le stock. En outre, on constate que Sébastien, qui est le seul rescapé de l'équipe initiale et qui a présenté « 3T » aux nouveaux arrivants, a transmis ses propres habitudes et ses propres notations à la nouvelle équipe. Je crois que c'est un point important à prendre en compte. On peut se demander comment ces habitudes auraient été transmises si Sébastien n'avait pas été seul.

IV-D. Reporting

Michel (le chef de projet) va être content en fin de projet. Les rapports fournissent des métriques excellentes. Évidemment, le rapport Surefire résumant les tests JUnit indique 100 % de réussite. Le contrat est donc rempli.

Surefire (JUnit)
Surefire (JUnit)
Tag list
Tag list

IV-E. Qualification

S'étant déjà fait surprendre l'an passé, lors de la phase de qualification de la « v1 », Bernard a préparé son affaire. Il a suivi le développement du coin de l'œil pour être prêt le jour J. Il a donc mis en place une batterie de tests conforme au cahier des charges, mais il a ajouté un ensemble de critères qualité, en accord avec Michel (le chef de projet), pour aller bien plus loin que les demandes du client. Ainsi le projet sera tiré vers le haut.

Sans grosse surprise, désormais, la qualification se passe sans encombre. Bernard ne trouve à redire que sur certains détails relatifs aux nouveaux critères avancés qu'il a ajoutés. C'est tellement négligeable, et hors périmètre, qu'il accepte la livraison sans discuter plus que ça.

V. Conclusion

Comme on l'a vu à travers cette petite fiction sur « la Boutique du Chien-Copain », un projet qui s'étale sur plusieurs années et versions, avec des équipes et des besoins qui évoluent, écrire des tests n'est pas synonyme de perte de temps. En effet, les TDD sont accusés à tort de couter cher, or, une version simplifiée des TDD, comme le propose « 3T », conduit non seulement à une forte qualité, mais également à des économies.

Les gains les plus évidents concernent les phases de recette et/ou de qualification pour lesquelles on ne connait que trop bien le coût d'une non-validation. Mais « 3T » permet également d'accélérer les développements, en les décomposant en tâches simples et cadrées, qui s'intègrent facilement avec des méthodes agiles comme Scrum. Finalement, « 3T » propose de mécaniser les développements et les tests, sans créer de surcoût, mais au contraire en diminuant les charges des projets.

Reste que « 3T » n'est qu'une proposition et ne se réclame de rien d'autre. En l'utilisant, les membres d'une équipe normalisent/formalisent ce qu'ils faisaient déjà de manière instinctive.

VI. Remerciements

Je tiens à remercier, en tant qu'auteur de ce miniroman à propos des Tests en Trois Temps (3T), toutes les personnes qui m'ont aidé et soutenu. Je pense tout d'abord à mes collègues qui subissent mes questions au quotidien, mais aussi à mes contacts et amis du web, dans le domaine de l'informatique ou non, qui m'ont fait part de leurs remarques et critiques. Bien entendu, je n'oublie pas l'équipe de developpez.com qui m'a guidé dans la rédaction de cet article et m'a aidé à le corriger et le faire évoluer, principalement sur le forum.

Plus particulièrement j'adresse mes remerciements, par ordre alphabétique, à djibril, Hing, Karyne, et keulkeul

Thierry

VII. Annexes

VII-A. Conversations

Dans cette partie de l'article, je propose plusieurs discussions fictives entre les acteurs de l'histoire pour comprendre leurs choix.

VII-A-1. Le goût de « 3T »

Michel (le chef de projet) et Laurent (l'architecte) sont à la cantine et discutent du cahier des charges de « la boutique du Chien-Copain » que Claire (la cliente) vient de leur envoyer. Laurent voudrait mettre en place un plan qualité performant et strict, mais Michel recherche une méthode plus simple.

Laurent

J'ai lu les « specs » de « Chien-Copain ». Ça a l'air sympa comme projet.

Michel

Ouais. La responsable, chez eux, est super ouverte et on travaille bien avec elle. En plus ils sont super contents du site qu'on leur a fait l'année dernière.

Laurent

Il faudrait que ça devienne un client de référence. On va leur faire une appli aux petits oignons. Tu dis aux gars de « booster » les aspects qualité. J'veux voir des tests bien faits et une couverture de code maximale. Ensuite on capitalisera dessus dans les plaquettes et sur le Wiki.
Sont bons les haricots verts ?

Michel

Bof, z'ont aucun goût. Et pour les tests, je pensais y aller doucement. La dernière fois, sur le projet Machin, quand on avait fait du TDD, ça a fini en catastrophe, avec tout le monde qui se tapait dessus. Et la fois d'avant, avec Truc, il n'y avait même pas de budget.

Laurent

Normal, le contact chez Truc, il avait des neurones en moins. Et avec Machin, c'était un petit manque d'organisation au début.

Michel

Tout de même, c'est super complexe de faire du TDD, surtout que la plupart des points ne nous servent à rien. Et quand on utilise des choses utiles, on se mélange les pinceaux et on se pose mille questions.

Laurent

C'est pas faux. Mais c'est une démarche qualité. C'est hyper important. Soit tu fais du TDD, soit t'en fais pas. On n'est plus dans la bulle.

Michel

Justement, j'ai trouvé un article intéressant sur developpez.com. Il y a un petit gars qui propose une alternative à nos méthodes. Il dit que c'est du TDD simplifié. Et dans ses exemples, ça n'a pas l'air de faire grand-chose, mais ça couvre 100 % de ce que j'ai envie de coller sur le projet.

Laurent

Faut voir. Tu m'enverras le lien.

Michel

OK, pas de soucis, dès qu'on remonte, je l'ai mis en bookmark. En plus c'est facile à lire ; ça tient sur une poignée de pages. Je crois que ça s'appelle « 3T », au pire tu le cherches sur Google.

Laurent

Au moins, ton truc là, ton « 3T », ça fait des tests ?

Michel

Oui, oui, c'est des tests. Ce qui change, c'est seulement la manière de les écrire. Quand on le lit, ça semble vraiment simple. Et question budget, c'est si bidon que c'est presque gratuit.

Laurent

Bon on verra. Déjà faut que je le lise. Mais t'as pas l'air sûr de ton coup.

Michel

C'est vrai. J'ai encore un peu de mal à voir comment on va pouvoir intégrer ça avec Scrum d'une part, et puis avec Hudson pour l'intégration continue.

Laurent

Tu peux toujours envoyer un email à l'auteur. Les mecs de developpez.com, ils ont la réputation d'être sympas et de répondre aux questions, donc profites-en.

Michel

Bonne idée ; je fais ça et je te tiens au courant.
Tu veux un café avant de remonter ?

VII-A-2. Les Post-It de « 3T » collent à Scrum

Ayant aimé l'article de présentation de « 3T » sur developpez.com, Michel souhaite échanger quelques mots et idées avec l'auteur dont il a trouvé les coordonnées.

Michel

Bonjour et merci d'accepter de répondre à mes questions sur « 3T ».

Thierry

Bonjour Michel. Tout le plaisir est pour moi.

Michel

J'ai lu votre article sur developpez.com et ça a l'air de correspondre avec ce que je recherche depuis quelque temps. En effet, je trouve que les tests sont indispensables. Toutefois je n'arrive pas à imposer une méthode comme TDD, car les équipes trouvent ça trop complexe, en particulier pour faire échouer les tests, et ma hiérarchie dit que ça coute trop cher.

Thierry

J'ai rencontré les mêmes difficultés durant mes missions. J'ai longtemps cherché un bon compromis, qui contente à la fois mes collègues, mon chef et la MOA, mais sans jamais y arriver vraiment. Quand le DSI imposait les TDD, ça devenait tellement complexe qu'on finissait par abandonner. Et à l'inverse, quand on faisait trop simple, c'était tellement « light » que ça ne servait à rien, ou alors à faire joli. Et puis un jour, en discutant avec un collègue, « 3T » m'est tombé dessus comme un éclair.

Michel

Effectivement, ça semble magique et tellement simple quand on y pense. Il suffit de faire exactement ce qui est demandé si je comprends bien. Et en fait les développeurs apportent de la plus-value avant de coder quoi que ce soit.

Thierry

Oui c'est ça. Du coup les membres de l'équipe peuvent utiliser leur tête pour de vrai et ne pas se contenter de mettre en application des compétences purement techniques, sur telle ou telle spécificité du langage Java ou de la base de données. C'est bien plus gratifiant. Le point important de « 3T », c'est le deuxième temps ; celui durant lequel on écrit les tests, or c'est dans les tests que toute l'intelligence est concentrée. Et encore, ce n'est qu'une recopie des spécifications.

Michel

Dans votre article, vous utilisez des Post-It. Est-ce que c'est obligatoire ?

Thierry

Rien n'est vraiment imposé dans « 3T », mis à part de bien travailler en trois temps. En ce qui concerne les Post-It, vous devez les voir comme un support de travail, simple et rapide. Bien entendu, vous devez faire évoluer le cahier des charges avec les Post-It que vous utilisez. Un peu de formalisme, à un moment ou un autre ne peut pas faire de mal ; vos clients n'en seront que plus satisfaits.

Michel

C'est vrai que certains clients nous envoient des cahiers des charges succincts. Justement, mon équipe va commencer un projet pour une animalerie et les spécifications sont vraiment légères.

Thierry

Je vois qu'on est sur la même longueur d'onde. Avec « 3T », c'est du gagnant-gagnant ; on travaille main dans la main avec les clients. Ça me fait penser que j'ai vu sur votre site Web que vous accordez une grande importance aux méthodes agiles, notamment à Scrum. Vous avez donc l'habitude de griffonner des Post-It. Et donc vous faites déjà une grosse partie du boulot.

Michel

Oui c'est vrai. Vu sous cet angle, franchir le pas de « 3T » a l'air encore plus facile. Du coup, si on part du principe que nos Post-It Scrum et nos Post-It « 3T » fonctionnent de pair, voire sont les mêmes, alors on peut s'en servir sur le « dashboard ». Il suffit d'ajouter des colonnes.

Thierry

Oui et non. C'est une très bonne idée d'utiliser les Post-It de « 3T » en remplacement de ceux de Scrum. Par contre il ne faut pas adapter le « dashboard ». Ce qu'il faut faire, c'est adapter les Post-It. Chaque Post-It doit traverser trois fois le « dashboard ». La première fois, c'est pour écrire les interfaces. La deuxième fois, c'est pour écrire les tests. Et enfin la troisième fois, c'est pour écrire le code. Ce sont les trois temps de « 3T ».

Michel

Ça revient au même que d'ajouter des colonnes ?

Thierry

Pas tout à fait, car lorsqu'un Post-It revient dans le « sprint backlog », tu sais la colonne de gauche dans le « dashboad », n'importe quel membre de l'équipe peut potentiellement en prendre possession. Ça signifie que, dans l'idéal, chaque temps de « 3T » peut être pris en charge par une personne différente et que le processus reste fluide.

Michel

Ah oui !… Excellent.

VII-A-3. Ragot « 3T »

Vanessa apporte des fournitures (blocs, Post-It, stylo, gommettes, agrafes, etc.) dans le bureau des développeurs et en profite pour discuter des derniers ragots avec Julie. Durant la discussion, Vanessa va demander à quoi correspondent les Post-It sur le mur.

Vanessa

Ça sert à quoi les Post-It sur le tableau ?

Julie

Ah ça… Heu… C'est notre méthode de travail. On note les tâches à faire sur des Post-It et, selon la colonne dans laquelle est le Post-It, on sait si la tâche est en attente, en cours de réalisation ou finie.

Vanessa

Ça a une importance les couleurs ? Parce que je peux commander uniquement des jaunes chez Métro si ça vous arrange.

Julie

Heu… ouais ! les couleurs et les tailles indiquent si le Post-It contient des informations d'organisation, ou fonctionnelle ou encore technique. Par exemple, les Post-It orange donnent des précisions sur des éléments super techniques qui ne sont même pas dans le cahier des charges.

Vanessa

Je crois que je comprends. Mais alors, pourquoi vous avez dessiné une colonne qui porte le titre « 3T » sur les grands Post-It jaunes, ceux sur lesquels vous avez collé des gommettes de gamin ?

Julie

Heu… Ça fait partie de la méthode. Et la colonne « 3T », heu… C'est encore autre chose. C'est un truc qu'est venu nous montrer un consultant pour nous aider à faire des tests plus efficaces, ou si tu préfères, à faire du code de meilleure qualité et plus facilement.

Vanessa

Tu parles du beau brun qui est venu la semaine dernière et qui a passé la matinée avec vous ?

Julie

Heu… Je n'irais pas jusqu'à dire qu'il est beau, mais, effectivement, c'est bien lui.

Vanessa

Arrête, il est trop mignon. En tout cas j'en ferais bien mon quatre heures.

Julie

Heu… Comme tu veux. Disons que ce n'est pas mon style.

Vanessa

Et donc, c'est bien ce qu'il vous a présenté, le consultant ?

Julie

Heu… Je ne sais pas trop. Apparemment Laurent (l'architecte, fiancé de Julie) trouve que c'est tellement simple que c'est génial. Perso je ne vois pas très bien où ça conduit, mais j'ai l'impression que ça nous aide un peu. Ça a le mérite de formaliser ce qu'on faisait déjà avant instinctivement.

Vanessa

Je crois que je comprends. Donc c'est un peu du pipeau.

Julie

Heu… Je ne sais pas encore. On doit essayer durant plusieurs semaines pour voir ce que ça donne. En tous cas, les autres ont l'air de bien aimer.

Vanessa

À propos de bien aimer, tu as vu comment le mec de la compta reluquait mon décolleté à la cantine ?…

VII-A-4. Le choc de « 3T »

Le développement de la seconde version de la boutique est sur le point de démarrer. Sébastien a été rejoint par Nathalie et William, à qui il va présenter « 3T » à sa manière. Luc, quant à lui n'est pas encore arrivé.

Sébastien

Bon les bleus. On va se poser en salle de réunion pendant une petite heure pour que je vous présente « 3T ».

Nathalie

Oui chef !…

William

Dis donc Man, tu te la racontes.

Sébastien

Alors, comme je disais, Michel voudrait que je vous explique comment « 3T » fonctionne.

Nathalie

C'est quoi d'abord ton « 3T machin » ?

Sébastien

Bonne question ; en fait c'est même « TTT » et c'est le sigle de « Tests en Trois Temps ». C'est grosso modo une version simplifiée des TDD.

William

Well. C'est une méthode officielle avec un web site ?

Sébastien

Je ne crois pas que ce soit vraiment quelque chose de bien cadré. C'est Michel qui avait trouvé un article sur developpez.com et qui a fait venir un consultant pour nous expliquer en quoi ça consiste.

Nathalie

Bon d'accord. Donc c'est comme les TDD, mais en plus simple.

William

Les TDD, c'est bien. On connait. On sait faire. Mais c'est very long.

Sébastien

Avec « 3T », ça devient un peu moins long et, surtout, c'est plus simple.

Nathalie

C'est quoi la différence avec les TDD ?

Sébastien

Heu, en fait je ne connais pas très bien les TDD donc je ne peux pas vraiment citer avec précision les différences, mais je peux déjà dire que ça simplifie la manière d'écrire les tests et de les faire planter au départ.

Nathalie

Tu parles. C'est toi le « stroumph » tout bleu.

Sébastien

OK, je vous explique et vous me direz au fur et à mesure les différences que vous notez. Ça vous va ?

William

Well, très bien.

Sébastien

D'abord, avec « 3T » on travaille toujours en trois temps, d'où le nom de la méthode. D'abord on doit écrire des interfaces pour les fonctionnalités demandées.

Nathalie

Il y a déjà une différence avec les TDD là, parce que normalement on commence par les tests.

Sébastien

Oui, ça j'avais vu. Mais en fait, dans le premier temps, on ne fait que recopier les spécifications en les traduisant sous forme d'interface. C'est pas vraiment du code, mais plutôt de la reformulation. D'ailleurs ça va super vite si on part du fichier Word pour écrire la Javadoc.

William

Well. Les interfaces c'est rapide.

Sébastien

Ensuite on écrit les tests, comme avec les TDD, sauf que pour les tests, on doit aussi recopier les spécs. L'idée est de ne pas se poser de question. Et chaque test doit avoir un numéro d'identification qui ramène au cahier des charges. Et inversement pour chaque point du cahier des charges, il doit y avoir un test.

Nathalie

D'accord, c'est une sorte de bijection.

William

Et s'il y a un trou dans les spécifications ?

Sébastien

En fait, s'il y a un trou dans les spécs, il faut aller voir Michel et demander à combler le trou. C'est les spécs qui font foi.

Nathalie

D'accord, mais c'est comme avec les TDD.

Sébastien

Pas tout à fait parce qu'avec les TDD, tu passes beaucoup de temps à te demander quoi tester. Du coup, tu testes souvent trop de choses ou pas assez. Et puis surtout tu perds beaucoup de temps à faire des plans sur la comète. Le principe de « 3T », c'est que tout est déjà écrit et qu'il suffit de recopier.

William

Well, c'est comme une notice des Lego.

Sébastien

Je crois qu'on peut dire ça.

William

Good…

Nathalie

Et pour faire échouer les tests, on fait comment ? Parce qu'avec les TDD, c'est hyper compliqué quand tu veux faire ça bien. Je suppose que ta super méthode propose quelque chose…

Sébastien

Exactement. Avec « 3T » on simplifie les échecs. On part du principe que le code n'est pas développé et que ça renvoie un « null » ou une exception. Et quand tu testes, c'est tout rouge.

Nathalie

C'est pas du tout comme les TDD alors. On ne peut pas vraiment dire qu'on fait échouer le test initial.

Sébastien

Oui je sais. Mais comme tu l'as toi-même remarqué, on écrit une bijection entre les tests et les spécs. Et « 3T » dit qu'un petit échec rapide, mais avec une couverture forte, c'est mieux que des vraies erreurs qui prennent du temps et que, de toute manière, tu vas effacer dans dix minutes.

Nathalie

C'est sûr que si tu fais comme ça, tu gagnes un sacré paquet de temps. Sans jeu de mots, hi hi hi.

Sébastien

Et puis il y a le troisième et dernier temps durant lequel on va écrire le code à proprement dit. Et là ça marche comme les TDD. Tu utilises les tests, de manière incrémentale, pour savoir quoi développer.

William

Well, je comprends. Donc, avec « 3T », quand tous les tests passent au vert dans Eclipse, ça veut dire que tout est développé, car il y a la bijection avec les spécifications.

Sébastien

En théorie, c'est ça. C'est ce que j'allais dire. Dans la pratique, c'est presque ça. Dans la « v1 » de la boutique, il n'y a qu'une ou deux fois où ça ne s'est pas vérifié, mais c'était parce qu'on avait mal identifié une problématique.

Nathalie

D'accord, donc, effectivement ça doit aller très vite. C'est beaucoup plus light que les TDD, mais ça reprend une partie des points importants.

VII-A-5. Motivation

Michel (le chef de projet) a découvert que Luc, un consultant en mission chez un client, est assez mal noté et que sa mission va rapidement prendre fin. Michel, qui avait déjà travaillé avec Luc et qui était très satisfait de ses prestations, est relativement surpris. Puisque Luc va revenir au siège de « Green Soft », il voudrait lui proposer de rejoindre ses équipes. Mais avant cela, Michel passe un coup de téléphone à Luc pour comprendre ce qui se passe.

Luc

Allo !…

Michel

Bonjour Luc. C'est Michel. Tu te souviens de moi.

Luc

Salut Michel. Ça faisait longtemps. Comment vas-tu ?

Michel

Ça va très bien. Beaucoup de travail, mais j'arrive à gérer. Et toi, ça roule ? J'ai cru comprendre que ça n'allait pas fort.

Luc

Effectivement, ma mission chez « Banque Machin » va s'arrêter.

Michel

C'est bien ce que j'avais entendu dire. Que se passe-t-il ?

Luc

Bof rien, justement. Je prends de plus en plus de pauses clope pour me changer les idées et m'échapper de ce projet pourri.

Michel

Mais tu ne fumais pas avant ?

Luc

Ouais, mais comme je te dis, le projet est vraiment pourri.

Michel

Ça avait l'air bien pourtant chez « Machin ».

Luc

Bah ouais. Au début c'était pas mal. Mais très rapidement, les mecs de la MOA ont commencé à nous demander n'importe quoi. Et notre chef dit oui à tout. Du coup on fait tout dans l'urgence et ça devient le bordel.

Michel

Vous aviez une démarche qualité pourtant en janvier…

Luc

Ouais, bah… Il y a longtemps que c'est enterré. Ça sentait le sapin dès le départ de toute manière. Au début les chefs ont joué le jeu, mais, à la mi-mars, ils ont décrété que ça coutait trop cher et que le métier ne payait pas pour ça.

Michel

C'est étrange. Le commercial avait l'air de dire que « Banque Machin » était convertie.

Luc

Les choses changent. Et maintenant, on continue de faire des tests, de la « qualif » et tout plein de trucs, mais après coup. Là on en est à écrire des tests sur du code qui a déjà été livré en production. Tu vois le genre.

Michel

Oui. C'est des tests de complaisance.

Luc

Les clients sont tous les mêmes. Au début ils veulent se démarquer et produire des outils de qualité, mais à la fin c'est toujours la même bouse. Je me demande si je ne vais pas changer de métier, tellement ça me déprime.

Michel

Attends justement j'ai un truc à te proposer. L'année dernière on a lancé un site de vente en ligne pour « Chien-Copain », tu sais le fabricant d'accessoires pour les animaux. Et là on vient de commencer la « v2 ». Ça te dirait de nous rejoindre dans l'équipe, vu que tu reviens au siège de « Green » ?

Luc

Bof, au siège ou en régie chez le client, ça revient au même.

Michel

Attends parce que ce n'est pas tout. Depuis un peu plus d'un an, on applique une nouvelle méthode qui simplifie les TDD et qui permet de faire de la qualité pour de vrai. La boutique était justement un projet pilote. Ça a super bien marché et on continue sur la lancée.

Luc

Ouais, c'est ça, jusqu'au jour où un mec de la compta dit que ça coute trop cher…

Michel

Justement non. Un des avantages de la méthode, ça s'appelle « 3T » au fait, c'est qu'elle rend les « dév » plus rapides. Du coup tout le monde est content. Pour l'équipe, c'est l'occasion de créer des produits avec une forte qualité. Pour le client ça coute moins cher et c'est plus rapidement prêt. Et pour la compta, ça permet de dégager plus de marges (plus rapide, moins de bogues) et de faire des volumes supplémentaires. Et pour la DSI, ça relève le niveau de la société. Du coup tout le monde est à fond ici.

Luc

Ouais, bon, je veux bien essayer pour voir. Je commence quand ?

Michel

Ça y est ! Tu as commencé quand tu as décroché le téléphone. C'est magique. C'est comme suivre le lapin blanc.

VII-B. Maven et Eclipse

Pour écrire cet article, j'ai créé un nouveau projet Maven 3 en écrivant le fichier pom (proposé ci-dessous) dans le dossier « boutique-chien-copain ».

pom.xml
Sélectionnez
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>fr.chien-copain</groupId>
    <artifactId>boutique</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>Boutique du Chien-Copain</name>
    <description>Projet de la Boutique du Chien-Copain</description>
    <url>http://www.thierryler.com</url>

    <licenses>
        <license>
            <name>Copyright ©1995-2011 thierryler.com et Copyright ©2011 Developpez.com</name>
            <comments>Les sources présentés sur cette page sont [..] Cette page est déposée à la SACD.</comments>
        </license>
    </licenses>

    <developers>
        <!-- Michel -->
        <developer>
            <name>Michel</name>
            <roles>
                <role>Chef de projet</role>
            </roles>
            <organization>Green Soft</organization>
        </developer>

        <!-- Laurent -->
        <developer>
            <name>Laurent</name>
            <roles>
                <role>Architecte</role>
                <role>Developpeur</role>
            </roles>
            <organization>Green Soft</organization>
        </developer>

        <!-- Julie -->
        <developer>
            <name>Julie</name>
            <roles>
                <role>Developpeur</role>
            </roles>
            <organization>Green Soft</organization>
        </developer>

        <!-- Sébastien -->
        <developer>
            <name>Sébastien</name>
            <roles>
                <role>Developpeur</role>
            </roles>
            <organization>Green Soft</organization>
        </developer>

        <!-- John -->
        <developer>
            <name>John</name>
            <roles>
                <role>Developpeur</role>
            </roles>
            <organization>Green Soft</organization>
        </developer>
    </developers>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven-compiler-plugin.version>2.3.1</maven-compiler-plugin.version>
        <junit.version>4.8.1</junit.version>
        <maven-site-plugin.version>3.0-beta-3</maven-site-plugin.version>
        <maven-javadoc-plugin.version>2.8</maven-javadoc-plugin.version>
        <maven-checkstyle-plugin.version>2.7</maven-checkstyle-plugin.version>
        <maven-pmd-plugin.version>2.5</maven-pmd-plugin.version>
        <maven-jxr-plugin.version>2.3</maven-jxr-plugin.version>
        <taglist-maven-plugin.version>2.4</taglist-maven-plugin.version>
        <cobertura-maven-plugin.version>2.5.1</cobertura-maven-plugin.version>
        <maven-surefire-plugin.version>2.9</maven-surefire-plugin.version>
        <maven-surefire-report-plugin>2.9</maven-surefire-report-plugin>
        <log4j.version>1.2.13</log4j.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- JUnit -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>

            <!-- JAX WS RT -->
            <dependency>
                <groupId>com.sun.xml.ws</groupId>
                <artifactId>jaxws-rt</artifactId>
                <version>${jaxws-rt.version}</version>
            </dependency>

            <!-- log4j -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>Boutique du Chien-Copain</finalName>

        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin.version}</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-site-plugin</artifactId>
                <version>${maven-site-plugin.version}</version>
            </plugin>
            
            <!-- Surefire -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven-surefire-plugin.version}</version>
            </plugin>
        </plugins>
    </build>


    <reporting>
        <plugins>
            <!-- javadoc -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>${maven-javadoc-plugin.version}</version>
            </plugin>

            <!-- checkstyle -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-checkstyle-plugin</artifactId>
                <version>${maven-checkstyle-plugin.version}</version>
                <!-- <configuration> <configLocation>checkstyle.xml</configLocation> 
                    </configuration> -->
            </plugin>
            
            <!-- PMD -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-pmd-plugin</artifactId>
                <version>${maven-pmd-plugin.version}</version>
            </plugin>

            <!-- JXR : pour lier les sources -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jxr-plugin</artifactId>
                <version>${maven-jxr-plugin.version}</version>
            </plugin>

            <!-- taglist -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>taglist-maven-plugin</artifactId>
                <version>${taglist-maven-plugin.version}</version>
                <configuration>
                    <tagListOptions>
                        <tagClasses>
                            <tagClass>
                                <displayName>Todo Work</displayName>
                                <tags>
                                    <tag>
                                        <matchString>todo</matchString>
                                        <matchType>ignoreCase</matchType>
                                    </tag>
                                    <tag>
                                        <matchString>FIXME</matchString>
                                        <matchType>exact</matchType>
                                    </tag>
                                </tags>
                            </tagClass>
                            <tagClass>
                                <displayName>Regles</displayName>
                                <tags>
                                    <tag>
                                        <matchString>REGLE</matchString>
                                        <matchType>ignoreCase</matchType>
                                    </tag>
                                </tags>
                            </tagClass>
                        </tagClasses>
                    </tagListOptions>
                </configuration>
            </plugin>

            <!-- Cobertura : couverture de code -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>cobertura-maven-plugin</artifactId>
                <version>${cobertura-maven-plugin.version}</version>
            </plugin>
            
            <!-- Surefire (junit) -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-report-plugin</artifactId>
                <version>${maven-surefire-report-plugin}</version>
            </plugin>

        </plugins>
    </reporting>
</project>

Dans ce fichier « pom.xml », j'utilise un ensemble de plugins qui me semblent constituer l'arsenal minimum à mettre en œuvre sur un projet.

Ensuite, en ligne de commande, dans le répertoire « boutique-chien-copain », j'ai fabriqué la structure du projet Eclipse à l'aide de la commande Maven suivante.

Création du projet
Sélectionnez
mvn clean install eclipse:eclipse

Si on vient tout juste d'installer Maven, celui-ci va commencer par rapatrier un nombre assez important de bibliothèques, dont JUnit, nécessaires à son fonctionnement. Donc, il est important d'avoir une connexion Internet active à ce moment-là.

La commande crée en particulier le dossier « target » et les fichiers Eclipse « .classpath » et « .project ». Il ne reste plus qu'à importer le projet dans Eclipse (via le menu « File>Import>General>Existing Projects into Workspace »). Maintenant on peut travailler.

Eclipse et Maven ne sont utilisés ici qu'à titre pratique. Ils n'ont rien à voir avec « 3T ».

VII-C. Le Dashboard Scrum et 3T en bref

Le « dashboard » est un outil visuel de Scrum, qui ressemble aux illustrations ci-dessous. Le « dashboard Scrum » se présente le plus souvent sous la forme d'un tableau avec trois colonnes, dans lesquelles les développeurs collent des Post-It. Chaque Post-It correspond, grosso modo, à une tâche à accomplir. Les colonnes indiquent si la tâche est en attente de traitement, en cours de traitement ou terminée. En fonction de l'avancée de l'équipe, les Post-It changent progressivement de colonne.

Dashboard
Dashboard

Normalement, en début de projet (ou de « sprint ») tous les Post-It sont dans la colonne de gauche (« sprint backlog »). À la fin du projet, tous les Post-It doivent être dans la colonne de droite. Durant les développements, les Post-It transitent, en toute logique, par la colonne centrale.

Dashboard
Dashboard

Dans cet article, les développeurs de « Green Soft », mélangent les Post-It de Scrum et les Post-It de « 3T ».

VII-D. Le sprint Scrum et 3T

Dans cet article, je m'autorise beaucoup de libertés vis-à-vis de Scrum et des TDD. Dans Scrum, les Post-It vont du « sprint backlog » (c'est-à-dire la colonne de gauche du « dashboard ») vers la colonne de droite en fonction de la réalisation des tâches. Un « sprint » est une durée (généralement 2 ou 3 semaines) durant laquelle l'équipe va se concentrer sur un ensemble de Post-It bien identifiés.

Dans le cadre de « 3T », les Post-It doivent traverser trois fois le « dashboard » durant le sprint. Chaque passage correspond à un temps de « 3T » : écriture des interfaces, écriture des tests et écriture du code. J'entends déjà les puristes qui crient au scandale. Gardons à l'esprit que ce n'est qu'une proposition.

VII-E. Digression sur la confiance versus les tests

Pour finir cet article, je me permets une petite analyse personnelle à propos de la confiance. Vous souvenez-vous lorsque votre médecin vous affirmait que « ça n'allait pas faire mal » juste avant de vous infliger une piqure ? Sacré menteur !… Ma mère avait l'habitude de me dire de ne « jamais faire confiance à personne sauf à ta maman » et j'ajoute qu'il ne faut jamais faire confiance à quelqu'un qui vous demande de lui faire confiance.

Comment cela se traduit-il en informatique et plus particulièrement dans le cadre du développement logiciel ? À l'intérieur d'une application, cela implique l'utilisation de techniques de défense (copie de défense, assertion, etc.), mais ce n'est pas l'objet de cet article. Dans la communication, c'est encore plus simple : il ne faut jamais faire confiance à un développeur ou à une équipe et encore moins à un logiciel. Ce que je demande à mes clients, c'est de ne jamais croire à mes promesses (je n'en fais jamais), mais, au contraire, de toujours exiger des preuves.

Plus concrètement, et sous réserve qu'on m'en donne les moyens, je crois que « 3T » est une bonne piste pour arriver à cet objectif. Avec « 3T », on écrit d'abord les tests qui prouveront au client que le produit en création sera conforme au cahier des charges. J'insiste sur le fait que les tests doivent être écrits en amont, et non après les développements comme c'est encore trop souvent le cas malheureusement (car cela favorise la multiplication de tests de complaisance). En procédant de cette manière, je crois qu'une équipe gagne bien plus que de la « confiance » ; elle acquiert de la « crédibilité »…

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2011 Thierry Leriche-Dessirier. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.