코드 구조에서 알아본 바와 같이 한 줄짜리 주석은 //
로, 여러 줄의 주석은 /* ... */
로 시작합니다.
주석(comment)은 어떻게 코드가 동작하는지, 왜 코드가 동작하는지를 설명하는 데 쓰입니다.
주석을 작성하는 게 쉬워 보일 수 있는데, 초보 개발자들은 종종 잘못된 방법으로 주석을 작성하는 실수를 범합니다.
좋지 않은 주석
초심자들은 주석에 '코드에서 무슨 일이 일어나는지’에 대한 내용을 적곤 합니다. 아래와 같이 말이죠.
// 이 코드는 (...)과 (...)을 수행합니다
// A라는 개발자가 이 기능에 대해 알고 있으며...
very;
complex;
code;
그러나 좋은 코드엔 ‘설명이 담긴(explanatory)’ 주석이 많아선 안 됩니다. 주석 없이 코드 자체만으로 코드가 무슨 일을 하는지 쉽게 이해할 수 있어야 합니다.
이와 관련된 좋은 규칙도 있습니다. “코드가 불분명해서 주석 작성이 불가피하다면 코드를 다시 작성해야 하는 지경에 이른 걸 수 있습니다.”
리팩토링 팁: 함수 분리하기
함수 내 코드 일부를 새로운 함수로 옮기는 게 유익할 때도 있습니다. 아래와 같이 말이죠.
function showPrimes(n) {
nextPrime:
for (let i = 2; i < n; i++) {
// i가 소수인지를 확인함
for (let j = 2; j < i; j++) {
if (i % j == 0) continue nextPrime;
}
alert(i);
}
}
코드 일부를 함수 isPrime
으로 옮기면 더 나은 코드를 작성할 수 있습니다.
function showPrimes(n) {
for (let i = 2; i < n; i++) {
if (!isPrime(i)) continue;
alert(i);
}
}
function isPrime(n) {
for (let i = 2; i < n; i++) {
if (n % i == 0) return false;
}
return true;
}
함수 이름 자체가 주석 역할을 하므로 코드를 쉽게 이해할 수 있게 되었습니다. 이런 코드를 자기 설명적인(self-descriptive) 코드라 부릅니다.
리팩토링 팁: 함수 만들기
아래와 같이 코드가 ‘아래로 죽 늘어져 있는’ 경우를 생각해 봅시다.
// 위스키를 더해줌
for(let i = 0; i < 10; i++) {
let drop = getWhiskey();
smell(drop);
add(drop, glass);
}
// 주스를 더해줌
for(let t = 0; t < 3; t++) {
let tomato = getTomato();
examine(tomato);
let juice = press(tomato);
add(juice, glass);
}
// ...
이럴 땐 새로운 함수를 만들고, 코드 일부를 새로 만든 함수에 옮기는 게 좋습니다. 아래와 같이 말이죠.
addWhiskey(glass);
addJuice(glass);
function addWhiskey(container) {
for(let i = 0; i < 10; i++) {
let drop = getWhiskey();
//...
}
}
function addJuice(container) {
for(let t = 0; t < 3; t++) {
let tomato = getTomato();
//...
}
}
함수는 주석이 없어도 그 존재 자체가 무슨 역할을 하는지 설명할 수 있어야 합니다. 코드를 분리해 작성하면 더 나은 코드 구조가 되죠. 이런 가이드를 잘 지켜 코드를 작성하면 함수가 어떤 동작을 하는지, 무엇을 받고 무엇을 반환하는지가 명확해집니다.
그런데 실무에선, ‘설명이 담긴’ 주석을 작성하는 게 불가피한 경우도 있습니다. 알고리즘이 복잡한 코드를 작성하는 경우나 최적화를 위해 코드를 약간 비틀어 작성할 땐 설명을 적어주어야 합니다. 이런 경우를 제외하곤 간결하고 코드 자체만으로 설명이 가능하게 코딩해야 합니다.
좋은 주석
설명이 담긴 주석은 대개 좋지 않습니다. 그럼 좋은 주석이란 무엇일까요?
- 아키텍처를 설명하는 주석
- 고차원 수준 컴포넌트 개요, 컴포넌트 간 상호작용에 대한 설명, 상황에 따른 제어 흐름 등은 주석에 넣는 게 좋습니다. 이런 주석은 조감도 역할을 해줍니다. 고차원 수준의 아키텍처 다이어그램을 그리는 데 쓰이는 언어인 UML도 시간을 내어 공부해 보는걸 추천해 드립니다.
- 함수 용례와 매개변수 정보를 담고 있는 주석
- JSDoc이라는 특별한 문법을 사용하면 함수에 관한 문서를 쉽게 작성할 수 있습니다. 여기엔 함수 용례, 매개변수, 반환 값 정보가 들어갑니다.
예시:
/**
* x를 n번 곱한 수를 반환함
*
* @param {number} x 거듭제곱할 숫자
* @param {number} n 곱할 횟수, 반드시 자연수여야 함
* @return {number} x의 n 거듭제곱을 반환함
*/
function pow(x, n) {
...
}
이렇게 주석을 달면 코드를 읽어보지 않고도 함수의 목적과 사용법을 한눈에 알 수 있습니다.
WebStorm 등의 다양한 에디터는 이런 주석을 이용해 자동 완성 기능, 자동 에러 검출 기능 등을 제공합니다.
JSDoc 3이나 기타 유사한 툴을 사용하면 주석으로 HTML 문서를 만들 수 있습니다. 자세한 정보는 http://usejsdoc.org/에서 확인하시기 바랍니다.
- 왜 이런 방법으로 문제를 해결했는지를 설명하는 주석
-
무엇이 적혀있는지는 중요합니다. 그런데 무슨 일이 일어나고 있는지 파악하려면 무엇이 적혀있지 않은 지가 더 중요할 수 있습니다. '왜 이 문제를 이런 방법으로 해결했나?'라는 질문에 코드는 답을 해 줄 수 없기 때문입니다.
문제 해결 방법이 여러 가지인데 왜 하필이면 이 방법을 택했는지 의문이 들 때가 있습니다. 선택한 방법이 가장 나은 것도 아닌데 말이죠.
왜 이런 방법을 써서 문제를 해결했는지 알려주는 주석이 없으면 다음과 같은 일이 발생할 수 있습니다.
- 당신(혹은 동료)은 작성된 후 시간이 꽤 흐른 코드를 열어봅니다. 그리고 그 코드에서 선택한 방식이 ‘가장 좋은 방식은 아니란 걸’ 알아냅니다.
- "그때는 내가 멍청했구나. 하지만 지금은 더 똑똑해졌지"라고 생각하며, 이전보단 ‘더 명확하고 올바른’ 방법으로 코드를 개선합니다.
- 코드를 개선하려는 시도까지는 좋았습니다. 하지만 리팩토링 과정에서 '더 명확’하다고 생각했던 방법을 적용하면 문제가 발생한다는 걸 알아냅니다. 이미 시도해봤던 방법이기 때문에 왜 이 방법이 먹히지 않는지 희미하게 기억이 떠오릅니다. 새로 작성한 코드를 되돌렸지만, 시간이 낭비되었습니다.
해결 방법을 담고 있는 주석은 아주 중요한 역할을 합니다. 이전에 했던 실수를 방지하는 안내판 역할을 하기 때문입니다.
- 미묘한 기능이 있고, 이 기능이 어디에 쓰이는지를 설명하는 주석
-
직감에 반하는 미묘한 동작을 수행하는 코드가 있다면 주석을 달아주는 게 좋습니다.
요약
주석을 보면 좋은 개발자인지 아닌지를 어느 정도 알 수 있습니다. 주석을 언제 쓰고 언제 쓰지 않는지를 보면 되죠.
주석을 잘 작성해 놓으면 시간이 지난 후 코드를 다시 살펴볼 때 효율적으로 정보를 얻을 수 있습니다. 코드 유지보수에 도움이 되죠.
주석에 들어가면 좋은 내용
- 고차원 수준 아키텍처
- 함수 용례
- 당장 봐선 명확해 보이지 않는 해결 방법에 대한 설명
주석에 들어가면 좋지 않은 내용
- '코드가 어떻게 동작하는지’와 '코드가 무엇을 하는지’에 대한 설명
- 코드를 간결하게 짤 수 없는 상황이나 코드 자체만으로도 어떤 일을 하는지 충분히 판단할 수 없는 경우에만 주석을 넣으세요.
주석은 JSDoc3 같은 자동 문서생성 도구에도 쓰입니다. 자동 문서생성 도구는 주석을 이용해 HTML 등의 포맷을 가진 문서를 자동으로 만들어줍니다.