10. Organization and documentation

프로그래밍에 있어 코드의 구조화와 문서화는 중요하다. 불충분한 주석은 코드를 읽는 이의 이해력을 떨어트린다. 과도하거나 틀린 주석은 읽는 이에게 방해가 된다.

Takeaway 2.10.0.1. (what) 함수 인터페이스는 무엇이 이루어지는지를 표현한다.

Takeaway 2.10.0.2. (what for) 함수 인터페이스 주석은 함수의 목적을 문서화한다.

Takeaway 2.10.0.3. (how) 함수 코드는 함수가 어떻게 구성되는지를 이야기한다.

Takeaway 2.10.0.4. (in which manner) 코드 주석은 함수의 세부 사항이 어떻게 구현되는지를 설명한다.

Takeaway 2.10.0.5. 인터페이스와 구현을 분리하라.

C에서 이것은 .h로 끝나는 헤더 파일과 .c로 끝나는 번역 단위를 분리함으로써 이루어진다.

Takeaway 2.10.0.6. 인터페이스를 문서화하고 구현을 설명하라.

10.1. Interface documentation.

C는 Java처럼 내장 문서화 표준이 있지는 않으나, doxygen 등이 많이 쓰인다.

Takeaway 2.10.1.1. 인터페이스를 완전히 문서화하라.

Takeaway 2.10.1.2. 의미적 연결 고리가 존재하는 코드를 하나의 단위로 묶어라.

10.2. Implementation.

Takeaway 2.10.2.1. 글을 쓰듯이 구현하라.

Takeaway 2.10.2.2. 제어 흐름은 명확해야 한다.

break, continue, return, goto 등이 if, switch 문과 뒤섞이면 제어 흐름을 깬다. a–>0, !!++*p– 등의 복잡한 표현은 가독성을 떨어트린다.

10.2.1. Macros.

매크로는 텍스트 치환으로, 남용될 시 제어 흐름을 불명확하게 한다.

Takeaway 2.10.2.3. 매크로가 제어 흐름을 예상치 못한 방향으로 바꾸면 안 된다.

이런 식으로 코딩하지 마라.

#define begin {
#define end }
#define forever for (;;)
#define ERRORCHECK(CODE) if (CODE) return -1

forever
    begin
    // do something
    ERRORCHECK(x);
    end

전부 다 문제지만 가장 큰 문제는 ERRORCHECK 매크로이다.

if (a) ERRORCHECK(x);
else puts("a is 0!");

이 코드는

if (a) if (x) return -1;
else puts("a is 0!");

으로 바뀐다. 이 때 else는 댕글링 else가 되어 의도하지 않은 코드가 된다. 이를 방지하기 위해선 이런 식으로 짜야 한다.

#define ERROR_RETURN(CODE) \
do {                       \
    if (CODE) return -1;    \
} while (false)

Takeaway 2.10.2.4. 함수형 매크로는 함수 호출과 비슷한 문법으로 동작해야 한다.

유명한 함정들은 다음과 같다:

  • 댕글링 else.
  • 끝 세미콜론.
  • 콤마 연산자.
  • 연산자 인자가 되는 표현식에서 괄호를 치지 않은 경우.
  • 부가 효과를 동반하는 매크로의 중복 평가.

10.2.2. Pure functions.

Takeaway 2.10.2.5. 함수 인자들은 값으로 전달된다.

두 함수가 같은 오브젝트를 조작하는 방법은 그 오브젝트의 선언이 두 함수 모두에게서 보일 때이다. 이런 전역 변수들에는 단점이 있는데, 전역 변수에 적용될 수 있는 연산은 제한적이기 때문에 코드의 유연성을 떨어트리고, 어디에서 수정했는지를 알 수 없기 때문에 예측을 어렵게 하고, 유지보수를 어렵게 한다.

Takeaway 2.10.2.6. 전역 변수를 피하라.

다음 2개를 만족하는 함수를 순수 함수라 한다.

  • 값을 리턴하는 것 외에 다른 효과가 없는 함수.
  • 리턴하는 값이 그 인자에만 의존하는 함수.

최적화의 관점에서, 순수 함수들은 컴파일러에 의해 이동되거나 병렬화되어 실행될 수 있다. 추상 상태 기계의 관점에서, 리턴값만 제공하는 것과 다른 일을 하는 함수는 순수 함수가 아니게 된다. 예시를 들면 이렇다.

  • 프로그램의 다른 상태를 인자가 아닌 방법으로 읽어들일 경우.
  • 전역 오브젝트를 수정할 경우.
  • 지역 static 오브젝트를 통해 영구적 내부 상태를 호출간에 저장할 경우.
  • 입출력을 할 경우.

추상 상태 기계의 관점에서, 순수 함수는 최적화를 도와준다.

Takeaway 2.10.2.7. 작은 작업은 가능하면 순수 함수로 하라.

순수 함수를 통한 최적화를 돕는 관점에서 inline 함수나 링크 타임 최적화에 대해 나중에 배울 것이다.

요점 정리

  • 프로그램의 각 부분에서, 우리는 오브젝트 (우리가 무엇을 가지고 작업을 하는가?), 목적 (우리가 무슨 목적으로 작업을 하는가?), 메소드 (우리가 어떻게 작업을 하는가?), 구현 (우리가 작업을 어떤 방식으로 하는가?)을 분리해야 한다.
  • 함수와 타입 인터페이스는 소프트웨어 설계의 핵심이다. 나중에 바꾸긴 힘들어진다.
  • 구현은 글로 쓰는 듯 해야 하고 제어 흐름 내에서 분명해야 한다. 복잡한 구현은 가능한 한 피해야 하며 필요한 만큼 명시적이어야 한다.

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중