»
S
I
D
E
B
A
R
«
[개발자 역량] 주석.. 다느냐 마느냐 그것이 문제로다
Oct 7th, 2009 by Wegra Lee

(특히) 팀으로써 소프트웨어를 개발하다보면 주석을 잘 달라는 이야기를 자주 듣는다. 하지만 반대로 주석이 필요없는 코드를 짜라는 이야기 역시 심심치 않게 들려온다. 얼핏 생각하기엔 서로 모순되는 주장 같기도 한 두 가이드들에 대해  정확히 이해해보고, 또 좋은 주석을 달기 위한 팁과 고려 사항들까지 일부 정리해보도록 하겠다.

주석의 역사

이야기를 시작하기 전에 주석에는 어떤 종류가 있는지부터 명확히 해야 하는데, 주석의 역사에서 시작하는 것이 자연스러울듯 하다.

놀랍게도(?) 태초의 소프트웨어 코드에는 주석이란 개념이 아얘 없었다. 그도 그럴 것이 종이카드에 0011000 구멍 뚫어서 프로그램하던 시절에 주석을 삽입한다는 것은 사치일뿐 아니라 기술적인 도적이었다. ^^ 이 시절 펜으로 종이 위에 이것저것 적어놓던 것이 주석의 시작이라고 보면 된다. (사실 이 부분은 직접 경험해보진 않아서 추측성임)

컴파일러(사실 전처리기)가 주석을 인식하기 시작한 것은 당연히 소스 코드를 디지털화시킨 이후이다. 이마저도 처음엔 지금과 같은 형태는 아니었다. 초창기 언어들은 주로 line by line 으로 해석되었기 때문에 주석 역시 single-line 형태가 먼저 등장했다. 복잡한 인터페이스 설명이나 알고리즘 설명 같은 것보다는 영역/블록 구분과 간단한 커맨트 중심이어서 그리 불편하지 않았다. 그 후 등장한 multi-line 주석은 편집 편의성 증대를 위한 욕구 해결 정도여서 전혀 신선하지도 혁신적이지도 않았다.

Java가 등장하면서 (최초인지는 모름) API 문서 생성 ‘표준’ 툴(Javadoc)을 SDK 가 내장하기 시작하였고, 이는 주석의 개념을 한 단개 발전(not 혁신)시키는 계기가 되었다. Javadoc 의 특징이라면 ‘스펙 기술용 주석‘과 ‘구현 설명용 주석‘을 명백히 구분하기 시작한 것이다. 물론 그 전부터 주석을 구분해 사용하고는 있었지만, 언어의 표준적인 방식으로 도입했다는 것이 큰 의미가 있다.

이를 계기로 주석에 대한 인식은 한층 개선하였고, 그 후 등장하는 대부분의 언어들도 같은 어프로치를 취하게 되었다. 하지만 아직까지 컴파일러는 스펙/구현 가리지 않고 모든 주석을 무시하였고, 스펙을 얻어내려면 별도의 툴을 돌려야만 하였다. 이는 ‘스펙 기술’ 이라는 오늘날에 있어 아주 중대한 개념을 ‘주석’ 이라는 사소한 범주에 함께 묶는 한계에서 아직 벗어나지 못했음을 의미한다.

이에 대한 개선은 최근 Noop 언어 프로젝트를 통해 가시화되고 있다. Noop 의 여러 특징 중 ‘Executable documentation that’s never out-of-date’ 는 주석을 프로그래밍 언어 스펙에 포함시키고 컴파일러가 컴파일 워닝/에러와 같은 수준에서 직접 핸들링한다는 의미이다. 형식적으로는 거의 변화가 없지만, 주석의 위상은 거의 코드 수준까지 격상되게 된다.

나아가 annotation 이라는 개념이 추가된다. Annotation 을 주석으로 한데 묶는데는 의 아해할 사람들이 있을 수 있겠으나, 수행 코드가 아니라는 점에서 주석의 범주에 속한다. 더구나 annotation 의 한글 해석 자체가 ‘주석( 달기)’이다. ^^ (Noop 에서 annotation 을 어떻게 처리할 지는 명시적인 언급은 없다.)

