지난번 포스팅에 이어, ‘읽기 좋은 코드가 좋은 코드다’ 책의 5장 ‘주석에 담아야 하는 대상’ 에 대한 내용을 정리해 봅니다.
5 주석에 담아야 하는 대상
주석의 목적은 코드를 읽는 사람이 코드를 작성한 사람만큼 코드를 잘 이해하게 돕는 데 있다.
이 장에서는 자주 ‘무시’되지만 주석에 관련한 더 흥미로운 측면에 초점을 맞추었다.
- 설명하지 말아야 하는 것
- 코딩을 수행하면서 머릿속에 있는 정보를 기록하기
- 코드를 읽는 사람의 입장에서 필요한 정보가 무엇인지 유차하기
설명하지 말야아 하는 것
다음 코드에 있는 주석은 새로운 정보를 제공하거나, 코드를 더 잘 이해하도록 도와 주지 않으므로 모두 가치가 없다
// 클래스 Account 를 위한 정의
Class Account {
public :
// 생성자
Account();
// profit에 새로운 값을 설정
void SetProfit(double profit);
// 이 어카운트의 profit을 반환
double GetProfit();
};
코드에서 빠르게 유츄할 수 있는 내용은 주석으로 달지 말자
# 두 번째 '*' 뒤에 오는 내용을 모두 제거한다.
name = '*'.join(line.split('*')[:2])
프로그래머는 주석이 아닌 코드를 읽고 코드가 수행하는 일을 훨씬 더 빠르게 이해한다.
설명 자체를 위한 설명을 달지 말라
// 주어진 이름과 깊이를 이용해서 서브트리[h1]에 있는 노드를 찾는다.
Node* findNodeInSubtree(Node* subtree, string name, int depth);
이 함수를 위한 주석을 달고 싶으면, 더 중요한 세부 사항을 적는 것이 낫다.
// 주어진 'name'으로 노드를 찾거나 아니면 NULL을 반환한다.
// 만약 depth <= 0 이면, 'subtree'만 검색된다.
// 만약 depth == N 이면 N 레벨과 그 아래만 검색된다.
Node* findNodeInSubtree(Node* subtree, string name, int depth);
나쁜 이름에 주석을 달지마라 - 대신 이름을 고쳐라
// 반환되는 항목의 수나 전체 바이트 수와 같이
// Requset가 정하는 대로 Reply에 일정한 한계를 적용한다.
void CleanReply(Request request, Reply reply);
이 주석은 ‘clean’ 이 의미하는 바를 설명하려고 한다. 이렇게 하는 대신 “한계를 적용한다”는 부분을 애초에 함수명에 포함해야 한다.
// 'reply' 가 count/byte/등과 같이 'request'가 정하는 한계조건을 만족시키도록 한다.
void EnforceLimitsFromRequset(Request request, Reply reply);
좋은 이름은 함수가 사용되는 모든 곳에서 드러나므로 좋은 주석보다 더 낫다.
좋지 못한 이름의 또 다른 예이다.
// 해당 키를 위한 핸들을 놓아준다. 이 함수는 실제 레지스트리를 수정하지는 않는다.
void DeleteRegistry(Registry* key)
void ReleaseRegistryHandle(Registry* key)
좋은 코드 > 나쁜 코드 + 좋은 주석
생각을 기록하라
‘감독의 설명’을 포함하라 중요한 통찰을 기록한 주석을 코드에 포함시켜야 한다.
// 놀랍게도, 이 데이터에서 이진트리는 해시테이블보다 40% 정도 빠르다.
// 해시를 계산하는 비용이 좌/우 비교를 능가한다.
이 주석은 코드를 최적화하느라 시간을 허비하지 않게 도와 준다.
// 이 주먹구구식 논리는 몇 가지 단어를 생략할 수 있다. 상관없다. 100% 해결은 쉽지 않다.
이 주석은 뭔가 버그가 있다고 생각하고 실패를 찾기 위한 테스트 케이스를 짜거나, 버그를 수정하는 데 시간을 허비하지 않게 돕는다.
주석으로 코드가 왜 훌륭하지 않은지도 설명할 수 있다.
// 이 클래스는 점점 엉망이 되어가고 있다. 어쩌면 'ResourceNode' 하위클래스를 만들어서 정리해야 할지도 모르겠다.
코드에 있는 결함을 설명하라
// TODO: 더 빠른 알고리즘을 사용하라
혹은 코드가 불완전할 때 개선 아이디어를 설명하는 게 좋다.
// TODO(더스틴) : JPEG 말고 다른 이미지 포맷도 처리할 수 있어야 한다.
표시 | 보통의 의미 |
---|---|
TODO: | 아직 하지 않은 일 |
FIXME: | 오동작을 일으킨다고 알려진 코드 |
HACK: | 아름답지 않은 해결책 |
XXX: | 위험! 여기 큰 문제가 있다 |
TextMate | ESC |
주석은 코드를 읽는 사람에게 코드의 질이나 상태 그리고 추후 개선 방법 등을 제시하여 소중한 통찰을 제공하기 때문이다.
상수에 대한 설명
MAX_THREADS = 8 // 이 상수값이 2 * num_processors 보다 크거나 캍으면 된다.
이 코드를 읽는 사람은 상수값을 어떻게 변경해야 하는지 알게 되었다. 즉, 이 값을 1로 하면 지나치게 적고, 50으로 하면 너무 크다는 사실을 알게 된 것이다.
// 합리적인 한계를 설정하라 - 그렇게 많이 읽을 수 있는 사람은 어차피 없다
const int MAX_RSS_SUBSCRIPTIONS = 1000;
상수값이 신중하게 설정되었으므로 변경하지 않는 게 더 좋은 경우도 있다.
image_quality = 0.72; // 사용자들은 0.72 가 크기/해상도 대비 최선이라고 생각한다.
코드를 읽는 사람의 입장이 되어
이 책은 ‘코드를 처음으로 읽는 외부인의 입장에 자기 자신을 놓는 기법’을 다루고 있다.
나올 것 같은 질문 예측하기
struct Recoder {
vector<float> data;
...
void Clear() {
// 벡터가 메모리를 반납하도록 강제한다("STL swap trick"을 보라)
vector<float>().swap(data);
}
}
사람들이 쉽게 빠질 것 같은 함정을 경고하라
// 외부 서비스를 호출하여 이메일 서비스를 호출한다(1분 이후 타임아웃된다)
void SendEmail(string no, string subject, string body);
// 실행시간이 0 (number_tags * average_tag_depth) 이므로 엉망으로 중첩된 입력을 사용할 때는 주의해야 한다.
def FixBrokenHtml(html);
‘큰 그림’에 대한 주석 팀에 새로운 사람이 합류했는데, 그녀는 여러분 옆 자리에 앉아 있고, 여러분은 그녀가 팀의 코드베이스에 익숙해지게 도와 주어야 한다.
- ‘비지니스 로직과 데이터베이스를 연결해주는 코드입니다. 애플리케이션 코드에서는 직접 이용하면 안됩니다.’
- ‘이 클래스는 복잡하게 보이지만, 사실 스마트 캐시에 불과합니다. 시스템의 다른 부분은 전혀 모르는 코드예요’
이와 같은 말은 상위수준 주석에 포함되어야 하는 내용이다.
// 파일시스템에 편리한 인터페이슬 제공하는 헬퍼 함수들을 담고 있다.
// 파알의 퍼미션과 다른 자세한 세부 사항을 처리한다.
요약 주석 다음은 더 아래에 있는 하위 수준 코드의 내용을 간결하게 요약하는 주석의 예다.
// 고객이 자신을 위해서 구입한 항목을 모두 찾는다.
for customer_id in all_customers:
for sale in all_sales[customer_id].sales:
if sale.recipient == customer.id:
위 예제에서 주석이 없는 상태에서 코드를 한 줄씩 읽는 건 미스터리물을 읽는 행위나 다름없다 (all_customer를 순차적으로 반복하네! 근데 무엇을 위해서지?)
이러한 요약 주석은 몇몇 커다란 ‘덩어리’로 구성된 긴 함수에 특히 유용하다.
def GenerateUserRoport():
// 이 사용자를 위한 lock 을 얻는다.
...
// 데이터베이스에서 사용자의 정보를 읽는다.
...
// 정보를 파일에 작성한다.
...
// 사용자를 위한 loc 을 되돌려 넣는다.
이러한 주석은 코드를 읽는 사람이 자세한 내용을 읽기 전에 주석을 보고 요점을 파악할 수 있다.
마지막 고찰 - 글 쓰는 두려움을 떨쳐내라
주석 달기를 주저하게 된다면 머릿속에 떠오르는 생각을, 심지어 다듬어지지 않은 생각이라고 해도 일단 쓰기 시작하라
// 이런 제길, 이 리스트 안에 중복된 항목이 있으면 이건 복잡해 지잖아
- ‘이런 제길’ 은 ‘주의: 주의를 기울여야 할 내용’을 의미한다.
- ‘이건’ 이라는 표현은 ‘입력을 다루는 코드’를 의미한다.
- ‘복잡해지잖아’ 라는 표현은 ‘구현하기 어려워진다’를 의미한다.
위와 같이 좀 더 구체적인 표현으로 바꾸면 새 주석으로 다시 태어난다.
// 주의 : 이 코드는 리스트안에 있는 중복된 항목을 다루지 ㅇ낳는다. 그렇게 하는 것이 어렵기 때문이다.
주석을 작성 하는 과정
- 마음에 떠오르는 생각을 무조건 적어본다.
- 주석을 읽고 무엇이 개선되어야 하는지 (그런 부분이 있다면) 확인한다.
- 개선한다.
마무리
좋은 코드 > 나쁜 코드 + 좋은 주석 이번 장에서 가장 중요한 내용은 바로 이것 같습니다.
산출물을 위한 의미 없는 주석보다는 좋은 코드를 만들 수 있도록 신경을 써보는게 좋겠네요.
그럼 이만. 🥕👋🏼🖐🏼