복잡한 코드를 설명하는 주석에 어떤 문제가 있습니까?


236

많은 사람들이 "의견은 '왜'를 설명해야하지만 '어떻게'를 설명해서는 안된다"고 주장합니다. 다른 사람들은 "코드는 자기 문서화되어야한다"고 말하고 주석은 드 물어야한다고 말한다. Robert C. Martin은 (내 말로 표현하면) "댓글은 잘못 작성된 코드에 대한 사과"라고 주장합니다.

내 질문은 다음과 같습니다

설명이 복잡한 복잡한 알고리즘이나 길고 복잡한 코드를 설명하는 데 무엇이 문제가 있습니까?

이 방법을 사용하면 다른 개발자 (자신 포함)가 전체 알고리즘을 한 줄씩 읽어야 할 필요가 없으며, 평범한 영어로 작성한 친근한 설명 주석을 읽을 수 있습니다.

영어는 사람이 쉽게 이해할 수 있도록 '설계되었습니다. 그러나 Java, Ruby 또는 Perl은 인간의 가독성과 컴퓨터의 가독성을 균형있게 설계하여 텍스트의 가독성을 떨어 뜨립니다. 인간은 영어를 훨씬 더 빨리 이해할 수 있습니다. 조작이 사소하지 않은 한 동일한 의미의 코드를 이해할 수 있습니다.

따라서 부분적으로 사람이 읽을 수있는 프로그래밍 언어로 작성된 복잡한 코드를 작성한 후, 친숙하고 이해하기 쉬운 영어로 코드의 작동을 설명하는 설명적이고 간결한 설명을 추가해보십시오.

어떤 사람들은 "코드를 이해하기 어려워서는 안된다", "기능을 작게 만들다", "설명적인 이름 사용하기", "스파게티 코드를 쓰지 마십시오"라고 말할 것입니다.

그러나 우리는 그것이 충분하지 않다는 것을 알고 있습니다. 이 지침은 중요하고 유용한 지침 일 뿐이지 만 일부 알고리즘이 복잡하다는 사실을 변경하지는 않습니다. 따라서 한 줄씩 읽을 때 이해하기 어렵습니다.

일반적인 연산에 대한 몇 줄의 주석으로 복잡한 알고리즘을 설명하는 것이 실제로 그렇게 나쁜가요? 주석으로 복잡한 코드를 설명 할 때 무엇이 ​​문제입니까?


14
그것이 복잡하다면, 작은 조각으로 리팩토링을 시도하십시오.
Vaughan Hilts

151
이론적으로는 이론과 실제에 차이가 없습니다. 실제로는 있습니다.
Scott Leadley

5
@ mattnz : 더 직접적으로, 주석을 작성할 때이 코드로 해결되는 문제에 빠져 있습니다. 다음에 방문하면 이 문제에 대한 기능이 줄어 듭니다 .
Steve Jessop

26
함수 나 메소드의 "무엇"은 그 이름에서 명백해야합니다. 그것이 어떻게 코드에서 분명하다. 왜 이런 식으로, 암시 적 가정이 사용되었는지, 알고리즘을 이해하기 위해 읽어야 할 논문 등은 주석에 있어야합니다.
SK-logic

11
아래 답변 중 많은 부분이 의도적으로 귀하의 질문을 잘못 해석한다고 생각합니다. 코드 주석에 아무런 문제가 없습니다. 설명 주석을 작성해야한다고 생각되면해야합니다.
Tony Ennis

답변:


408

평신도의 관점에서 :

  • 주석 자체 에는 아무런 문제가 없습니다 . 문제는 이런 종류의 주석이 필요한 코드를 작성하거나 평범한 영어로 친숙하게 설명하는 한 복잡한 코드를 작성하는 것이 좋다고 가정하는 것입니다.
  • 코드를 변경할 때 주석은 자동으로 업데이트되지 않습니다. 그렇기 때문에 종종 주석이 코드와 동기화되지 않습니다.
  • 주석으로 코드를 쉽게 테스트 할 수는 없습니다.
  • 사과는 나쁘지 않습니다. 사과하기 쉬운 (쉽게 이해할 수없는 코드 작성)은 나쁘다.
  • 복잡한 문제를 해결하기 위해 간단한 코드를 작성할 수있는 프로그래머는 복잡한 코드를 작성한 다음 코드의 기능을 설명하는 긴 주석을 작성하는 것보다 낫습니다.

결론 :

자신을 설명하는 것이 좋으며 그렇게 할 필요가 없습니다.


91
좋은 의견이 훨씬 적은 시간 내에 작업을 수행 할 수있을 때 고용주의 돈 재 작성 코드를보다 자명하게 설명하는 것이 종종 불가능합니다. 정직한 프로그래머는 매번 자신의 판단을 사용해야합니다.
aecolley

34
@aecolley 처음부터 설명하는 코드를 작성하는 것이 좋습니다.
Tulains Córdova

127
때로는 자체 설명 코드가 오늘날의 HW & SW의 문제를 해결할만큼 효율적이지 않습니다. 그리고 비즈니스 로직은 악명 높았습니다 ... 우아한 소프트웨어 솔루션이있는 문제의 하위 집합은 경제적으로 해결하는 데 도움이되는 문제 집합보다 훨씬 작습니다.
Scott Leadley

62
@rwong : 반대로, 나는 종종 비즈니스 로직에서 더 많은 의견을 작성하고 있음을 발견한다. 왜냐하면 코드가 명시된 요구 사항과 어떻게 일치하는지 정확하게 보여주는 것이 중요하기 때문이다. 형법 ". 그것이 단지 알고리즘이라면, 프로그래머는 절대적으로 필요한 경우 목적을 처음부터 알아낼 수 있습니다. 비즈니스 로직의 경우 동시에 같은 방에 변호사와 고객이 필요합니다. 아마도 내 "상식"평균 응용 프로그래머의 ;-)에서 다른 도메인에
스티브 Jessop

29
@ user61852 코드를 작성하고 마지막 $ 기간을 사용한 당신에게 자명 한 것을 제외하고 지금부터 5 년 동안 유지하거나 편집 해야하는 사람에게는 자명하지 않을 수도 있습니다. 당신이 아닌 사람들을보아야 할 수도 있습니다. "자명 한 설명"은 정의의 성스러운 성배입니다.
Shadur

110

코드가 복잡하거나 혼동되는 데에는 여러 가지 이유가 있습니다. 가장 일반적인 이유는 최고의되지 않은 모든 종류의 의견을 추가하여, 덜 혼란하게하는 코드를 리팩토링에 의해 해결된다.