주석의 중요성이 점차 커지는 것은 소프트웨어 산업의 변화 과정을 봤을 때 아주 자연스러운 결과이다. 개인이 다룰 수 있던 작은 소프트웨어에서, 이제는 수백 수천명이 수년에 걸쳐 만들고, 완전히 없어지기까지 또 수년이 더 필요한 수준까지 변화하였기 때문에, 공간과 시간을 초월한 개발자간의 커뮤니케이션이 그만큼 중요해진 것이다.

주석의 분류

이쯤에서 현재 우리가 주석이라 부를 수 있는 것들에는 어떠한 것들이 있는지 다시 정리해보자.

  • 문서화 주석 – API 명세(specification) 기술을 주목적으로 하며, 해당 소프트웨어를 black box 로 바라보는 제3의 개발자와의 커뮤니케이션을 담당한다.
  • Annotation 주석 – 코드를 처리하는 툴들에게 특정 지시를 내리는 주석으로, 이를 인식할 수 있는 툴에게만 의미가 있다. 툴의 목적에 따라 다양한 용도로 응용될 수 있다.
    또한 팀원간에 정해진 약속으로 사용하기도 좋다. 대표적인 사례로는 @todo @fixme 같은 것이 있다.
  • 구현 주석 – 내부 구현에 대한 주석으로 여타의 툴들에서는 완전히 무시된다. 이해하기 어려운 코드에 대한 설명, 추가로 해야할 일, 코드 수정 시 주의점 등, 코드 레벨에서 직접 봐야하는 개발자들 간의 디테일하고, 종종 자질구레한 커뮤니케이션을 담당한다.

이처럼 현재까지는 크게 3 가지의 대표적인 주석이 있으며, 소프트웨어 산업이 변화하면서 앞으로도 기존 주석이 변화/갈라지거나 새로운 형태의 주석이 추가될 것이다.

상세한 주석 vs. 주석이 필요 없는 코드

“상세한 주석이 좋다.” – 주로 문서화 주석에 해당하는 지침이다. 제공하는 소프트웨어 모듈의 동작 명세는 가능한 모든 케이스에 대해 명확하게 설명해 주는 것이 좋다.

“주석이 필요 없도록 코딩하라.” – 주로 구현 주석에 해당하는 지침이다. 구현 주석이 있다는 것은 코드만으론 의미 전달이 불충분하다는 반증이므로, 가능한 코드를 명확히 작성하여 구현 주석 없이 읽고 이해할 수 있게 하는 것이 좋다.

보통은 위와 같이 받아들이면 되지만, 반대의 경우도 얼마든지 있다.

문서화 주석이 최소화 되도록 코딩하라.” – 이는 문서화 주석을 생략하라는 의미보다, ‘문서화 주석에서 군더더기 설명이 필요 없도록 API 를 명확하게 만들라’ 정도로 이해해야 한다. 문서 없이 API 만 봤을 때 오해의 소지가 있다거나, 다양한 예외 상황이 존재하거나, 한 API 를 너무 다목적으로 사용할 수 있다거나, pre/post 조건을 주렁주렁 달고 있는 API 들은 이 가이드를 제대로 지키지 못한 예들이다.

“상세한 구현 주석이 좋다” – 어쩔 수 없이 구현 주석이 필요할 시에는 명확하고 상세한 설명을 달라는 의미이다. 최적화를 위해 어쩔 수 없이 복잡한 코드를 작성했다거나, 컨트롤 밖에 있는 외부 종속성 때문에 비효율적인 구조를 가져갈 수 밖에 없었다거나, 일정 등의 이유로 임시 코드를 넣어놨거나 일부 기능을 구현해놓지 않은 상황에서는 상세한 주석을 달아주어야 한다. (이 주석을 보게될 사람이 자신뿐이라는 가정은 절대 하지 말라.)

좋은 주석 작성을 위한 팁

