Зараз я читаю і працюю над «Чистим кодом: Підручник з гнучкої майстерності програмного забезпечення» Роберта К. Мартіна. Автор розповідає про те, як функція повинна виконувати лише одне, і таким чином бути відносно короткою. Конкретно Мартін пише:
Це означає, що блоки в операторах if, операторах else, в той час як оператори і так далі повинні бути довгими на один рядок. Можливо, ця лінія повинна бути викликом функції. Це не тільки робить функцію, що додає, невеликою, але й додає документальну цінність, оскільки функція, що викликається в блоці, може мати добре описову назву.
Це також означає, що функції не повинні бути досить великими, щоб утримувати вкладені структури. Тому рівень відступу функції не повинен перевищувати одного або двох. Це, звичайно, полегшує читання та розуміння функцій
Це має сенс, але, здається, суперечить прикладам того, що я вважаю чистим кодом. Візьмемо для прикладу наступний метод:
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;
}
Примітка. Це питання відрізняється від можливого дубліката (хоча це питання також мені корисно), тому що я намагаюся визначити, чи розумію я намір автора « Чистого кодексу», і я надаю конкретний приклад, щоб зробити щось більше бетонний.