В настоящее время я читаю и работаю над «Чистым кодом: Справочник по мастерству гибкого программного обеспечения» Роберта Мартина. Автор говорит о том, как функция должна делать только одну вещь и, следовательно, быть относительно короткой. Конкретно Мартин пишет:
Это означает, что блоки внутри операторов if, операторов else, операторов while и т. Д. Должны быть длиной в одну строку. Вероятно, эта строка должна быть вызовом функции. Это не только уменьшает объем включаемой функции, но также добавляет документальное значение, поскольку вызываемая внутри блока функция может иметь приятное описательное имя.
Это также подразумевает, что функции не должны быть достаточно большими, чтобы содержать вложенные структуры. Следовательно, уровень отступа функции не должен быть больше одного или двух. Это, конечно, облегчает чтение и понимание функций
Это имеет смысл, но, кажется, вступает в противоречие с примерами того, что я вижу как чистый код. Возьмите следующий метод для примера:
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
}
}
Этот код взят из репозитория исходного кода Apache Commons по адресу: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/primes/SmallPrimes.java
Метод выглядит очень читабельным для меня. Для реализаций алгоритма, подобных этой (реализация вероятностного критерия простоты Миллера-Рабина), подходит ли сохранить код как есть и все еще считать его «чистым», как определено в книге? Или даже что-то уже столь же читаемое, как эта выгода от извлечения методов, делающих алгоритм по существу последовательным вызовом функций, которые «делают только одну вещь»? Одним из быстрых примеров извлечения метода может быть перемещение первых трех операторов if в такую функцию:
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;
}
Примечание. Этот вопрос отличается от возможного дубликата (хотя этот вопрос и мне полезен), потому что я пытаюсь определить, понимаю ли я намерение автора Чистого кода и приведу конкретный пример, чтобы сделать вещи более бетон.
источник
Ответы:
«Чистый код» - это не самоцель, а средство для достижения цели. Основная цель преобразования больших функций в более мелкие и очистки кода другими способами состоит в том, чтобы обеспечить возможность развития и поддержки кода.
Когда из учебника выбирают такой специфический математический алгоритм, как простой тест Миллера-Рабина, большинство программистов не хотят его развивать. Их стандартная цель состоит в том, чтобы правильно перенести его из псевдокода учебника на язык программирования их среды. Для этой цели я бы рекомендовал как можно ближе следовать учебнику, что, как правило, означает не проводить рефакторинг.
Тем не менее, для кого-то, работающего в качестве математика в этой области, который пытается работать над этим алгоритмом и изменить или улучшить его, ИМХО разделение этой функции на более мелкие, хорошо именованные или замена группы «магических чисел» именованными константами, может помочь сделать изменения в коде проще, как и для любого другого вида кода.
источник