How To Write Good Comments
핵심 전제
- 프로그래밍 언어는 완전한 자기 문서화(self-documenting)가 불가능함
- 코드는 “어떻게(how)“를 표현하고, 주석은 “왜(why)“를 표현하는 도구
- 주석은 실행 코드의 한계를 벗어나 자연어의 풍부함을 활용하는 수단
- 잘 작성된 주석은 코드베이스의 품질을 높임 — 주석을 제거해야 할 악(evil)으로 보는 관점에 동의하지 않음
Don’t Compensate with Comments
주석은 나쁜 코드를 보완하는 수단이 아니다
- 먼저 코드로 의도를 완전히 표현할 수 있다면, 주석 없이 코드만으로 작성해야 함
- 코드베이스에 익숙하지 않은 사람도 “무엇을(what)” 하는지 이해할 수 있도록 서술적인 이름과 구조를 갖춰야 함
- 코드를 잘 작성한 이후에도 추가 정보가 필요하다고 판단될 때 주석을 작성할 것
- 코드가 불명확해서 주석으로 보완하는 것은 이중 작업(double work)
Comments Should Tell The “Why”
- “코드가 잘 작성되었다면 자기 문서화된다”는 주장은 부분적으로만 옳음
- 코드는 프로그램이 어떻게 동작하는지의 유일한 진실(source of truth)이지만, 로직에 담긴 맥락까지 전달하지는 못함
- 비즈니스 요구사항, 물리 법칙, 도메인 지식 등 외부 세계의 개념은 코드만으로 표현 불가
- 이름 짓기와 포맷팅으로 일부 정보를 전달할 수 있지만, “왜 이 방식으로 구현했는가”의 근거는 전달 불가
| 표현 방식 | 전달 가능한 것 |
|---|---|
| 코드 | 어떻게(how) 동작하는가 |
| 변수/함수명 | 무엇을(what) 하는가 |
| 주석 | 왜(why) 이렇게 구현했는가 |
binaryTreeBecauseLinkedListSlower같은 변수명은 쓰지 않지만, 자료구조 선택의 이유는 주석으로 남길 수 있음- 코드를 지나치게 서술적으로 만들면 오히려 가독성이 저하됨 — 주석이 “why”를 담당하면 코드는 “how”에만 집중할 수 있음
Comments Define Abstractions
- 추상화(abstraction): 복잡한 내부를 숨기고 단순한 인터페이스를 제공하는 개념
- 코드는 상세하지만, 추상화는 본질적으로 모호함 — 코드만으로 추상화를 설명하기에는 한계가 있음
- 소스 코드를 전부 읽지 않아도 모듈이 무엇을 하는지 이해할 수 있어야 함
- 주석은 인터페이스와 구현 사이의 중간 위치를 차지함:
인터페이스 → 기본 연산 제공
주석 → 사용 방법, 제약, 기능 설명 (중간 수준)
구현 코드 → 세부 동작 방식
- 주석을 통해 모듈/클래스의 high-level 뷰를 제공 — 너무 추상적이지도, 너무 구체적이지도 않게
The Trouble With Inline Comments
주석의 두 가지 유형
- 모듈/클래스/함수 수준 주석: 전체가 무엇을 하는지 설명하는 고수준 주석
- 인라인(구현) 주석: 실제 구현 코드 사이에 삽입되어 각 연산의 세부 정보를 제공
인라인 주석 = 리팩터링 초대장
- 개발자들이 주석의 유용성에 불만을 가질 때, 대부분 인라인 주석을 의미함
- 인라인 주석으로 함수의 논리적 부분을 구분하고 있다면, 함수를 더 작게 분리하라는 신호
// 주석으로 함수의 파트를 구분하는 나쁜 예
function createUserAccount(email, password) {
// 이메일 유효성 검사
...
// 새 유저 엔티티 생성
...
// 계정 확인 이메일 발송
...
}
// 더 작은 함수들로 분리하는 좋은 예
function createUserAccount(email, password) {
validateEmail(email)
createUserEntity(email, password)
sendConfirmationEmail(email)
}
엣지 케이스도 함수로 추출
- 엣지 케이스나 특별 처리 로직을 인라인 주석과 함께 두는 대신, 별도 함수로 추출하고 함수 수준 주석을 붙이는 것이 더 좋음
// 인라인 처리 — 장황해짐
if (typeof IntersectionObserver === undefined) {
// Safari에서 IntersectionObserver 폴리필이 필요함
await import('intersection-observer')
}
// 함수로 추출하고 함수 수준 주석 작성
/**
* IntersectionObserver API 인스턴스를 반환한다.
* 현재 브라우저에서 지원되지 않는 경우 폴리필을 임포트한다.
*/
async function initIntersectionObserver() {
...
if (typeof IntersectionObserver === undefined) {
await import('intersection-observer')
}
...
}
Inline Comments Should be Precise
- 인라인 주석은 저수준(low-level) 세부 정보를 제공하는 데 여전히 유용함
- 구현 코드에 가깝기 때문에 더 정확하고 구체적일 수 있음
- 도메인 특정 비즈니스 맥락, 특정 용어의 의미 등을 전달하는 데 적합
// D&D 캐릭터는 특정 스킬에 숙련도를 가지며 보너스를 받는다
const modifier = baseModifier + (isProficient ? 2 : 0)
- 짧고 이름이 잘 지어진 함수에는 인라인 주석이 불필요하지만, 길거나 복잡한 함수에는 명확성을 위해 유용함
- 인라인 주석도 구현 방법(“how”)은 코드에 맡기고, “what”과 “why”에만 집중해야 함
Knowing Where to Add Clarity
명백한 주석은 피해야 함
- 불필요하게 명백한 주석은 추가 작성 및 유지보수 부담만 늘릴 뿐 이득이 없음
- 작성자가 오랫동안 특정 문제를 다뤄왔다면, 자신에게 명백한 내용이 다른 사람에게는 혼란스러울 수 있음
- 한 번 이해한 로직은 단순하게 보이기 때문에 복잡한 부분을 놓치고 문서화하지 않을 수 있음
코드 리뷰를 활용하라
- 복잡한 로직에 충분한 설명이 있는지 확인하려면 코드 리뷰에 의존해야 함
- 한 명 이상이 동일한 부분에 혼란을 느낀다면, 작성자에게 명백해 보여도 주석이 필요하다는 신호
- “두 명 이상이 혼란을 느끼면 반드시 주석을 추가하라”
The Case of the Deep Copy
실제 사례: 수수께끼 같은 코드 한 줄
const data = JSON.parse(JSON.stringify(response))
- 이 코드를 처음 본 사람은 즉시 “왜 이렇게 했지?“라는 의문을 갖게 됨
- 주석이 없으면 동료에게 직접 물어봐야 하는 상황 발생 → 20분짜리 설명을 반복하게 됨
주석 한 줄이 텔레파시와 같다
// 참조에 의한 변경을 막기 위해 깊은 복사를 만든다
const data = JSON.parse(JSON.stringify(response))
- 응답(response)은 여러 곳에서 사용되는 깊게 중첩된 구조 → 참조 변이를 막으려면 깊은 복사 필요
- 주석 한 줄이 있었다면 불필요한 질문과 컨텍스트 전환이 없었을 것
더 나은 방법: 함수로 추출
/**
* 깊게 중첩된 자료구조의 복사본을 반환한다.
* 참조에 의한 수정을 막기 위해 사용된다.
*/
function makeDeepCopy(response) {
return JSON.parse(JSON.stringify(response))
}
const data = makeDeepCopy(response)
- 함수명만으로는 “왜” 이 방식을 쓰는지 알 수 없으므로, 이 경우 함수 수준 주석이 가치 있음
parse/stringify호출을 “최적화”한다며 제거했다가 미묘한 버그가 발생할 수 있음- 주석은 시간여행과 같다 — 작성자가 회사를 떠난 뒤에도, 그 사람의 의도를 언제든 확인할 수 있음
Maintaining Comments
주석도 코드와 마찬가지로 유지보수가 필요하다
-
코드는 거의 변하지 않고 고정되는 경우가 드뭄 — 요구사항 변화나 기술 변경으로 언제든 리팩터링 필요
-
주석도 함께 업데이트해야 함:
- 버그를 처리하기 위해 함수를 특이하게 변경했다면 → 주석으로 문서화
- 드문 비즈니스 케이스를 처리한다면 → 이유를 주석으로 남겨야 함
- 기존 코드를 변경했다면 → 관련 주석도 반드시 갱신
-
동기화가 깨진 주석은 없는 것보다 더 나쁘다:
- 주석이 없으면 → 도움을 찾으러 감
- 주석이 틀렸으면 → 잘못된 방향으로 이끌려 더 큰 피해 발생
Keep Commenting
- 주석은 도구이며, 사용 방식에 따라 결과가 달라짐
- 과도한 주석: 유지보수 부담 증가
- 주석 부재: 헤밍웨이처럼 코드를 쓰지 않는 한, 머릿속에 유지해야 할 멘탈 모델이 기능마다 커짐
주석이 다루어야 할 내용
- 코드로 표현할 수 없는 모든 것
- 특정 연산의 “why”
- 자료구조나 알고리즘 선택의 이유
- 알고리즘의 세부적인 작은 디테일
파일의 모든 문자는 이후에 유지보수해야 하는 문자다 — 신중하게, 그러나 아끼지 말고 사용하라