Проблема, що розуміє, як виглядає чистий код у реальному житті


10

Зараз я читаю і працюю над «Чистим кодом: Підручник з гнучкої майстерності програмного забезпечення» Роберта К. Мартіна. Автор розповідає про те, як функція повинна виконувати лише одне, і таким чином бути відносно короткою. Конкретно Мартін пише:

Це означає, що блоки в операторах 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;
    }

Примітка. Це питання відрізняється від можливого дубліката (хоча це питання також мені корисно), тому що я намагаюся визначити, чи розумію я намір автора « Чистого кодексу», і я надаю конкретний приклад, щоб зробити щось більше бетонний.


3
наскільки я бачу, ця функція виконує лише одне ... вона не має побічних ефектів, які я бачу. Чому ви думаєте, що це може бути не чисто? Яку частину цієї функції ви вважаєте гідною, щоб її перевели в іншу функцію, щоб зробити її більш чистою?
Ньютопський

14
Назва вашого запитання задає ситуацію "в реальному житті", і тоді ваш приклад мені здається прекрасним прикладом функції не реального життя (принаймні, для 99,9% розробників програм або веб-сайтів). Звичайно, це може бути функція реального життя для теоретиків чисел, математиків або вчених-комп'ютерів, які працюють у цій конкретній галузі.
Док Браун


2
Так, для мене це реальне життя, оскільки я зараз розвиваюсь у галузі обчислювальної теорії алгебраїчних чисел :)
захід

2
Я б, швидше за все, рефакторую getTFactor (), як ви описуєте.
user949300

Відповіді:


17

"Чистий код" - це не самоціль, це засіб для досягнення мети. Основна мета переформування більших функцій на більш дрібні та очищення коду іншими способами - збереження коду, що розвивається та підтримується.

Підбираючи такий специфічний математичний алгоритм, як простий тест "Міллер-Рабін" з підручника, більшість програмістів не хочуть його розвивати. Їх стандартна мета - правильно перенести його з псевдокоду підручника в мову програмування свого середовища. Для цього я рекомендую слідкувати за текстовою книжкою якомога ближче, що, як правило, означає не робити рефактор.

Однак для того, хто працює математиком у цій галузі, який намагається працювати над цим алгоритмом і змінювати або вдосконалювати його, ІМХО розділивши цю функцію на менші, добре названі, або замінивши купу "магічних чисел" названими константами, може допомогти зробити зміни в коді простішими, як і для будь-якого іншого типу коду.


1
Це саме те, що я шукав. У мене виникли проблеми з визначенням, коли використовувати чисті кодові практики в галузі, в якій я розробляюсь. Ваша відповідь забезпечує чіткість, яку я шукав. Дякую!
захід
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.