Kesulitan memahami seperti apa kode bersih di kehidupan nyata

10

Saat ini saya membaca dan bekerja melalui "Kode Bersih: Buku Panduan Pengerjaan Perangkat Lunak Agile" oleh Robert C. Martin. Penulis berbicara tentang bagaimana suatu fungsi seharusnya melakukan satu hal saja, dan dengan demikian relatif singkat. Secara khusus Martin menulis:

Ini menyiratkan bahwa blok-blok di dalam pernyataan if, pernyataan lain, pernyataan sementara, dan seterusnya harus sepanjang satu baris. Mungkin saluran itu harus menjadi pemanggilan fungsi. Ini tidak hanya menjaga fungsi penutup tetap kecil, tetapi juga menambah nilai dokumenter karena fungsi yang disebut di dalam blok dapat memiliki nama deskriptif yang bagus.

Ini juga menyiratkan bahwa fungsi tidak boleh cukup besar untuk menampung struktur bersarang. Oleh karena itu, level indent suatu fungsi tidak boleh lebih besar dari satu atau dua. Ini, tentu saja, membuat fungsi lebih mudah dibaca dan dimengerti

Ini masuk akal, tetapi tampaknya bertentangan dengan contoh-contoh dari apa yang saya lihat sebagai kode bersih. Ambil metode berikut ini misalnya:

    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
    }
}

Kode ini diambil dari repo kode sumber Apache Commons di: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/primes/SmallPrimes.java

Metode ini terlihat sangat mudah dibaca oleh saya. Untuk implementasi algoritma seperti ini (implementasi Miller-Rabin Probabilistic Primality Test), apakah cocok untuk menjaga kode seperti apa adanya dan masih menganggapnya 'bersih', seperti yang didefinisikan dalam buku ini? Atau bahkan sesuatu yang sudah dapat dibaca karena manfaat dari metode penggalian untuk membuat algoritma dasarnya serangkaian panggilan ke fungsi yang "melakukan satu hal saja"? Salah satu contoh cepat dari ekstraksi metode mungkin memindahkan tiga pernyataan-if pertama ke fungsi seperti:

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;
    }

Catatan: Pertanyaan ini berbeda dengan kemungkinan duplikat (meskipun pertanyaan itu juga membantu saya), karena saya mencoba menentukan apakah saya memahami maksud dari penulis Kode Bersih dan saya memberikan contoh khusus untuk membuat lebih banyak hal beton.

1 barat
sumber
3
sejauh yang saya bisa lihat fungsi ini hanya melakukan satu hal ... ia tidak memiliki efek samping yang dapat saya lihat. Apa yang membuat Anda berpikir itu mungkin tidak bersih? Bagian mana dari fungsi ini yang Anda anggap layak dimasukkan ke dalam fungsi lain untuk membuatnya lebih bersih?
Newtopian
14
Judul pertanyaan Anda menanyakan situasi "kehidupan nyata", dan kemudian contoh Anda terlihat seperti contoh sempurna dari fungsi non-kehidupan nyata (setidaknya, untuk 99,9% pengembang aplikasi atau web). Ini mungkin fungsi kehidupan nyata bagi sejumlah ahli teori, ahli matematika atau ilmuwan komputer yang bekerja di bidang spesifik itu, tentu saja.
Doc Brown
2
Ya, bagi saya ini adalah kehidupan nyata karena saya saat ini berkembang di bidang teori bilangan aljabar komputasi :)
1west
2
Saya mungkin akan memperbaiki getTFactor () seperti yang Anda jelaskan.
user949300

Jawaban:

17

"Kode bersih" bukan tujuan itu sendiri, ini adalah sarana untuk mencapai tujuan. Tujuan utama dari refactoring fungsi yang lebih besar menjadi yang lebih kecil dan membersihkan kode dengan cara lain adalah untuk menjaga agar kode dapat dikembangkan dan dipelihara.

Ketika memilih algoritma matematika yang sangat spesifik seperti tes utama "Miller-Rabin" dari sebuah buku teks, kebanyakan programmer tidak ingin mengembangkannya. Tujuan standar mereka adalah untuk mentransfernya dari kode semu buku teks dengan benar ke bahasa pemrograman lingkungan mereka. Untuk tujuan ini, saya akan merekomendasikan untuk mengikuti buku teks sedekat mungkin, yang biasanya berarti tidak melakukan refactor.

Namun, untuk seseorang yang bekerja sebagai ahli matematika di bidang itu yang mencoba mengerjakan algoritma itu dan mengubah atau memperbaikinya, IMHO membagi fungsi ini menjadi yang lebih kecil, yang bernama baik, atau mengganti sekelompok "angka ajaib" dengan konstanta bernama, dapat membantu membuat perubahan pada kode lebih mudah seperti untuk jenis kode lainnya juga.

Doc Brown
sumber
1
Inilah yang saya cari. Saya mengalami kesulitan menentukan kapan harus menggunakan praktik kode bersih di bidang yang saya kembangkan. Jawaban Anda memberikan kejelasan yang saya cari. Terima kasih!
Barat