mercredi 14 décembre 2011

Tdd is not enough


Je viens de faire un petit truc en TDD et je me suis rendu compte que mon code était tout crade par rapport à ce qu'on pouvait faire.


L'idée c'était de faire une methode qui transforme les sauts de ligne ASCII en paragraphe ou en saut de ligne HTML
ex

Lalala
lilili

toto
tata

se transforme en

<p>Lalala<br/>Lilili</p><p>toto<br/>tata</p>

c'est fou non ?


Bref pour faire ça je me suis dis que j'allais sortir mon copain le TDD. Alors je fais mes tests au fur et à mesure du dev et j'obtiens ce jeu de tests

    @Test
    public void testFormatDisclaimerForHTMLPrinting() {
        Assert.assertEquals("<p>test</p>", DisclaimerAction.formatDisclaimerForHTMLPrinting("  \ntest"));
        Assert.assertEquals("<p>test</p>", DisclaimerAction.formatDisclaimerForHTMLPrinting("  \ntest\n"));
        Assert.assertEquals("<p>test<br/>test</p>", DisclaimerAction.formatDisclaimerForHTMLPrinting("  \ntest\ntest"));
        Assert.assertEquals("<p>test</p><p>test</p>", DisclaimerAction.formatDisclaimerForHTMLPrinting("  \ntest\n   \ntest"));
        Assert.assertEquals("<p>test</p><p>test</p>", DisclaimerAction.formatDisclaimerForHTMLPrinting("  \ntest\n \n \n  \ntest"));
        Assert.assertEquals("<p>test</p><p>test</p>", DisclaimerAction.formatDisclaimerForHTMLPrinting("  \ntest\n \n \n  \ntest"));
        Assert.assertEquals("<p>test</p><p>test<br/>toto</p>",
                DisclaimerAction.formatDisclaimerForHTMLPrinting("  \ntest\n \n \n  \ntest\ntoto"));

    }

et surtout ce code tout crade :
    public static String formatDisclaimerForHTMLPrintingOld(String toFormat) {
        String[] lines = toFormat.trim().split("\n");
        String toReturn = "<p>";
        for (int i = 0; i < lines.length; i++) {
            if (StringUtils.isEmpty(lines[i].trim())) {
                toReturn += "</p><p>";
                while (i < lines.length - 1 && StringUtils.isEmpty(lines[i + 1].trim())) {
                    i++;
                }

            } else {
                toReturn += lines[i];
                if (i + 1 < lines.length && !StringUtils.isEmpty(lines[i + 1].trim())) {
                    toReturn += "<br/>";
                }
            }
        }

        return toReturn + "</p>";
    }

J'ai pas trop essayer de reflechir en écrivant ça. Juste de prendre le test qui marche pas et d'écrire le code qui le fait marcher.

Alors ce matin je regarde d'un oeil coupable ce code, je commence à réfléchir et j'écris ça :

public static String formatDisclaimerForHTMLPrinting(String toFormat) {
        String toReturn = toFormat.trim();
        toReturn = toReturn.replaceAll("\\s*\\n\\s*\\n\\s*", "</p><p>");
        toReturn = toReturn.replaceAll("\\n", "<br/>");
        return "<p>" + toReturn + "</p>";
}

plus concis, plus simple, plus joli... et il passe bien mes tests.


Dans le TDD y a bien cette phase de refactoring qui est précisée cependant c'est quand même un peu difficile parce qu'une fois que j'ai écris mon code crade j'ai beau temps de le laisser comme ça s'il y a une autre urgence.

hum, je ne sais quelle conclusion tirer de tout ça. Si ce n'est que l'approche originale de TDD est peut être un peu trop dogmatique et qu'il faut toujours réfléchir avant de coder (... arf toujours pas de solution contre ce mal).

2 commentaires :

  1. Je dirais même que si demain tu veux que ton code soit plus générique et permette d'html-iser des variables passées en paramètres, tu auras une bose solide pour faire tes tests... et donc valider la robustesse de ton évolution, que tu pourras là aussi faire en 2 temps.

    Il faut voir (selon moi) TDD comme "qu'est-ce que la présence de ces tests me permettent de faire ? qu'est-ce que j'aurais peur de toucher si je n'avais pas eu ces tests ?

    TDD permet de faire confiance au code et d'avoir confiance en soi pour le modifier afin de le rendre meilleur.

    Sans TDD, on change à l'aveugle et on laisse traîner du code parce qu'on ne sait pas, parce qu'on n'a pas de filet de sécurité.

    my 2 cents :)

    RépondreSupprimer
    Réponses
    1. Attention, en aucun cas je ne remets en cause le fait de tester son code. Pour moi, il est clair que cela reste indispensable (Avec une granularité correcte toutefois) et un développement n'est DONE que lorsque les tests sont présents. C'est une faute professionnelle dans mon équipe de ne pas avoir de test sur un dev et ça ne passe pas un code review.

      Ce que je remets en cause c'est le dogmatisme de dire je ne touche pas mon code avant d'avoir un test qui échoue et surtout je fais des incréments de développement à chaque fois que mon test passe.




      Supprimer