Difficulté à comprendre à quoi ressemble un code propre dans la vraie vie

10

Je lis et travaille actuellement sur "Clean Code: A Handbook of Agile Software Craftsmanship" de Robert C. Martin. L'auteur explique comment une fonction doit faire une seule chose, et donc être relativement courte. Plus précisément, Martin écrit:

Cela implique que les blocs contenus dans les instructions if, les instructions else, les instructions while, etc. doivent être d'une ligne. Cette ligne devrait probablement être un appel de fonction. Non seulement cela maintient la fonction englobante petite, mais cela ajoute également une valeur documentaire car la fonction appelée dans le bloc peut avoir un nom bien descriptif.

Cela implique également que les fonctions ne doivent pas être suffisamment grandes pour contenir des structures imbriquées. Par conséquent, le niveau de retrait d'une fonction ne doit pas être supérieur à un ou deux. Ceci, bien sûr, rend les fonctions plus faciles à lire et à comprendre

Cela a du sens, mais semble entrer en conflit avec des exemples de ce que je considère comme du code propre. Prenons par exemple la méthode suivante:

    public static boolean millerRabinPrimeTest(final int n) {
        final int nMinus1 = n - 1;
        final int s = Integer.numberOfTrailingZeros(nMinus1);
        final int r = nMinus1 >> s;
        //r must be odd, it is not checked here
        int t = 1;
        if (n >= 2047) {
            t = 2;
        }
        if (n >= 1373653) {
            t = 3;
        }
        if (n >= 25326001) {
            t = 4;
        } // works up to 3.2 billion, int range stops at 2.7 so we are safe :-)
        BigInteger br = BigInteger.valueOf(r);
        BigInteger bn = BigInteger.valueOf(n);

        for (int i = 0; i < t; i++) {
            BigInteger a = BigInteger.valueOf(SmallPrimes.PRIMES[i]);
            BigInteger bPow = a.modPow(br, bn);
            int y = bPow.intValue();
            if ((1 != y) && (y != nMinus1)) {
                int j = 1;
                while ((j <= s - 1) && (nMinus1 != y)) {
                    long square = ((long) y) * y;
                    y = (int) (square % n);
                    if (1 == y) {
                        return false;
                    } // definitely composite
                    j++;
                }
                if (nMinus1 != y) {
                    return false;
                } // definitely composite
            }
        }
        return true; // definitely prime
    }
}

Ce code est extrait du référentiel de code source d'Apache Commons à l' adresse : https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/primes/SmallPrimes.java

La méthode me semble très lisible. Pour les implémentations d'algorithmes comme celle-ci (implémentation du test de probabilité probabiliste de Miller-Rabin), est-il approprié de conserver le code tel quel et de le considérer comme `` propre '', tel que défini dans le livre? Ou serait-ce même quelque chose de déjà aussi lisible que cela tirerait de l'extraction de méthodes pour faire de l'algorithme essentiellement une série d'appels à des fonctions qui "ne font qu'une chose"? Un exemple rapide d'une extraction de méthode pourrait être de déplacer les trois premières instructions if vers une fonction comme:

private static int getTValue(int n)
    {
        int t = 1;
        if (n >= 2047) {
            t = 2;
        }
        if (n >= 1373653) {
            t = 3;
        }
        if (n >= 25326001) {
            t = 4;    
        }
        return t;
    }

Remarque: Cette question est différente du doublon possible (bien que cette question me soit également utile), car j'essaie de déterminer si je comprends l'intention de l'auteur de Clean Code et je fournis un exemple spécifique pour rendre les choses plus béton.

1west
la source
3
pour autant que je puisse voir, cette fonction ne fait qu'une chose ... elle n'a pas d'effets secondaires que je puisse voir. Qu'est-ce qui vous fait penser que ce n'est peut-être pas propre? Quelle partie de cette fonction vous considéreriez digne d'être placée dans une autre fonction pour la rendre plus propre?
Newtopian
14
Le titre de votre question demande une situation «réelle», puis votre exemple me semble être un exemple parfait d'une fonction non réelle (au moins pour 99,9% des développeurs d'applications ou de développeurs Web). Il peut bien sûr s'agir d'une fonction réelle pour les théoriciens des nombres, les mathématiciens ou les informaticiens travaillant dans ce domaine spécifique.
Doc Brown
2
Oui, pour moi, c'est la vraie vie car je développe actuellement dans le domaine de la théorie des nombres algébriques computationnels :)
1west
2
Je voudrais probablement refactoriser le getTFactor () comme vous le décrivez.
user949300

Réponses:

17

Le «code propre» n'est pas une fin en soi, c'est un moyen pour une fin. Le principal objectif de la refonte de fonctions plus grandes en fonctions plus petites et de nettoyer le code d'autres manières est de maintenir le code évolutif et maintenable.

En choisissant un algorithme mathématique très spécifique comme le test principal "Miller-Rabin" dans un manuel, la plupart des programmeurs ne veulent pas le faire évoluer. Leur objectif standard est de le transférer correctement du pseudo-code du manuel dans le langage de programmation de leur environnement. À cette fin, je recommanderais de suivre le manuel le plus près possible, ce qui signifie généralement de ne pas refactoriser.

Cependant, pour quelqu'un qui travaille en tant que mathématicien dans ce domaine qui essaie de travailler sur cet algorithme et de le changer ou de l'améliorer, à mon humble avis, diviser cette fonction en plus petites et bien nommées, ou remplacer le groupe de "nombres magiques" par des constantes nommées, peut aider à apporter des modifications au code plus facilement comme pour tout autre type de code.

Doc Brown
la source
1
Ceci est exactement ce que je cherchais. J'avais du mal à déterminer quand utiliser les pratiques de code propre dans le domaine dans lequel je développe. Votre réponse apporte la clarté que je recherchais. Merci!
1west