그러나 잘 선택된 의견이 최선의 선택 인 경우가 있습니다.

  • 그것은 경우 알고리즘 자체 , 복잡하고 혼란뿐만 아니라 읽기, 수학 저널에 작성 얻고 Mbogo의 알고리즘 - 다음 구현의 시작에 코멘트를 넣어 영원히이라고 구현-종류를 "이것은 원래 여기에 설명 된 위젯을 되 찾는 Mbogo의 알고리즘입니다. [용지의 URL].이 구현에는 Alice와 Carol의 수정이 포함되어 있습니다. [다른 용지의 URL]." 그것보다 더 자세하게 들어 가려고하지 마십시오. 더 자세한 정보가 필요한 사람은 아마도 전체 논문을 읽어야 할 것입니다.

  • 특별한 표기법으로 한두 줄로 쓸 수있는 것을 취해 그것을 명령형 코드의 큰 글로로 확장 한 경우, 그 한두 줄의 특수 표기법을 주석 위에 주석으로 묶는 것이 좋은 방법입니다 독자에게 해야 할 일을 알려주십시오 . 특수 주석이 코드 보다 버그를 찾기가 훨씬 쉽기 때문에 "하지만 주석이 코드와 동기화되지 않는 경우"인수에 대한 예외 입니다. (영어로 사양을 작성한 경우 다른 방법입니다.) 좋은 예는 다음과 같습니다. https://dxr.mozilla.org/mozilla-central/source/layout/style/nsCSSScanner.cpp#1057 ...

    /**
     * Scan a unicode-range token.  These match the regular expression
     *
     *     u\+[0-9a-f?]{1,6}(-[0-9a-f]{1,6})?
     *
     * However, some such tokens are "invalid".  There are three valid forms:
     *
     *     u+[0-9a-f]{x}              1 <= x <= 6
     *     u+[0-9a-f]{x}\?{y}         1 <= x+y <= 6
     *     u+[0-9a-f]{x}-[0-9a-f]{y}  1 <= x <= 6, 1 <= y <= 6
    
  • 코드가 전체 간단하지만 하나 또는 두 가지가 포함되어있는 경우 보면 , 지나치게 복잡한, 불필요한, 또는 그냥 일반 잘못하지만 가지 이유로 그렇게 할 필요를, 당신은있는, 의심스러운 보이는 비트 바로 위에 코멘트를 넣어 당신 은 이유진술합니다 . 설명이 필요한 유일한 것은 상수가 특정 값을 갖는 이유입니다.

    /* s1*s2 <= SIZE_MAX if s1 < K and s2 < K, where K = sqrt(SIZE_MAX+1) */
    const size_t MUL_NO_OVERFLOW = ((size_t)1) << (sizeof(size_t) * 4);
    if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
        nmemb > 0 && SIZE_MAX / nmemb < size)
      abort();
    

25
즉, 모욕입니다, 4해야 CHAR_BIT / 2;-)
스티브 Jessop

@SteveJessop : CHAR_BITS16이고 sizeof (size_t)가 2 인 구현을 배제 할 수 있습니까? 그러나 size_t의 최대 값은 2 ^ 20입니다 [12 패딩 비트를 포함하는 size_t]?
supercat

2
@ supercat 나는 C99에서 분명히 배제하는 것을 보지 못했습니다. 즉, 그 예 기술적으로 잘못되었습니다. (약간 수정 버전) 오픈 BSD의에서 채취하는 일 reallocarray, 그리고 오픈 BSD는 일반적으로 발생하지 않는 가능성을 취사 믿지 않는 자신의 ABI.
zwol

3
@Zack : POSIX 가정을 중심으로 코드를 설계 한 경우 CHAR_BITS를 사용하면 코드가 8 이외의 값으로 작동 할 수 있다는 인상을 줄 수 있습니다.
supercat

2
@Zack : 정확한 너비의 부호없는 유형이 유용하려면의 의미를의 크기와 관계없이 정의해야합니다 int. 주어진대로 uint32_t x,y,z;의 의미는 (x-y) > z의 크기에 따라 다릅니다 int. 또한, 강력한 코드를 작성하도록 설계된 언어는 프로그래머가 계산이 유형의 범위를 초과 할 것으로 예상되는 유형과 자동으로 줄 바꿈해야하는 유형, 유형의 범위를 초과하는 계산이 트랩해야하는 유형과 계산해야하는 유형을 구별 할 수 있어야합니다. 유형의 범위를 초과 할 것으로 예상되지는 않지만 ...
supercat

61

주석으로 복잡한 코드를 설명 할 때 무엇이 ​​문제입니까?

Wikipedia 기사에 정의 된 것처럼 옳고 그름이 아니라 '모범 사례'에 대한 질문입니다 .

모범 사례는 다른 방법으로 달성 한 결과보다 일관된 결과를 일관되게 보여준 벤치 마크로 사용되는 방법 또는 기법입니다.

따라서 가장 좋은 방법은 먼저 코드를 개선하고 가능하지 않은 경우 영어를 사용하는 것입니다.

법은 아니지만 주석이 필요한 리팩토링 된 코드보다 리팩토링이 필요한 주석이 달린 코드를 찾는 것이 훨씬 흔합니다. 모범 사례는이를 반영합니다.


42
"댓글이 필요한 리팩토링 된 코드보다 리팩토링이 필요한 주석이 달린 코드를 찾는 것이 훨씬 일반적입니다"
Brandon

7
좋아, 그러나 그 의견은 얼마나 자주 : //This code seriously needs a refactor
Erik Reppen

2
물론 엄격한 과학적 연구에 의해 뒷받침되지 않는 소위 모범 사례는 단지 의견 일뿐입니다.
Blrfl

54

아름답고 완벽하게 제작되고 체계적이고 읽기 쉬운 코드가 작동하지 않는 날이 올 것입니다. 아니면 제대로 작동하지 않습니다. 또는 작동하지 않고 조정이 필요한 특별한 경우가 발생합니다.

이 시점에서 올바르게 작동하도록 변경하는 작업을 수행해야합니다. 특히 성능 문제가 있지만 작업중인 라이브러리, API, 웹 서비스, gem 또는 운영 체제 중 하나가 예상대로 작동하지 않는 시나리오에서 종종 그렇지 않은 제안을 할 수 있습니다. 반드시 우아하지는 않지만 반 직관적이거나 명백하지 않습니다.

왜 그 접근 방식을 선택했는지 설명 할 의견이 없다면 미래의 누군가 (그리고 누군가가 당신 일 수도 있습니다) 코드를 볼 가능성이 매우 높습니다. 수정 처럼 보이지 않기 때문에 더 읽기 쉽고 우아하며 실수로 수정 ​​프로그램을 취소합니다 .

모든 사람이 항상 완벽한 코드를 작성했다면 불완전하게 보이는 코드가 실제 세계의 까다로운 개입을 해결하는 것이 분명하지만 그것이 작동하는 방식은 아닙니다. 대부분의 프로그래머는 종종 혼란 스럽거나 다소 복잡한 코드를 작성하므로이 문제가 발생하면이를 정리하는 것이 자연스러운 경향입니다. 나는 내가 쓴 오래된 코드를 읽을 때마다 내 과거의 자아는 실제 바보 라고 맹세 합니다.

