难以掌握现实生活中的干净代码


10

我目前正在阅读和阅读Robert C. Martin撰写的“清洁代码:敏捷软件工艺手册”。作者讨论了一个函数应该如何仅做一件事情,因此比较简短。马丁特别写道:

这意味着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

该方法对我来说看起来很可读。对于像这样的算法实现(Miller-Rabin概率素性测试的实现),是否适合按书中的定义保持代码原样并仍然认为它“干净”?还是像这样已经很易读的东西将从提取方法中受益,使算法本质上是对“仅做一件事”的函数的一系列调用?方法提取的一个快速示例可能是将前三个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;
    }

注意:这个问题与可能重复的问题有所不同(尽管这个问题对我也有帮助),因为我试图确定我是否了解Clean Code作者的意图,并提供了一个具体示例来使事情变得更有意义。具体。


3
据我所知,此功能仅做一件事……它没有副作用。是什么让您认为它可能不干净?您认为值得将该功能的哪一部分放入另一个功能中以使其更清洁?
Newtopian

14
您的问题标题要求提供“现实生活”的情况,然后您的示例在我看来就像一个非现实功能的完美示例(至少对于99.9%的应用程序或Web开发人员而言)。当然,对于在那个特定领域工作的数字理论家,数学家或计算机科学家来说,这可能是一种现实生活中的功能。
布朗


2
是的,对我来说,这是现实生活,因为我目前正在计算代数数论领域发展:)
1west

2
我可能会像您描述的那样重构getTFactor()。
user949300

Answers:


17

“干净的代码”本身并不是目的,而是达到目的的一种手段。将较大的函数重构为较小的函数并以其他方式清理代码的主要目的是保持代码的可演化性和可维护性。

当从课本中选择非常具体的数学算法(例如“ Miller-Rabin”素数测试)时,大多数程序员都不想对其进行改进。他们的标准目标是将其从教科书的伪代码正确地转换为他们环境的编程语言。为此,我建议尽可能靠近课本,这通常意味着不要重构。

但是,对于在该领域从事数学工作的人,如果想尝试该算法并进行更改或改进,恕我直言,可以将此函数拆分为较小的,命名明确的函数,或用命名常量替换“神奇数字”。与其他任何类型的代码一样,也有助于简化代码更改。


1
这正是我想要的。我在确定何时在开发领域中使用干净的代码实践时遇到了麻烦。您的答案提供了我所寻找的清晰性。谢谢!
西部
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.