Actualmente estoy leyendo y trabajando a través de "Clean Code: A Handbook of Agile Software Craftsmanship" de Robert C. Martin. El autor habla sobre cómo una función debe hacer una sola cosa y, por lo tanto, ser relativamente corta. Específicamente Martin escribe:
Esto implica que los bloques dentro de las declaraciones if, las declaraciones else, las declaraciones while, etc. deben tener una línea de longitud. Probablemente esa línea debería ser una llamada de función. Esto no solo mantiene la función de cierre pequeña, sino que también agrega valor documental porque la función llamada dentro del bloque puede tener un nombre muy descriptivo.
Esto también implica que las funciones no deberían ser lo suficientemente grandes como para contener estructuras anidadas. Por lo tanto, el nivel de sangría de una función no debe ser mayor que uno o dos. Esto, por supuesto, hace que las funciones sean más fáciles de leer y comprender.
Esto tiene sentido, pero parece estar en conflicto con ejemplos de lo que veo como código limpio. Tome el siguiente método, por ejemplo:
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
}
}
Este código está tomado del repositorio de código fuente de Apache Commons en: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/primes/SmallPrimes.java
El método me parece muy legible. Para implementaciones de algoritmos como este (implementación de la Prueba de Primalidad Probabilística de Miller-Rabin), ¿es adecuado mantener el código como está y aún considerarlo 'limpio', como se define en el libro? ¿O incluso algo ya tan legible como este se beneficiaría de la extracción de métodos para hacer que el algoritmo sea esencialmente una serie de llamadas a funciones que "hacen una sola cosa"? Un ejemplo rápido de extracción de un método podría ser mover las primeras tres declaraciones if a una función como:
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;
}
Nota: Esta pregunta es diferente del posible duplicado (aunque esa pregunta también me ayuda), porque estoy tratando de determinar si entiendo la intención del autor de Clean Code y estoy proporcionando un ejemplo específico para hacer las cosas más hormigón.
fuente
Respuestas:
El "código limpio" no es un fin en sí mismo, es un medio para un fin. El objetivo principal de refactorizar funciones más grandes en funciones más pequeñas y limpiar el código de otras maneras es mantener el código en evolución y mantenible.
Al elegir un algoritmo matemático tan específico como la prueba principal "Miller-Rabin" de un libro de texto, la mayoría de los programadores no quieren evolucionarlo. Su objetivo estándar es transferirlo del pseudocódigo del libro de texto correctamente al lenguaje de programación de su entorno. Para este propósito, recomendaría seguir el libro de texto lo más cerca posible, lo que generalmente significa no refactorizar.
Sin embargo, para alguien que trabaja como matemático en ese campo que está tratando de trabajar en ese algoritmo y cambiarlo o mejorarlo, en mi humilde opinión, dividir esta función en otras más pequeñas y bien nombradas, o reemplazar el grupo de "números mágicos" por constantes con nombre, puede ayuda a hacer cambios en el código más fácil como para cualquier otro tipo de código también.
fuente