따라서 주석은 나쁜 코드에 대한 사과로 생각하지 않지만 왜 명백한 일을하지 않은지에 대한 설명으로 생각합니다. 데 // The standard approach doesn't work against the 64 bit version of the Frobosticate Library해당 라이브러리에 대한 코드 및 테스트의 그 부분에 관심을 지불 할 미래의 자신을 포함하여 미래의 개발자를 허용합니다. 물론, 소스 제어 커밋에 주석을 넣을 수도 있지만 사람들은 문제가 발생한 후에 만 ​​주석을 볼 것입니다. 코드를 변경할 때 코드 주석을 읽습니다.

항상 이론적으로 완벽한 코드를 작성해야한다고 말하는 사람들이 항상 실제 환경에서 프로그래밍 경험이 많은 사람은 아닙니다. 때로는 특정 수준으로 수행되는 코드를 작성해야하고 때로는 불완전한 시스템과 상호 운용해야합니다. 그렇다고해서 우아하고 잘 작성된 방법으로이 작업을 수행 할 수는 없지만 분명하지 않은 솔루션에는 설명이 필요합니다.

아무도 읽지 않는 취미 프로젝트 용 코드를 작성할 때 혼란스러워하는 부분에 대해서는 여전히 언급하고 있습니다. 6 개월 안에이 일을하는 방법을 완전히 잊었을 것입니다. 그것은 나쁜 코드에 대한 사과가 아니며 개인의 한계에 대한 인정입니다. 주석 처리되지 않은 상태로두면 앞으로 더 많은 일을 할 수 있습니다. 나는 미래의 자아가 지금 그것을 피할 수 있다면 불필요하게 무언가를 다시 배우기를 원하지 않습니다. 어떤 가치가 있을까요?


5
@ 크리스천인가? 첫 번째 줄은 분명히 그 진술을 언급하지만 그 이해를 넘어서는 조금 더 넓습니다.
glenatron

9
"내가 쓴 오래된 코드를 읽을 때마다 내 과거의 자아는 실제 바보라고 맹세한다." 4 년 동안 개발 경력을 쌓았는데 6 개월 이상 된 것을 볼 때마다 발생하는 것으로 나타났습니다.
Ken

6
대부분의 경우 가장 유익하고 유용한 과거 정보는 고려되었지만 결정된 사항과 관련이 있습니다. 누군가가 무언가를 위해 접근법 X를 선택하는 경우가 많으며 다른 접근법 Y가 더 좋아 보일 것입니다. 이러한 경우 중 일부에서 Y는 X보다 "거의"더 잘 작동하지만 극복 할 수없는 몇 가지 문제가 있습니다. 이러한 문제로 인해 Y가 회피 된 경우, 그러한 지식은 다른 사람들이 Y 접근법을 구현하려는 시도에 실패하는 것을 방지하는 데 도움이 될 수 있습니다.
supercat

4
매일 매일 진행중인 작업 주석도 많이 사용합니다. 장기적으로는 없지만 TODO 메모 또는 짧은 섹션을 삭제하면 다음에 할 일을 생각 나게하는 것이 유용 할 수 있습니다. 아침에 알림.
glenatron

1
@Lilienthal, 나는 마지막 파라가 있다고 생각하지 않는다 제한 -그는 프로젝트 상기 개인에 "... 나는 아직도 내가 혼란 찾을 부분을 주석 처리합니다."
와일드 카드

29

주석의 필요성은 코드의 추상화 수준에 반비례합니다.

예를 들어, 어셈블리 언어는 가장 실용적인 목적으로 주석없이 이해할 수 없습니다. 다음 은 피보나치 시리즈의 항을 계산하고 인쇄하는 작은 프로그램 에서 발췌 한 것입니다 .

main:   
; initializes the two numbers and the counter.  Note that this assumes
; that the counter and num1 and num2 areas are contiguous!
;
    mov ax,'00'                     ; initialize to all ASCII zeroes
    mov di,counter                  ; including the counter
    mov cx,digits+cntDigits/2       ; two bytes at a time
    cld                             ; initialize from low to high memory
    rep stosw                       ; write the data
    inc ax                          ; make sure ASCII zero is in al
    mov [num1 + digits - 1],al      ; last digit is one
    mov [num2 + digits - 1],al      ; 
    mov [counter + cntDigits - 1],al

    jmp .bottom         ; done with initialization, so begin

.top
    ; add num1 to num2
    mov di,num1+digits-1
    mov si,num2+digits-1
    mov cx,digits       ; 
    call    AddNumbers  ; num2 += num1
    mov bp,num2         ;
    call    PrintLine   ;
    dec dword [term]    ; decrement loop counter
    jz  .done           ;

    ; add num2 to num1
    mov di,num2+digits-1
    mov si,num1+digits-1
    mov cx,digits       ;
    call    AddNumbers  ; num1 += num2
.bottom
    mov bp,num1         ;
    call    PrintLine   ;
    dec dword [term]    ; decrement loop counter
    jnz .top            ;
.done
    call    CRLF        ; finish off with CRLF
    mov ax,4c00h        ; terminate
    int 21h             ;

주석이 있어도 이해하기가 매우 복잡 할 수 있습니다.

현대의 예 : 정규 표현식은 추상화 구조가 매우 낮은 경우가 많습니다 (소문자, 숫자 0, 1, 2, 줄 바꿈 등). 그들은 아마도 샘플 형식의 주석이 필요할 것입니다 (IIRC의 밥 마틴은 이것을 인정합니다). 다음은 HTTP (S) 및 FTP URL과 일치 해야하는 정규 표현식입니다.

