#6. 주석의 종류
C++ 에서 문법적으로는 다음의 두가지 주석이 있습니다.
1
2
3
1. //
2. /* */
위치적으로는 다음과 같이 분류할 수도 있습니다.
-
파일 주석
파일의 선두에 위치하며, 파일에 포함된 클래스, 함수에 대한 간략한 목적과 개발 히스토리, 작성자 정보등이 기재됩니다.
-
클래스 주석
클래스 선언 선두에 위치하며, 클래스의 목적, 설계 철학과 사용방법등이 기재됩니다. 클래스를 사용하는데 있어서의 가정과 주의사항도 들어가면 좋습니다.
-
함수 주석
함수 선언 또는 정의의 선두에 위치하며, 함수의 목적, 설계 철학, 인자 정보, 리턴 정보, 예외 정보와 사용방법, 가정등이 기재됩니다. 또는 문서화 유틸리티를 위한 메타 주석이 포함될 수 있고, 함수가 전역 변수에 미치는 영향, 알고리즘의 출처등을 적을 수도 있겠죠. 특히 인자 정보를 적을때에는 명칭, 의미, 허용범위, 단위등도 포함되어야 합니다.
-
줄 끝 주석
명령문 끝에 위치하며, 비교적 무시해도 좋은 내용이 기재됩니다. 변수 정의의 끝에도 유용하게 사용됩니다. 하지만 배치 문제와 미관상 들쑥날쑥해져 많이 사용하지는 않습니다.
-
블록 주석
동일한 목적을 수행하는 일련의 명령문들 상단에 위치하며, 코드의 목적, 의도, 의미, 요약이 기재됩니다.
-
루프/제어 주석
루프문, 제어문의 시작에 위치하며, 루프/제어의 목적, 의도, 의미등이 기재됩니다.
-
루프/제어 종결 주석
루프문, 제어문 끝에 위치하며, 복잡한 루프/제어문의 끝을 표시하기 위해 사용합니다. 이러한 주석을 사용하기 보다는 루프문, 제어문을 재구성하는 것이 좋습니다.
-
데이터 선언/정의 주석
데이터 선언부나 정의부에 기재되며, 충분한 설명을 작성하여야 합니다. 함수의 인자의 경우와 마찬가지로 명칭, 의미, 허용범위, 단위등을 적어야 합니다.
하지만 의미상으로 다음과 같이 분류 할 수도 있습니다.
-
코드의 반복
코드의 내용을 그대로 주석으로 기재합니다. “a 변수에 1을 더해 b에 대입한다.” 는 식이며, 눈만 어지럽히며, 코드 변경시 유지보수를 어렵게 합니다. 주로 코드 작성후 주석을 기재할 때 이런식의 주석이 작성되곤 합니다. 코드 작성전에 미리 주석을 적어서 보다 추상화된 수준의 주석을 작성해야 합니다.
혹은 코드 작성전에 의미를 적었는데, 그 내용이 너무 간결하여 코드를 반복할 수 있습니다.
예를 들어,
1
// 파일명을 리턴한다.
로 의사코드가 작성되었고, 코드 작성후에는
1 2 3 4
// 파일명을 리턴한다. LPCWSTR GetFileName() const { return m_FileName; }
으로 작성되면, 의미가 너무 간결하죠? 이제 불필요하므로 주석을 지우세요.
-
복사된 주석
빠른 코딩을 위해 복사하기/붙여넣기시 같이 복사된 주석이며, 코드 수정후 주석은 수정되지 않아 엉똥한 내용이 기재되 있곤 합니다. 코드 분석을 오히려 혼란스럽게 합니다. 주석을 복사한 후, 코드와 함께 주석도 수정되어야 한다는 것을 잊지 마세요.
-
잘못된 주석
코드의 내용과는 상관없는 주석입니다. 복사된 주석의 잔재일 수 있으며, 코드 수정시 주석은 수정하지 않은 경우입니다. 오히려 코드 분석을 방해할 수 있으므로 반드시 사라져야 합니다.
-
코드에 구체화된 주석
예를 들어 주석에 변수명을 그대로 기재하여 “m_UserInfo 를 갱신한다.” 는 변수명이 m_UserData로 변경되었다면, “m_UserData를 갱신한다.” 로 변경되어야 합니다. 애초에 주석의 내용을 조금 더 추상화하여 “사용자 정보를 갱신한다.”로 했다면, 코드 변경시 주석도 같이 변경할 필요가 없었겠죠.
-
코드의 설명
흔히들 “주석은 코드를 설명하는 것”으로 오인하고 있습니다. 코드를 설명하는 주석은 사실 모두 사라져야 합니다. 코드가 잘못 짜여졌거나, 잘못된 복잡한 논리를 가진다는 신호거든요. 논리를 단순화할 수 있도록 더 고민하세요. 그리고 리팩토링을 통해 설명적인 주석이 필요없도록 코드를 간결하게 유지하세요.
-
코드 표시
아직 완료되지 않은 기능, 테스트 등을 마킹합니다. 릴리즈 전까지는 다 없어져야 겠죠? 저는 주로
//!!
을 선호합니다. 소스 중에서//!!
인 것을 검색해서 릴리즈 전까지는 모두 없애죠. 이렇게 할일 목록을 주석을 이용해서 소스에 적으면, 디버깅할 항목이 현저히 주는 효과가 있습니다.또한 코드 블록이 많은 긴 함수내에서 각 블록이 손쉽게 눈에 띄도록 주석을 꾸미는데도 사용합니다.
1 2 3 4 5 6 7 8 9 10 11
// --------- // 데이터 초기화 // --------- 코드들.... // --------- // 데이터 유효성 검사 // --------- 코드들....
-
요약 주석
여러줄의 명령문, 코드 블록을 분석하지 않고 알아볼 수 있게 요약합니다. 코드 분석의 시간을 대폭 줄여주는 효과적인 주석입니다.
-
의미/의도 주석
왜 이런 코드를 작성하는지를 적습니다. 사실 본인이 작성한 코드라도 무슨 목적에 의해 이런 코드를 수행하는지 나중에는 잘 이해되지 않을 때가 많습니다. 나중에 괴로워할 자신을 위해 무슨 목적으로 이런 동작들을 하는지 적으세요.
다음 코드는 뭐하는 걸까요?
1 2 3
if (msg == WM_LBUTTONUP) { SetCursor(IDC_ARROW); }
간단하죠. 왼쪽 마우스 버튼을 띄면, 화살표 모양 커서로 바꾸는군요. 그래서 주석을 다음과 같이 바꾼다면,
1 2 3 4
// 왼쪽 마우스 버튼을 띄면, 화살표 모양의 커서로 바꾼다. if (msg == WM_LBUTTONUP) { SetCursor(IDC_ARROW); }
코드만 반복할 뿐 코드 분석에는 아무 도움도 되지 못합니다. 눈만 어지럽히는 쓸데없는 주석이죠. 왜, 왼쪽 마우스 버튼을 띄면, 화살표 모양의 커서로 바꾸는 걸까요? 그 의도가 도대체 뭘까요? 다음과 같이 의도나 의미를 적으세요.
1 2 3 4
// 마우스 이동시 변경했던 커서 초기화 if (msg == WM_LBUTTONUP) { SetCursor(IDC_ARROW); }
-
이유 주석 (일상적이지 않은 방식을 택한 이유)
좋은 개발 방식을 어긴 이유, 왜 최적화를 했는지, 어떤 버그에 의한 땜질인지, 용접봉은 무얼 사용했는지등을 적습니다.
-
메타주석
저작권, 버전, 히스토리 주석, 작성자 정보등을 적습니다. 가끔보면, 이메일이나 전화번호 등이 적혀져 있는 소스도 볼 수 있는데요. 작성자 정보에 그런게 꼭 필요한지는 좀 의문이네요. 이메일이나 전화번호… 사심이 담긴 프로포즈 인가요?
-
제약 주석
함수 및 클래스 사용에 어떠한 제약사항이 있는지 적습니다. 최대값, 최소값, 제약값을 어겼을때 어떻게 예외를 처리하는지… 예를 들어 각도인데, 370을 전달하면 360으로 자동 보정된다던지, 아니면 시스템이 종료된다던지, 여러가지 예외상황에 대한 정보를 제공할 수 있습니다.
-
가정 주석
함수 및 클래스 사용에 어떠한 가정이 있는지 적습니다. 대부분 전달되는 인수에 따라 함수가 작동하게 되는데, 알게 모르게 여러가지 가정을 하게 됩니다. 주로 포인터를 사용할때 이 포인터는 유효하다!!! 라고 가정하고 많이 작성하죠? 아무튼, 좋은 함수는 가정이 별로 없어야 하고요, 혹시라도 가정이 있다면
_ASSERTE()
로 꼭 확인해야 합니다. -
인자, 데이터 선언/정의 주석, 리턴 주석
함수 선언부에 주로 적게 되는데요, 인자의 단위, 허용 범위, 함수의 작동방식, 리턴값 등을 작성합니다. 주로 리팩토링해서 최소화 시키는 것이 좋습니다.
-
리턴 주석
리턴값의 의미, 성공시의 값, 실패시의 값등을 적습니다.
-
설계 이념, 클래스 설계 철학
뭐 반드시 지켜야 하거나 하는 이념, 철학등은 클래스를 멋지게 구성하여, 잘못 사용하기에는 어렵게, 혹은 아예 불가능하게, 바르게 사용하기에는 쉽게 작성해야 합니다. 하지만, 언어의 제약으로 이게 힘들다면, 그리고 후학들을 위해 이념이나 철학을 적고 싶다면, 클래스 정의부에 적어주는 것이 좋습니다.
-
참고 문서
혹시나 참고한 문서가 있고, 이 알고리즘을 말로 풀어 쓰기 힘들다면, 참고 문서를 기재하여 후학들을 배려합시다.
-
유지보수 기록
유지보수의 기록은 본인이 퇴사한 후 큰 도움이 됩니다. 버그 트랙킹 시스템과 연동되면 더욱 좋겠죠. 요청자, 요청 사유, 수정한 방법, 수정일 등을 적어줍니다.
-
빈 else 주석
대부분의
if
문이else
없이 작성된 코드를 보면, 과연else
상황은 없는가? 라는 의심이 들때도 있습니다. 이때 빈else
문을 넣어주고else
인 상황은 없다라고 주석으로 명기하면, 나중에 안심이 되긴 합니다. -
문서화 주석
따로 문서화를 하지 않기 위해 코드에 포함된 주석입니다. Doxygen등의 툴로 코드로 부터 문서를 추출해 낼 수 있으나, 주석의 메타데이터가 많고, 추출된 문서는 문서로서의 가치가 그리 높지는 않더라구요.(여러 프로그래머에 의해 작성된 주석이므로 일관성이 없고 읽기도 어렵고, 괜히 고생만 몇번 했던 기억이 있습니다. 좋은 팀웍과 의지가 높아야지만 가능해 보입니다.)
-
루틴이 전역에 미치는 영향
어떤 함수가 어떠한 영향을 미치는지 적습니다. 물론, 영향도가 최소화 되도록 구조를 설계하는게 정답입니다.
-
클래스 사용 방식
사실,
public
함수 1개만 있다면 사용방식을 적을 필요가 없겠죠? 하지만, 리팩토링 전에 다른 개발자들이 쉽게 접근할 수 있도록 사용방식을 꼭 적어주시고요, 쉽게 이해할 수 있도록 점차적으로 코드도 리팩토링하셔야 합니다. -
사용상 유의 사항
잘못 사용하기에 불가능하게 설계하셨다면 이런 주석은 필요 없을 겁니다. 하지만 언어의 제약으로 불가능 하다면 어떻게든 알려주어야 겠죠. “더이상 이 클래스는 상속하지 마시오. 가상 함수를 수정하면 오동작의 우려가 있습니다.” 등이요.
-
이메일, 주소, 전화번호
코드로 연애 상대 찾는 게 아니라면, 개인정보는 자제하는게 좋습니다.
-
형식화된 주석
지나친 형식은 오히려 주석작성을 두렵게 합니다. 예를 들어 주석 시작은
//@@
이고, 함수내용을//&!
라고 해서 적는등, 나중에 문서화한다고 하면서 외계어 사용을 강요하는 데요, 장담하건데, 헛짓입니다.
주석의 종류 참 많죠?
자신이 놓치고 있는 주석은 없는지 확인해 보세요.
책을 보다 보니 다음 말이 있네요. 참고들 하시고요,
“10개의 명령문마다 주석을 1개 작성하는것이 이해도가 높다.” IBM Caper Jones. Code Complete 2 발췌
잊지 마세요. 다시한번 강조하지만,
-
주석은 리팩토링의 !!!신호!!!입니다.
-
주석은 리팩토링의 !!!힌트!!!입니다.
-
주석은 리팩토링 과정을 거쳐 소스코드에서 사라져야 합니다.
-
주석이 없어지도록 리팩토링하면 소스 가독성이 !!!증가!!!합니다.
댓글남기기