# 4장 주석

주석은 오래될수록 코드에서 멀어진다.

주석은 거짓말을 한다.

부정확한 주석은 아예 없는 주석보다 훨씬 더 나쁘다.

코드만이 정확한 정보를 제공하는 유일한 출처다.

## 주석은 나쁜 코드를 보완하지 못한다.

코드에 주석을 추가하는 일반적인 이유는 코드 품질이 나쁘기 때문이다.

## 코드로 의도를 표현하라!

> before

```
// 직원에게 복지 혜택을 받을 자격이 있는지 검사한다. 
if ((employee.flags & HOURLY_FLAG) && (employee.age > 65))
```

> after

```
if (employee.isEligibleForFullBenefits())
```

⇒ **주석보다 코드로** 대다수 의도를 표현할 수 있다. 많은 경우 주석으로 달려는 설명을 함수로 만들어 표현해도 충분하다.

***

## 좋은 주석

#### 법적인 주석

**법적인 이유**로 특정 주석을 넣어야 하는 경우가 있다. 예를 들어, 각 소스 파일 첫머리에 주석으로 들어가는 저작권 정보와 소유권 정보는 필요하고도 타당하다.

```
// Copyright (C) ... 이하 생략
```

#### 정보를 제공하는 주석

때로는 기본적인 정보를 주석으로 제공하면 편리하다.

```
// kk:mm:ss EEE, MMM dd, yyyy 형식이다. 
Pattern timeMatcher = Pattern.compile(
    "\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*"
);
```

⇒ 위에 제시한 주석은 코드에서 사용한 **정규표현식이 시간과 날짜를 뜻한다고 설명**한다.

물론 시각과 날짜를 변환하는 클래스를 만들어 코드를 옮겨주면 더 좋고 더 깔끔해진다. 그러면 주석이 필요 없어진다.

#### 의도를 설명하는 주석

주석은 구현을 이해하게 도와주는 선을 넘어 **결정**에 깔린 의도까지 설명한다. 이러한 주석은 저자의 의도가 분명히 드러나서 코드를 이해하는데 도움이 된다.

```
public void testConcurrentAddWidgets() throws Exception {
    WidgetBuilder widgetBuilder = new WidgetBuilder(new Class[] {BoldWidget.class});
    String text = "'''bold text'''";
    ParentWidget parent = new BoldWidget(new MockWidgetRoot(), "'''bold text'''");
    AtomicBoolean failFlag = new AtomicBoolean();
    failFlag.set(false);

    // 스레드를 대량 생성하는 방법으로 어떻게든 경쟁 조건을 만들려 시도한다.
    for(int i = 0; i < 25000; i++) {
        WidgetBuilderThread widgetBuilderThread = new WidgetBuilderThread(widgetBuilder, text, parent, failFlag);
        Thread thread = new Thread(widgetBuilderThread);
        thread.start();
    }
    assertEquals(false, failFlag.get());
}
```

#### 의도를 명료하게 밝히는 주석

일반적으로는 인수나 반환값 자체를 명확하게 만들면 더 좋겠지만, 인수나 반환값이 **표준 라이브러리나 변경하지 못하는 코드에 속한다면** 의미를 명료하게 밝히는 주석이 유용하다.

```
assertTrue(a.compareTo(a) == 0); // a == a
assertTrue(a.compareTo(b) != 0); // a != b
assertTrue(a.compareTo(b) == -1); // a < b
```

#### 결과를 경고하는 주석

다른 프로그래머에게 결과를 경고할 목적으로 주석을 사용한다. 다음은 테스트하는데 시간이 너무 들어 특정 테스트 케이스를 꺼야 하는 이유를 설명하는 주석이다.

```
// 여유 시간이 충분하지 않다면 실행하지 마십시오.
```

* 주석이 적절한 예제

  프로그램 효율을 높이기 위해 정적 초기화 함수를 사용하려던 다른 개발자가 주석 때문에 실수를 면한다.

```
// SimpleDataeFormat은 스레드에 안전하지 못하다.
// 따라서 각 인스턴스를 독립적으로 생성해야 한다.
```

#### TODO 주석

때로는 '앞으로 할 일'을 //TODO 주석으로 남겨두면 편하다. **하지만 TODO 주석을 나쁘 코드를 남겨 놓는 핑계로 적지 말자**

#### 중요성을 강조하는 주석

자칫 **대수롭지 않다고 여겨질** 뭔가의 중요성을 강조하기 위해서도 주석을 사용한다.

```
String listItemContent = match.group(3).trim();
// 여기서 trim은 정말 중요하다. trim 함수는 문자열에서 시작 공백을 제거한다.
// 문자열은 시작 공백이 있으면 다른 문자열로 인식되기 때문이다.
new ListItemWidgets(this, listItemContent, this.level + 1);
return buildList(text.substring(match.end()));
```

#### 공개 API에서 Javadocs

공개 API를 구현한다면 반드시 훌륭한 Javadocs를 작성한다.

***

## 나쁜 주석

대다수 주석이 이 범주에 속한다.

#### 주절거리는 주석

더 구체적인 내용 및 설명이 없어서 무슨 의미인지 알아내려면 다른 코드를 뒤져야 하는 주석

