ปัญหาในการเข้าใจโค้ดที่ดูสะอาดตาในชีวิตจริง


10

ขณะนี้ฉันกำลังอ่านและทำงานผ่าน "รหัสสะอาด: หนังสือฝีมือซอฟต์แวร์เปรียว" โดย Robert C. Martin ผู้เขียนพูดถึงว่าฟังก์ชั่นควรทำสิ่งใดสิ่งหนึ่งเท่านั้นจึงค่อนข้างสั้น มาร์ตินเขียน:

นี่ก็หมายความว่าบล็อกภายในถ้าคำสั่งคำสั่งอื่นในขณะที่คำสั่งและอื่น ๆ ควรมีความยาวหนึ่งบรรทัด อาจเป็นไปได้ว่าสายควรจะเรียกฟังก์ชั่น สิ่งนี้ไม่เพียงทำให้ฟังก์ชั่นการปิดล้อมมีขนาดเล็ก แต่ยังเพิ่มมูลค่าเอกสารเพราะฟังก์ชั่นที่เรียกว่าภายในบล็อกสามารถมีชื่อที่สื่อความหมายได้ดี

นี่ก็หมายความว่าหน้าที่ไม่ควรใหญ่พอที่จะเก็บโครงสร้างที่ซ้อนกัน ดังนั้นระดับเยื้องของฟังก์ชันไม่ควรมากกว่าหนึ่งหรือสอง แน่นอนสิ่งนี้ทำให้ฟังก์ชั่นการอ่านและทำความเข้าใจง่ายขึ้น

มันสมเหตุสมผล แต่ดูเหมือนขัดแย้งกับตัวอย่างของสิ่งที่ฉันเห็นว่าเป็นโค้ดที่สะอาด ใช้วิธีการต่อไปนี้เช่น:

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

รหัสนี้นำมาจาก repo ซอร์สโค้ด Apache ที่: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/primes/SmallPrimes.java

วิธีการอ่านมากสำหรับฉัน สำหรับการใช้งานอัลกอริทึมเช่นนี้ (การทดสอบการทำงานของ Miller-Rabin Probabilistic Primality) เหมาะสมหรือไม่ที่จะต้องเก็บรหัสตามที่เป็นอยู่และยังถือว่ามันสะอาดตามที่กำหนดไว้ในหนังสือ หรือแม้กระทั่งบางสิ่งบางอย่างที่สามารถอ่านได้แล้วเนื่องจากได้รับประโยชน์จากวิธีการแยกเพื่อให้อัลกอริทึมเป็นชุดที่เรียกฟังก์ชันที่ "ทำสิ่งเดียวเท่านั้น"? ตัวอย่างหนึ่งอย่างรวดเร็วของการแยกเมธอดอาจเป็นการย้าย if-statement สามรายการแรกไปยังฟังก์ชันเช่น:

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
เท่าที่ฉันเห็นฟังก์ชั่นนี้ทำสิ่งเดียวเท่านั้น ... มันไม่มีผลข้างเคียงที่ฉันเห็น อะไรทำให้คุณคิดว่าอาจไม่สะอาด ส่วนไหนของฟังก์ชั่นนี้ที่คุณจะพิจารณาว่าสมควรใส่ไว้ในฟังก์ชั่นอื่นเพื่อทำให้มันสะอาดขึ้น?
Newtopian

14
ชื่อคำถามของคุณถามถึงสถานการณ์ "ชีวิตจริง" และจากนั้นตัวอย่างของคุณดูเหมือนว่าฉันเป็นตัวอย่างที่สมบูรณ์แบบของฟังก์ชั่นที่ไม่ใช่ชีวิตจริง (อย่างน้อย 99.9% ของแอปพลิเคชันหรือนักพัฒนาเว็บ) มันอาจเป็นฟังก์ชั่นในชีวิตจริงสำหรับนักทฤษฎีจำนวนนักคณิตศาสตร์หรือนักวิทยาศาสตร์คอมพิวเตอร์ที่ทำงานในสาขาเฉพาะนั้นแน่นอน
Doc Brown


2
ใช่สำหรับฉันนี่คือชีวิตจริงขณะที่ฉันกำลังพัฒนาในด้านทฤษฎีจำนวนพีชคณิตการคำนวณ :)
1

2
ฉันน่าจะ refactor getTFactor () ตามที่คุณอธิบาย
user949300

คำตอบ:


17

"รหัสสะอาด" ไม่ใช่จุดจบในตัวมันเป็นหนทางไปสู่จุดจบ จุดประสงค์หลักของการปรับฟังก์ชั่นที่ใหญ่ขึ้นให้เล็กลงและทำความสะอาดโค้ดในรูปแบบอื่น ๆ คือการรักษารหัสให้คงอยู่และบำรุงรักษาได้

เมื่อเลือกอัลกอริทึมทางคณิตศาสตร์ที่เฉพาะเจาะจงเช่นการทดสอบเฉพาะ "มิลเลอร์ - ราบิน" จากหนังสือตำราโปรแกรมเมอร์ส่วนใหญ่ไม่ต้องการที่จะพัฒนามัน เป้าหมายมาตรฐานของพวกเขาคือการถ่ายโอนจากรหัสเทียมของหนังสือเรียนอย่างถูกต้องไปยังภาษาการเขียนโปรแกรมของสภาพแวดล้อมของพวกเขา เพื่อจุดประสงค์นี้ฉันอยากจะแนะนำให้ทำตามตำราเรียนให้มากที่สุดซึ่งโดยทั่วไปจะไม่หมายถึงการปรับโครงสร้าง

อย่างไรก็ตามสำหรับคนที่ทำงานเป็นนักคณิตศาสตร์ในสาขานั้นซึ่งพยายามที่จะทำงานกับอัลกอริทึมนั้นและเปลี่ยนแปลงหรือปรับปรุง IMHO ได้แยกฟังก์ชันนี้ออกเป็นขนาดเล็ก ๆ ชื่อที่มีชื่อเสียงหรือแทนที่กลุ่มของ "หมายเลขเวทมนตร์" โดยค่าคงที่ชื่อสามารถ ช่วยในการเปลี่ยนแปลงรหัสได้ง่ายขึ้นเช่นเดียวกับรหัสอื่น ๆ เช่นกัน


1
นี่คือสิ่งที่ฉันกำลังมองหา ฉันมีปัญหาในการพิจารณาว่าเมื่อใดควรใช้แนวทางปฏิบัติแบบคลีนโค้ดในสาขาที่ฉันกำลังพัฒนาคำตอบของคุณให้ความชัดเจนที่ฉันกำลังมองหา ขอบคุณ!
2560
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.