^(((ht|f)tp(s?))\://)?(www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|m
+il|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(/($|[a-zA-Z0-9\.
+\,\;\?\'\\\+&amp;%\$#\=~_\-]+))*$

언어가 추상화 계층을 진행함에 따라 프로그래머는 연상적인 추상화 (변수 이름, 함수 이름, 클래스 이름, 모듈 이름, 인터페이스, 콜백 등)를 사용하여 내장 문서를 제공 할 수 있습니다. 이것을 이용하지 않고 그것을 주석 처리하여 주석을 달아주는 것은 게으르고, 관리자에게 불쾌하고 무례합니다.

내가 생각하고 C에서 수치 조리법 을 대부분 그대로 번역 C ++에서 수치 조리법 으로 시작 내가 추론, 수치 조리법 모든 변수 (FORTAN에서) a, aa, b, c, cc각 버전을 유지, 등. 알고리즘은 정확했지만 언어가 제공 한 추상화를 활용하지 않았습니다. 그리고 그들은 나를 떼어 놓았다. Dr. Dobbs 기사-Fast Fourier Transform의 샘플 :

void four1(double* data, unsigned long nn)
{
    unsigned long n, mmax, m, j, istep, i;
    double wtemp, wr, wpr, wpi, wi, theta;
    double tempr, tempi;

    // reverse-binary reindexing
    n = nn<<1;
    j=1;
    for (i=1; i<n; i+=2) {
        if (j>i) {
            swap(data[j-1], data[i-1]);
            swap(data[j], data[i]);
        }
        m = nn;
        while (m>=2 && j>m) {
            j -= m;
            m >>= 1;
        }
        j += m;
    };

    // here begins the Danielson-Lanczos section
    mmax=2;
    while (n>mmax) {
        istep = mmax<<1;
        theta = -(2*M_PI/mmax);
        wtemp = sin(0.5*theta);
        wpr = -2.0*wtemp*wtemp;
        wpi = sin(theta);
        wr = 1.0;
        wi = 0.0;
        for (m=1; m < mmax; m += 2) {
            for (i=m; i <= n; i += istep) {
                j=i+mmax;
                tempr = wr*data[j-1] - wi*data[j];
                tempi = wr * data[j] + wi*data[j-1];

                data[j-1] = data[i-1] - tempr;
                data[j] = data[i] - tempi;
                data[i-1] += tempr;
                data[i] += tempi;
            }
            wtemp=wr;
            wr += wr*wpr - wi*wpi;
            wi += wi*wpr + wtemp*wpi;
        }
        mmax=istep;
    }
}

추상화에 대한 특별한 경우로서, 모든 언어에는 특정 공통 작업 (C에서 동적 링크 목록 삭제)에 대한 관용어 / 표준 코드 스 니펫이 있으며, 모양에 관계없이 문서화해서는 안됩니다. 프로그래머는 비공식적으로 언어의 일부이므로이 관용구를 배워야합니다.

따라서 피할 수없는 낮은 수준의 빌딩 블록으로 작성된 비 아이디 오 매틱 코드는 주석이 필요합니다. 그리고 이것은 필요한 것보다 적은 WAAAAY가 필요합니다.


1
어셈블리 언어로 다음과 같은 줄을 작성해서는 안됩니다 dec dword [term] ; decrement loop counter. 반면, 어셈블리 언어 예제에서 누락 된 것은 다음 코드 블록이 수행하는 작업을 설명하는 각 "코드 단락"앞의 주석입니다. 이 경우 주석은 일반적으로 의사 코드의 단일 행 (예 : ;clear the screen실제로 화면을 지우는 데 걸리는 7 행) 과 같습니다 .
Scott Whitlock

1
예, 어셈블리 샘플에 불필요한 의견을 고려할 사항이 있지만 공정하게 말하자면 '좋은'어셈블리 스타일을 나타냅니다. 한 두 줄의 단락 프롤로그가 있어도 코드를 실제로 따르기가 어려울 수 있습니다. FFT 예제보다 ASM 샘플을 더 잘 이해했습니다. 저는 대학원에서 C ++로 FFT를 프로그래밍했는데 이런 식으로 보이지 않았지만 STL, 이터레이터, 펑터를 사용하여 몇 가지 메소드 호출을 사용했습니다. 모 놀리 식 함수만큼 빠르지는 않지만 읽기가 훨씬 쉽습니다. NRinC ++ 샘플과 대조하기 위해 추가하려고합니다.
Kristian H

당신은 의미 했습니까 ^(((ht|f)tps?)\:\/\/)?(www\.)*[a-zA-Z0-9\-\.]+\.(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(\/($|[a-zA-Z0-9\.\,\;\?\'\\\+&%\$#\=~_\-]+))*$? 숫자 주소를 알고 있어야합니다.
izabera

내 요점은 다소 낮습니다. 매우 낮은 수준의 추상화로 작성된 일부 내용은 읽거나 확인하기가 쉽지 않습니다. 주석 (그리고 너무 멀어지지 않기 위해 TESTS)은 유용 할 수 있으며 해를 끼치 지 않습니다. 동시에, 사용 가능한 높은 수준의 추상화 (: alpha : : num : 사용 가능한 경우)를 사용하지 않으면 높은 수준의 추상화를 사용하는 것보다 좋은 주석으로도 이해하기가 어렵습니다.
Kristian H

3
+1 : "The need for comments is inversely proportional to the abstraction level of the code." 거의 모든 것을 요약합니다.
Gerrat

21

코드의 주석에 문제가 있다고 생각하지 않습니다. 내 의견에 의견이 어떻게 든 나쁜 아이디어는 일부 프로그래머가 일을 너무 많이 수행했기 때문입니다. 이 산업에는 특히 극단적 인 견해를 향한 많은 악대가 있습니다. 어딘가에 주석 처리 된 코드가 잘못된 코드와 동일 해졌으며 왜 그런지 잘 모르겠습니다.

주석에는 문제가 있습니다. 너무 자주 발생하지 않는 참조 코드를 업데이트 할 때 업데이트를 유지해야합니다. 위키에 관한 자료는 코드에 대한 철저한 문서화에 더 적합한 자료입니다. 주석없이 코드를 읽을 수 있어야합니다. 버전 제어 또는 개정 정보는 코드 변경 사항을 설명하는 위치에 있어야합니다.

그러나 위의 어느 것도 주석 사용을 무효화하지 않습니다. 우리는 이상적인 세상에 살고 있지 않으므로 어떤 이유로 든 위의 어떤 것이라도 실패하면, 나는 약간의 의견을 가지고 싶습니다 .


18

나는 당신이 그가 말하는 것에 대해 너무 많이 읽고 있다고 생각합니다. 불만 사항에는 두 가지 부분이 있습니다.

(1) 복잡한 알고리즘 또는 (2) 길고 복잡한 코드 조각을 설명 주석으로 설명하면 무엇이 문제입니까?

(1) 불가피하다. 마틴이 당신과 동의하지 않을 것 같아요. 빠른 역 제곱근 과 같은 것을 작성하는 경우 "사악한 부동 소수점 비트 수준 해킹"일지라도 주석이 필요합니다. DFS 또는 이진 검색과 같은 간단한 것을 제외하고는 코드를 읽는 사람이 해당 알고리즘에 경험이 없을 가능성이 높으므로 해당 내용에 대한 의견에는 적어도 언급이 있어야한다고 생각합니다.

그러나 대부분의 코드는 (1)이 아닙니다. 수동 롤 뮤텍스 구현, 라이브러리 지원이 열악한 선형 대수 연산, 회사의 연구 그룹에게만 알려진 새로운 알고리즘을 사용하는 소프트웨어는 거의 사용하지 않을 것입니다. 대부분의 코드는 라이브러리 / 프레임 워크 / API 호출, IO, 상용구 및 단위 테스트로 구성됩니다.

이것은 Martin이 말하고있는 일종의 코드입니다. 그리고 그는이 장의 맨 위에있는 Kernighan과 Plaugher의 인용문으로 당신의 질문을 다룹니다.

잘못된 코드에 대해서는 언급하지 말고 다시 작성하십시오.

코드에 길고 복잡한 섹션이있는 경우 코드를 깨끗하게 유지하지 못했습니다 . 이 문제에 대한 최선의 해결책은 파일의 맨 위에 단락 길이의 주석을 작성하여 미래 개발자가 문제를 해결하는 데 도움이되지 않는 것입니다. 가장 좋은 해결책은 다시 작성하는 것입니다.

그리고 이것이 바로 마틴의 말입니다.

주석을 올바르게 사용하는 것은 코드에 자신을 표현하지 못한 것을 보상하는 것입니다 ... 주석은 항상 실패입니다. 우리는 항상 그들없이 자신을 표현하는 방법을 알 수 없기 때문에 그것들을 가져야하지만, 그것들의 사용이 축하의 원인이 아닙니다.

이것은 당신의 (2)입니다. Martin은 길고 복잡한 코드에는 주석이 필요하다는 데 동의하지만, 코드를 작성한 프로그래머의 어깨에 해당 코드에 대한 책임을지고있다. 그는 다음과 같이 주장한다.

주석이 적은 명확하고 표현적인 코드는 주석이 많고 복잡한 코드보다 훨씬 우수합니다. 엉망진창을 설명하는 의견을 작성하는 데 시간을 허비하지 말고 엉망진창을 청소하십시오.


3
내가 작업하고있는 개발자라면 "제곱 부동 소수점 비트 수준 해킹"을 작성하여 빠른 제곱근 알고리즘을 설명하면 나에게 대화를 나눌 수 있습니다. 그들이 더 유용한 어딘가에 대한 참조를 포함하는 한 나는 행복 할 것입니다.
Michael Anderson

8
나는 한 가지 방식으로 동의하지 않는다-어떻게 나쁜 일이 더 빠른지 설명하는 의견. 다시는 손대지 않을 가능성이있는 일부 코드 (대부분의 코드는 짐작할 수 있음)를 감안할 때 주석은 큰 리팩토링보다 더 나은 비즈니스 솔루션입니다. 완벽하게 이해할 수있는 완벽한 코드는 우리에게 제공되지 않습니다.
gbjbaanb

2
@trysis haha, 그렇습니다. 그러나 프로그래머가 책임지고 비즈니스맨이 아닌 세계에서는 완벽하게 헛된 노력으로 끊임없이 리팩터링 된 코드베이스를 금으로 도금하므로 결코 배송되지 않습니다.
gbjbaanb

4
@PatrickCollins 웹에서 읽은 거의 모든 것이 처음에 올바르게 수행하는 것입니다. 엉망진창 수정에 관한 기사를 쓰고 싶어하는 사람은 거의 없습니다! 물리학 자들은 Comp.Scientists 말 "... 완벽한 구형을 주어"말 "그린 필드 개발 주어진 ..."
gbjbaanb

2
가장 좋은 해결책은 주어진 시간을 무한정으로 다시 쓰는 것입니다. 그러나 다른 사람의 코드 기반, 전형적인 회사 기한 및 현실을 감안할 때; 때로는 가장 좋은 방법은 주석을 달고 TODO : 리 팩터를 추가 한 후 리팩터링을 다음 릴리스로 가져 오는 것입니다. 그리고 그 수정은 어제 지금 완료해야했습니다. 리팩토링에 대한이 이상주의적인 이야기는 작업장에서 실제로 작동하는 방식을 설명하지 않습니다. 때로는 기존의 품질이 낮은 코드를 수정하는 데 우선 순위가 높고 마감일이 충분할 때가 있습니다. 그것이 바로 그 방법입니다.
hsanders

8

설명이 복잡한 복잡한 알고리즘이나 길고 복잡한 코드를 설명하는 데 무엇이 문제가 있습니까?

그런 것은 없습니다. 작업을 문서화하는 것이 좋습니다.

즉, 여기에는 잘못된 이분법이 있습니다. 깨끗한 코드 작성 대 문서화 된 코드 작성-이 두 가지는 반대입니다.

"복잡한 코드는 주석 처리되어있는 한 괜찮습니다"라고 생각하는 대신 복잡한 코드를 단순화하고 더 간단한 코드로 추상화하는 데 중점을 둡니다.

코드는 간단 하고 문서화 되어야합니다 .

이 방법을 사용하면 다른 개발자 (자신 포함)가 전체 알고리즘을 한 줄씩 읽어야 할 필요가 없으며, 평범한 영어로 작성한 친근한 설명 주석을 읽을 수 있습니다.

참된. 그렇기 때문에 모든 공개 API 알고리즘을 문서에 설명해야합니다.

따라서 부분적으로 사람이 읽을 수있는 프로그래밍 언어로 작성된 복잡한 코드를 작성한 후, 친숙하고 이해하기 쉬운 영어로 코드의 작동을 설명하는 설명적이고 간결한 설명을 추가해보십시오.

이상적으로 복잡한 코드를 작성한 후에는 다음을 수행해야합니다 (전체 목록이 아님).

  • 초안으로 간주하십시오 (예 : 다시 작성 계획)
  • 알고리즘 진입 점 / 인터페이스 / 역할 / 등을 공식화합니다 (인터페이스의 분석 및 최적화, 추상화 공식화, 전제 조건, 사후 조건 및 부작용 및 문서 오류 사례).
  • 시험 쓰기
  • 정리 및 리팩터링

이 단계들 중 어느 것도 쉬운 일이 아니며 (즉, 각각 몇 시간이 걸릴 수 있음),이를 수행하는 것에 대한 보상은 즉각적인 것이 아닙니다. 따라서, 이러한 단계는 (거의) 항상 절충됩니다 (개발자 코너, 관리자 코너, 마감일, 시장 제약 / 기타 실제 상황, 경험 부족 등).

[...] 일부 알고리즘은 복잡합니다. 따라서 한 줄씩 읽을 때 이해하기 어렵습니다.

API의 기능을 파악하기 위해 구현을 읽는 데 의존해서는 안됩니다. 그렇게 할 때 (인터페이스 대신) 구현을 기반으로 클라이언트 코드를 구현하고 있으며 이는 모듈 결합이 이미 지옥에 맞았 음을 의미하며 , 작성하는 모든 새로운 코드 줄마다 문서화되지 않은 종속성을 잠재적으로 도입하고 있습니다. 이미 기술 부채를 추가하고 있습니다.

일반적인 연산에 대한 몇 줄의 주석으로 복잡한 알고리즘을 설명하는 것이 실제로 그렇게 나쁜가요?

아니요-좋습니다. 그래도 몇 줄의 주석을 추가하는 것만으로는 충분하지 않습니다.

주석으로 복잡한 코드를 설명 할 때 무엇이 ​​문제입니까?

피할 수 있다면 복잡한 코드를 가져서는 안된다는 사실.

복잡한 코드를 피하려면 인터페이스를 공식화하고 구현에 소비하는 것보다 API 설계에 ~ 8 배 이상을 소비하고 (Stepanov는 구현에 비해 인터페이스에 10 배 이상 지출을 제안했습니다) 지식을 바탕으로 프로젝트를 개발합니다. 단지 알고리즘을 작성하는 것이 아니라 프로젝트를 작성하고 있습니다.

프로젝트에는 API 문서, 기능 문서, 코드 / 품질 측정, 프로젝트 관리 등이 포함됩니다. 이러한 프로세스 중 단 한 번의 빠른 단계도 수행 할 수 없습니다 (모두 시간이 걸리고, 예측 및 계획이 필요하며, 주기적으로 돌아와서 세부 사항을 수정하여 수정 / 완료해야합니다).


3
"API의 기능을 파악하기 위해 구현을 읽는 데 의존해서는 안됩니다." 때때로 이것은 당신이 사용하려는 업스트림에 의해 당신에게 영향을 미칩니다. "공급 업체의 주장에도 불구하고 simpleAPI ()가이 하드웨어에서 제대로 작동하지 않기 때문에 다음과 같은 추악한 Heath Robinson 코드가 존재합니다."
pjc50

6

다른 개발자 (자신 포함)가 알고리즘을 수행하기 위해 전체 알고리즘을 한 줄씩 읽어야하는 대신 평범한 영어로 작성한 친근한 설명 주석을 읽을 수 있습니다.

나는 이것을 "코멘트"의 약간의 남용으로 간주 할 것이다. 프로그래머가 전체 알고리즘 대신 무언가를 읽고 싶다면 이것이 함수 문서입니다. 함수 문서는 실제로 소스의 주석에 나타날 수 있지만 (문서 도구로 추출한 경우도 있음) 구문 상으로는 컴파일러에 관한 한 주석이지만 별도의 목적으로 별도의 항목을 고려해야합니다. "댓글이 부족해야한다"는 것이 반드시 "문서가 부족해야 함"또는 "저작권 고지가 부족해야 함"을 의미하는 것은 아닙니다!

사람이 읽을 기능의 댓글은 뿐만 아니라 코드. 따라서 코드에 이해하기 어려운 몇 줄이 있고 이해하기 쉽지 않은 경우 독자가 해당 줄의 자리 표시 자로 사용할 때 주석이 유용합니다. 독자가 일반적인 요지를 얻으려고 할 때 매우 유용 할 수 있지만 몇 가지 문제가 있습니다.

  • 주석은 반드시 사실 일 필요는 없지만 코드는 기능을 수행합니다. 그래서 독자는 당신의 말을 받아들이고 있으며 이것은 이상적이지 않습니다.
  • 독자는 아직 코드 자체를 이해하지 못하므로 나중에 다시 돌아올 때까지 코드를 수정하거나 재사용 할 자격이 없습니다. 어떤 경우에 그들은 무엇을 읽고 있습니까?

예외가 있지만 대부분의 독자는 코드 자체를 이해해야합니다. 대체하지 말고 도움을주기 위해 주석을 작성해야하므로 일반적으로 주석이 "왜 그렇게하는지"라고 말해야합니다. 다음 몇 줄의 코드에 대한 동기를 알고있는 독자는 자신이하는 일과 방법을 더 잘 볼 수 있습니다.


5
주석을 작성하는 데 유용한 한 가지 장소 : 과학 코드에서는 많은 변수를 포함하여 계산이 매우 복잡한 경우가 많습니다. 프로그래머의 건강을 위해 변수 이름을 짧게 유지하는 것이 합리적이므로 이름 대신 수학을 볼 수 있습니다. 그러나 그것은 독자를 이해하기가 정말로 어렵습니다. 따라서 무슨 일이 일어나고 있는지에 대한 간단한 설명 (또는 저널 기사의 방정식 참조 등)이 실제로 도움이 될 수 있습니다.
naught101

1
@ naught101 : 그렇습니다. 특히 언급 한 논문에서 단일 문자 변수 이름을 사용했을 것입니다. 동일한 이름을 사용하는 경우 코드가 실제로 논문을 따르는 지 확인하는 것이 더 쉽지만, 이는 설명이 필요하지 않은 코드의 목표와 충돌합니다 ( 대신 논문 에서 설명 ). 이 경우 각 이름이 정의되어 실제로 의미하는 바가있는 주석은 의미있는 이름을 대체합니다.
Steve Jessop

1
코드에서 특정 항목을 검색 할 때 (이 특정 사례가 처리되는 곳은 어디입니까?), 코드의 단락을 읽고 이해하여 결국 그 위치가 아님을 발견하고 싶지 않습니다. 다음 단락의 내용을 한 줄에 요약 한 설명이 필요합니다. 이렇게하면 문제와 관련된 코드 부분을 신속하게 찾고 관심없는 세부 사항을 건너 뛸 수 있습니다.
Florian F

1
@FlorianF : 전통적인 응답은 변수와 함수 이름이 코드의 내용을 대략적으로 나타내야하므로 찾고있는 내용이 아닌 내용을 확실히 살펴볼 수 있다는 것입니다. 나는 이것이 항상 성공하지는 않는다는 것에 동의하지만, 검색이나 탈지 읽기를 돕기 위해 모든 코드에 주석을 달아야 한다고 생각하지는 않습니다 . 그러나 당신이 옳습니다. 누군가가 당신의 코드를 읽고 있고 (합법적으로) 이해할 필요가없는 경우입니다.
Steve Jessop

2
@Snowman 사람들은 변수 이름으로 그렇게 할 수 있습니다. 변수 listOfApples에 바나나 목록이 포함 된 코드를 보았습니다. 누군가가 사과 목록을 처리하는 코드를 복사하여 변수 이름을 변경하지 않고도 바나나에 맞게 수정했습니다.
Florian F

5

종종 복잡한 일을해야합니다. 나중에 이해하기 위해 문서화하는 것이 옳습니다. 때때로이 문서의 올바른 위치는 코드에 있으며 문서는 코드를 최신 상태로 유지할 수 있습니다. 그러나 별도의 문서를 고려할 가치가 있습니다. 또한 다른 사람에게 발표하기가 쉽고 다이어그램, 컬러 사진 등이 있습니다. 그런 다음 주석은 다음과 같습니다.

// This code implements the algorithm described in requirements document 239.

또는 심지어

void doPRD239Algorithm() { ...

확실히 사람들은 MatchStringKnuthMorrisPrattor encryptAES또는 이라는 함수에 만족 partitionBSP합니다. 더 모호한 이름은 주석으로 설명 할 가치가 있습니다. 또한 서지 데이터와 알고리즘을 구현 한 논문에 대한 링크를 추가 할 수도 있습니다.

알고리즘이 복잡하고 참신하고 명확하지 않은 경우, 회사 내부 순환에만 해당 되더라도 확실히 가치가있는 문서입니다. 문서를 잃어 버릴 염려가 있으면 문서를 소스 컨트롤로 확인하십시오.

관료 주의자만큼 알고리즘 적이 지 않은 또 다른 범주의 코드가 있습니다. 다른 시스템에 대한 매개 변수를 설정하거나 다른 사람의 버그와 상호 운용해야합니다.

/* Configure the beam controller and turn on the laser.
The sequence is timing-critical and this code must run with interrupts disabled.
Note that the constant 0xef45ab87 differs from the vendor documentation; the vendor
is wrong in this case.
Some of these operations write the same value multiple times. Do not attempt
to optimise this code by removing seemingly redundant operations.
*/

2
내부 알고리즘 후에 함수 / 메소드 이름 지정에 대해 논쟁하고 싶습니다. 대부분 사용 된 메소드는 내부 관심사 여야합니다. 반드시 사용 된 메소드로 함수의 맨 위를 문서화하지만 전화하지 마십시오 doPRD239Algorithm. 알고리즘을 찾아 보지 않고 기능에 대해 아무 것도, 이유 MatchStringKnuthMorrisPrattencryptAES작업은 그들이하는 일에 대한 설명으로 시작한 다음 방법론에 대한 설명으로 이어지기 때문입니다.
scragar

5

나는 그것을 읽을 수는 있지만이 어디 잊지 입니다 코드에 표시되어야하고 주석으로 어떻게 나타날 것을 사이에 선명하고 명확한 선.

알고리즘이 아니라 의도를 주석 해야한다고 생각합니다 . 즉 , 당신이하는 일이 아니라 당신이하려는 일에 대해 언급하십시오 .

예를 들면 다음과 같습니다.

// The getter.
public <V> V get(final K key, Class<V> type) {
  // Has it run yet?
  Future<Object> f = multitons.get(key);
  if (f == null) {
    // No! Make the task that runs it.
    FutureTask<Object> ft = new FutureTask<Object>(
            new Callable() {

              public Object call() throws Exception {
                // Only do the create when called to do so.
                return key.create();
              }

            });
    // Only put if not there.
    f = multitons.putIfAbsent(key, ft);
    if (f == null) {
      // We replaced null so we successfully put. We were first!
      f = ft;
      // Initiate the task.
      ft.run();
    }
  }
  try {
    /**
     * If code gets here and hangs due to f.status = 0 (FutureTask.NEW)
     * then you are trying to get from your Multiton in your creator.
     *
     * Cannot check for that without unnecessarily complex code.
     *
     * Perhaps could use get with timeout.
     */
    // Cast here to force the right type.
    return (V) f.get();
  } catch (Exception ex) {
    // Hide exceptions without discarding them.
    throw Throwables.asRuntimeException(ex);
  }
}

여기에는 각 단계의 수행 상태를 나타내려는 시도가 없으며 모든 상태가 수행 해야하는 것입니다.

추신 : 내가 언급 한 출처를 찾았습니다.- 코딩 공포 : 코드는 방법을 알려줍니다.


8
첫 번째 코멘트 : 아직 실행 되었습니까? 아직 무엇을 실행 했습니까? 다른 의견도 마찬가지입니다. 코드의 기능을 모르는 사람에게는 쓸모가 없습니다.
gnasher729

1
@ gnasher729이 - 문맥 촬영은 거의 모든 코멘트는 쓸모가있을 것이다 -이 코드 표시 주석을 추가하는 데모입니다 의도 하지는 않고 오히려 설명 . 그것이 당신을 위해 아무것도하지 않는 것이 유감입니다.
OldCurmudgeon

2
해당 코드의 관리자에게는 컨텍스트가 없습니다. 코드의 기능을 파악하는 것은 특히 어렵지 않지만 주석은 도움이되지 않습니다. 의견을 쓰면 시간을내어 글을 쓸 때 집중하십시오.
gnasher729

BTW- 아직 실행 중 주석은를 참조하고 있으며 Future, get()그 다음에 검사를 수행 null하면 프로세스가 아닌 의도를Future 문서화하여 이미 실행 되었는지 여부 를 감지 함을 나타냅니다 .
OldCurmudgeon

1
@ OldCurmudgeon : 귀하의 답변은 내가 생각한 것에 가깝습니다.이 의견을 요점의 예로서 추가 할 것입니다. 깨끗한 코드를 설명하기 위해 주석이 필요하지는 않지만, 주석이 다른 방법으로 코딩이 수행 된 이유를 설명하는 것이 좋습니다. 제한된 경험에서 주석은 코드가 작동하는 데이터 세트 또는 코드가 적용 할 비즈니스 규칙의 특이성을 설명하는 데 종종 유용합니다. 데이터에 대한 가정이 잘못되어 버그가 발생한 경우 버그를 수정하기 위해 추가 된 코드를 주석 처리하는 것이 좋은 예입니다.
랜달 스튜어트

4

그러나 우리는 그것이 충분하지 않다는 것을 알고 있습니다.

정말? 언제부터?

이름이 좋은 잘 설계된 코드는 대부분의 경우에 충분합니다. 주석 사용에 대한 논쟁은 잘 알려져 있고 문서화되어 있습니다 (참조).

그러나 이것들은 다른 것들과 같은 지침입니다. 드문 경우이지만 (제 경험상 약 2 년에 한 번씩) 작은 가독성 함수 (성능 또는 응집력 요구로 인해)로 리팩토링 할 때 상황이 악화되는 경우가 있습니다. (및 모범 사례를 위반하는 이유).


7
충분하지 않다는 것을 알고 있습니다.
Florian F

2
언제부터? 분명히, 당신은 이미 그것에 대한 답을 알고 있습니다. "이름이 좋은 잘 설계된 코드는 대부분 의 경우에 충분합니다 ." 따라서 소수의 경우에는 충분하지 않을 수 있습니다.
Ellesedil

3
나는 2 년에 한 번 이상 주석을 추가 한 다른 사람들의 코드를 해독하려고 노력하고 있습니다.
오우거 시편

@ OgrePsalm33-작은 방법이 있고 좋은 이름을 사용합니까? 주석과 관계없이 잘못된 코드는 잘못되었습니다.
Telastyn

2
@Telastyn 불행히도, 큰 코드 기반에서 작업 할 때 "작은"방법과 "좋은"이름은 각 개발자의 주관적입니다. Flarbigan 그래픽 처리 알고리즘 코드를 7 년 동안 작성하는 개발자는 그와 유사한 개발자에게 완벽하게 명확한 내용을 쓸 수 있지만 지난 4 년간 Perbian 그리드 인프라 코드를 개발 한 새로운 사람에게는 암호가 될 것입니다. 그런 다음 2 주 후에 Flarbigan 전문가가 종료됩니다.
오우거 시편

2

코드의 주된 목적은 컴퓨터가 무언가를하도록 명령하는 것이므로 주석을 실행할 수 없기 때문에 좋은 주석은 좋은 코드를 대신 할 수 없습니다.

즉, 소스의 주석은 다른 프로그래머 (자신 포함)를위한 한 가지 형태의 문서입니다. 주석이 코드가 모든 단계에서 수행하는 것보다 더 추상적 인 문제에 관한 것이라면 평균보다 우수합니다. 추상화 수준은 사용중인 도구에 따라 다릅니다. 어셈블리 언어 루틴과 함께 제공되는 주석은 일반적으로이 APL보다 낮은 수준의 "추상"을 갖습니다 A←0⋄A⊣{2⊤⍵:1+3×⍵⋄⍵÷2}⍣{⍺=A+←1}⎕. 아마도 그것이 해결하려는 문제에 대한 의견을 가질만한 가치가 있다고 생각합니다.


2

코드가 사소한 경우 설명 주석이 필요하지 않습니다. 코드가 사소하지 않다면 설명 주석도 사소하지 않을 것입니다.

이제 사소한 자연어의 문제점은 많은 사람들이 읽거나 쓰는 데 능숙하지 않다는 것입니다. 귀하의 서면 의사 소통 기술은 훌륭하지만, 언어를 잘 모르는 사람은 귀하의 말을 오해 할 수 있습니다.

잘못 해석 할 수없는 자연어를 작성하기 위해 열심히 노력하면 법적인 문서와 같은 결과를 낳게됩니다.

코드는 논리에 대한 가장 간결한 설명이어야하며, 컴파일러와 플랫폼이 최종적으로 언급하기 때문에 코드의 의미에 대해 많은 논쟁이 없어야합니다.

개인적으로 나는 당신이 절대로 의견을 쓰지 말라고 말하지 않을 것입니다. 코드에 주석이 필요한 이유와 해결 방법을 고려해야합니다. 이것은 여기에 대한 답변에서 일반적인 주제 인 것 같습니다.


"사람이 영어를 훨씬 더 빨리 이해할 수 있기 때문에 (작업이 사소하지 않은 한) 같은 의미의 코드를 이해할 수 있다는 생각에 정확히 동의하지 않았습니다." 항상 덜 모호하고 간결합니다.
stephenbayer

0

아직 언급되지 않은 한 가지 점은 언어가 여러 목적으로 특정 구문을 사용하는 경우 코드의 기능을 정확하게 주석 처리하는 것이 도움이 될 수 있다는 것입니다. 예를 들어 모든 변수가 유형이라고 가정하면 float다음을 고려하십시오.

f1 = (float)(f2+f3); // Force result to be rounded to single precision
f4 = f1-f2;

a float를 명시 적으로 캐스팅 float하면 결과가 단 정밀도로 반올림됩니다. 따라서 주석은 단순히 코드의 기능을 말하는 것으로 볼 수 있습니다. 반면에이 코드를 다음과 비교하십시오.

thing.someFloatProperty = (float)(f2*0.1); // Divide by ten

여기서 캐스트의 목적은 컴파일러가 가장 효율적인 계산 방법 (f2 / 10)에서 스 쿼킹을 방지하는 것입니다 (f2 / 10) [0.1f를 곱하는 것보다 더 정확하고 대부분의 컴퓨터에서는 10.0f로 나누는 것보다 빠릅니다].

주석이 없으면 이전 코드를 검토 한 사람이 캐스트가 컴파일러의 스 쿼킹을 방지하고 필요하지 않다는 잘못된 생각으로 추가되었다고 생각할 수 있습니다. 실제로, 캐스트는 언어 사양에서 말하는 것과 정확히 일치하는 목적을 수행합니다. 결과를 높은 정밀도로 유지하는 것보다 반올림이 더 비싼 기계에서도 계산 결과를 단 정밀도로 반올림해야합니다. 캐스트 대상 float이 여러 가지 다른 의미와 목적을 가질 수 있다는 점을 감안할 때 특정 시나리오에서 어떤 의미를 의도하는지에 대한 설명을 주석으로 지정하면 실제 의미가 의도와 일치하는지 명확하게 알 수 있습니다.


두 번째 예제를 살펴본 J. Random Programmer는 원래 프로그래머가 'f'를 입력하는 것을 잊어 버린 것이 아니라 좋은 이유로 상수가 0.1로 작성되었음을 알 수 있습니다.
David K

특히 디버깅 중에는 어떤 이유로 든 좋은 이유가 있다고 가정하지 않습니다.
gnasher729

@DavidK : 두 번째 예제 코드의 목적은 첫 번째 코드와 대조하는 것이 었습니다. 두 번째 코드에서 프로그래머의 의도는 아마도 그것이 할 수 someFloatProperty있는 것의 가장 정확한 표현 을 가지고있을 것입니다 f2/10. 따라서 두 번째 캐스트의 주요 목적은 단순히 코드를 컴파일하는 것 입니다. 그러나 첫 번째 예에서는 피연산자가 이미 있으므로 일반적인 목적으로 (캐스트 시간 유형을 다른 것으로 변경) 캐스팅이 필요하지 않습니다 float. 이 의견은 캐스트 2 차 목적 (반올림)에 필요하다는 것을 분명히하는 역할을 합니다.
supercat

나는 (float)두 번째 예에서 캐스트에 대해 언급 할 필요가 없다는 개념에 동의합니다 . 문제는 문자 상수에 관한 것 0.1입니다. "텍스트의 다음 단락에서) 우리가 왜 0.1"0.1f를 곱하는 것보다 더 정확합니다 "라고 썼는지 설명했습니다. 나는 그것들 이 의견에 있어야 할 단어 라고 제안하고 있습니다.
David K

@DavidK : 0.1f가 용납 할 수 없을 정도로 정확하지 않다는 것을 알면 분명히 의견을 포함하고 정밀도의 손실이 허용되고 0.1f가 실제로 0.1보다 훨씬 빠르다는 것을 알고 있으면 0.1f를 사용 합니다. 나는 사실이 그런 것들 중 하나를 알 수없는 경우, 내 코딩 습관을 사용하는 것입니다 선호 double상수 또는 그 값으로 표현할 수 없습니다 중간 계산을 위해 float[짜증나는 명시 적으로 더블 - 투 - 플로트 캐스트, 게으름을 필요로 언어 불구하고 float속도를 위해서가 아니라 성가심을 최소화하기 위해 상수 를 사용하도록 강요 할 수있다 ].
supercat

-1

코드의 기능을 설명하는 주석은 복제 형식입니다. 코드를 변경 한 후 주석 업데이트를 잊어 버리면 혼동 될 수 있습니다. 나는 그들을 사용하지 말고 신중하게 사용하십시오. 나는 밥 삼촌 맥심에 가입했다 : "코드가 말할 수없는 것만 언급하라".

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.