```
// 속성 파일이 없다면 기본값을 모두 메모리로 읽어 들였다는 의미다. 
```

⇒ 누가 모든 기본값을 읽어 들이는가? `loadProperties.load` 를 호출하기 전에 읽어 들이는가? 아니면 `loadProperties.load`가 예외를 잡아 기본값을 읽어 들인 후 예외를 던져주는가? 아니면 `loadProperties.load` 가 파일을 읽어 들이기 전에 모든 기본값부터 읽어들이는가? 충분한 설명이 없어 해당 주석은 독자에게 도움이 되지 않고 오히려 궁금중만 불러 일으킨다.

#### 같은 이야기를 중복하는 주석 & 오해할 여지가 있는 주석

주석이 코드보다 더 많은 정보를 제공하지 못하고 코드보다 주석을 읽는 시간이 더 오래 걸린다.

```
// this.closed 가 true일 때 반환되는 유틸리티 메서드다. 
// 타임아웃에 도달하면 예외를 던진다. 
public synchronized void waitForClose(final long timeoutMillis) throws Exception {
    if(!closed) {
        wait(timeoutMillis);
        if(!closed) {
            throw new Exception("MockResponseSender could not be closed");
        }
    }
}
```

⇒ 주석이 코드보다 읽기도 쉽지도 않다. 실제로 코드보다 부정확해 **독자가 함수를 대충 이해하고 넘어가게 만든다.**

⇒ 오해할 여지가 있는 주석이다. `this.closed` 가 true 로 변하는 순간에 메서드는 반환되지 않는다. `this.closed` 가 **true 여야** 메서드는 반환된다. 또 타임아웃을 기다리면 무작정 예외를 던지는 것도 아니다. 타임아웃이 지나고, **그래도 `this.closed`가 true가 아니면** 예외를 던진다. 이처럼, 해당 주석들은 내용이 정확하지 않아 코드를 오해할 여지가 있다.

#### 의무적으로 다는 주석

오히려 코드만 헷갈리게 만들며, 거짓말할 가능성을 높이며, 잘못된 정보를 제공할 여지만 만든다.

#### 이력을 기록하는 주석

소스 코드 관리 시스템과 내용이 다르면 혼란만 가중할 뿐이다. 완전히 제거하는 편이 좋다.

#### 있으나 마나 한 주석

너무 당연한 사실을 언급하며 새로운 정보를 제공하지 못하는 주석들 때문에 개발자가 주석을 무시하는 습관에 빠지게 만든다.

#### 함수나 변수로 표현할 수 있다면 주석을 달지 마라

* 주석 대신 코드로 의도를 표현해라!

> before

```
// 전역 목록 <smodule>에 속하는 모듈이 우리가 속한 하위 시스템에 의존하는가?
if (smodule.getDependSubsystem().contains(subSysMod.getSubSystem()))
```

> after

```
ArrayList moduleDependees = smodule.getDependSubsystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem))
```

별도의 변수로 정의해서 낭바라고 볼 수도 있지만, **변수명으로 의도를 드러냈기 때문에 유용하다.**

#### 위치를 표시하는 주석

```
// Actions ////////////////////////////////////////
```

너무 자주 사용하지 않는다면 배너는 눈에 띄며 주의를 환기해주는 유용한 주석이다. 그러므로 반드시 필요할 때만, 아주 드물게 사용하는 편이 좋다. **하지만 배너를 남용하면 독자가 흔한 잡음으로 여겨 무시한다.**

#### 닫는 괄호에 다는 주석

**닫는 괄호에 주석을 달아야겠다는 생각이 든다면 대신 함수를 줄이려 시도하자.**

#### 공로를 돌리거나 저자를 표시하는 주석

```
/* 릭이 추가함 */
```

위와 같은 정보는 소스 코드 관리 시스템에 저장하는 편이 좋다. 코드를 요염시키지 말자

#### 주석으로 처리한 코드

소스 코드 관리 시스템으로 이전 코드들이 저장되므로 **절대 코드를 주석처리 하지말자. 그냥 코드를 삭제해라**

주석으로 처리도니 코드는 다른 사람들이 지우기를 주저한다. 쓸모 없는 코드가 점차 쌓여간다.

#### 전역 정보

주석을 달아야 한다면 근처에 있는 코드만 기술하라

#### 모호한 관계

주석과 주석이 설명하는 코드는 둘 사이 관계가 명백해야 한다. 이왕 공들여 주석을 달았다면 **적어도 독자가 주석과 코드를 읽어보고 무슨 소리인지 알아야 한다.**

```
/*
 * 모든 픽셀을 담을 만큼 충분한 배열로 시작한다(여기에 필더 바이트를 더한다).
 * 그리고 헤더 정보를 위해 200바이트를 더한다. 
 */
this.pngBytes = new byte[(this.width + 1) * (this.height * 3) + 200];
```

주석이 말하는 것이 무엇인가?

* 여기서 필터 바이트란 무엇일까? +1과 관련이 있을까? 아니면 \*3과 관련이 있을까? 아니면 둘 다?
* 한 픽셀이 한 바이트인가?
* 200을 추가하는 이유는?

⇒ 주석 자체가 다시 설명을 요구하는 안타까운 상황이다.

⇒ 코드로 설명이 되도록 리팩토링하자

<br>