좋은 주석 작성 팁까지 집대성 해놓으면 최고의 글이 되겠지만.. 이 글의 범주에서는 제외하도록 하겠다. (다른 누군가 집대성 해주시거나, 이미 잘 되어 있는 좋은 링크들을 보내주시면 해피할텐데 ㅎ)

  • 문서화 주석 작성에 대한 가이드는 표준화 단체에서 공개하고 있는 것이 많이 있다. 적어도 문서화가 잘 된 유명 플랫폼/라이브러리 등은 찾을 수 있다. 자신의 도메인과 가장 유사한 가이드를 찾아 적용해보는 것은 좋은 시작이 될 것이다. (e.g. Requirements for Writing Java API Specifications)
  • Annotation 주석 활용 – 같은 목적의 주석들에 동일 키워드를 사용하는 방법으로, annotation 이 정식으로 지원되지 않더라도 전혀 문제는 없다. 가장 추상화된 @todo (더 해야할 일) 부터 시작해서 @fixme (명백한 결함), @review (리뷰 커맨트), @pending (미결사항), @thread (스레드 안정성 보장 필요), @dependon (특정 기능/이슈 종속적 – 해당 기능/이슈 해결 후 일괄 검토 요구) 등 상황에 따라 적절히 응용하면 최소한의 주석으로 커뮤니케이션 효과를 극대화시킬 수 있다.
  • Aspect 를 고려한 코드 영역 구분 – 코드를 작성하다 보면 로그 작성, 접근 권한 체크, 멀티 스레딩을 위한 락 처리, 에러 처리, 부하 조정, 캐시 사용 등등 비즈니스 로직과 직접적으로 관련되지 않은 로직들로 코드가 지저분해지기 쉽다. 이 문제를 다루기 위해 Aspect Oriented 언어를 사용하는 방법도 있지만, 여건이 되지 않는 경우엔 어쩔 수 없이 모든 로직을 한데 몰아 두어야 한다. 이럴 때에는 아쉬운데로 부가적인 로직 처리 블럭과 비즈니스 로직 블럭을 구분해주는 안을 적용해볼 수 있다. 동일 룰이 코드 전반에 일괄적으로 적용되어 있다면, 코드를 보는 사람들은 목적에 맞는 코드 블럭만 정확히 찾아 검토할 수 있다.
    영역 구분을 위한 구현 주석이 필요할 수도 있지만, 그 외 구현 주석의 필요성을 감소시켜주는 효과가 있다.
  • 예외 처리 코드 주의 – 한 눈에 들어올 간단한 로직도 과도한 예외 처리가 가미되면 금새 난해한 코드로 둔갑한다. (필요악이라 할 수 있는 예외에 대한 다양하고 심도있는 관점은 C++ Exceptions: Pros and Cons 을 참조하기 바란다.) 가장 선행되어야 하는 노력은 물론 ‘불필요한 예외가 발생하지 않도록 설계’하는 것이고, 꼭 필요한 예외에 대해서 일반 로직과 명확히 구분되는 형태로 처리해주는 것이 좋다. 예를 들어 예외 발생 여부 확인을 위해 전용 매크로를 정의해 ‘if’ 절을 사용을 피하는 것도 한 방법이다. ‘if’ 절은 일반 로직에서도 등장하기 때문에 로직을 따라가다 rollback 하여 다시 시작하게 만든다.
  • 읽을 수 있는 코드 작성 – 당연하지만 너무 일반적인 가이드이다. 수많은 종속 팁들이 있을 수 있지만 너무 길어질듯 하여 생략한다. (Developer Capacities – Writing Program 참조)

결론

주석을 주석으로만 취급하는 시대는 끝났다(끝내야 한다^^). 하지만 아직도 대부분의 개발자들 주석에 대한 인식은 가볍기만 하고, 진정한 가치와 중요성을  제대로 교육/훈련시키는 모습은 찾아보기 쉽지 않다.

이제부터라도 주석과 관련한 명확한 개념 정리와, 용도별 좋은 주석 작성을 위한 가이드를 정리해 소프트웨어 입문 초기부터 익히고 생활화할 수 있도록 지도해야 한다. 지금과 같은 소셜 개발 시대에서 훌륭한 개발자가 되려면 시공간을 넘나드는 4차원적인 커뮤니케이션 능력도 갖춰야 한다.

»  Substance: WordPress   »  Style: Ahren Ahimsa