실생활에서 깨끗한 코드가 어떻게 보이는지 파악하는 데 어려움


10

저는 현재 Robert C. Martin의 "Clean Code : A Agile Software Craftsmanship 핸드북"을 읽고 작업하고 있습니다. 저자는 함수가 어떻게 한 가지만 수행해야하는지에 대해 이야기하므로 상대적으로 짧습니다. 특히 Martin은 다음과 같이 씁니다.

이는 if 문, else 문, while 문 등의 블록이 한 줄 길이 여야 함을 의미합니다. 아마도 그 라인은 함수 호출이어야합니다. 이렇게하면 둘러싼 함수가 작게 유지 될뿐만 아니라 블록 내에서 호출 된 함수의 이름이 잘 설명 될 수 있으므로 다큐멘터리 값이 추가됩니다.

이것은 또한 함수가 중첩 구조를 보유하기에 충분히 크지 않아야 함을 의미합니다. 따라서 함수의 들여 쓰기 레벨은 1 또는 2보다 크지 않아야합니다. 이것은 물론 함수를 읽고 이해하기 쉽게 만듭니다.

이것은 의미가 있지만 깨끗한 코드로 보는 예제와 충돌하는 것 같습니다. 예를 들어 다음 방법을 사용하십시오.

    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 Probabilistic Primality Test 구현)의 경우 코드를 그대로 유지하고 책에 정의 된대로 '깨끗한'것으로 간주하는 것이 적합합니까? 아니면 알고리즘을 본질적으로 "한 가지만 수행하는"함수에 대한 일련의 호출로 만드는 메소드 추출의 이점으로 이미 읽을 수있는 것이 있을까요? 메소드 추출의 빠른 예는 처음 세 개의 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 %)의 완벽한 예처럼 보입니다. 물론 특정 분야에서 일하는 수많은 이론가, 수학자 또는 컴퓨터 과학자에게는 실제 기능 일 수 있습니다.
Doc Brown


2
예, 저는 계산 대수 이론에서 현재 발전하고있는
실생활입니다.

2
설명대로 getTFactor ()를 리팩터링 할 것입니다.
user949300

답변:


17

"클린 코드"는 그 자체가 목적이 아니라 목적을위한 수단입니다. 더 큰 함수를 더 작은 함수로 리팩토링하고 다른 방법으로 코드를 정리하는 주된 목적은 코드를 전개 가능하고 유지 가능하게 유지하는 것입니다.

교과서에서 "밀러-라빈 (Miller-Rabin)"프라임 테스트와 같은 매우 구체적인 수학적 알고리즘을 선택할 때 대부분의 프로그래머는이를 진화시키고 싶지 않습니다. 표준 목표는 교과서의 의사 코드에서 환경의 프로그래밍 언어로 올바르게 전송하는 것입니다. 이를 위해 교과서를 최대한 가깝게 따르는 것이 좋습니다. 이는 일반적으로 리팩터링하지 않는 것을 의미합니다.

그러나 해당 분야에서 수학자로 일하고 해당 알고리즘을 변경하거나 개선하려는 사람의 경우 IMHO는이 기능을 더 작고 이름이 지정된 기능으로 나누거나 이름이 지정된 상수로 "마법의 숫자"를 대체 할 수 있습니다. 다른 종류의 코드와 마찬가지로 코드를 쉽게 변경할 수 있습니다.


1
이것이 바로 내가 찾던 것입니다. 내가 개발하고있는 분야에서 깨끗한 코드 관행을 언제 사용할지 결정하는 데 어려움을 겪고있었습니다. 귀하의 답변은 내가 찾고 있던 명확성을 제공합니다. 감사!
1west
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.