[Effective Java] item 56 : 공개된 API 요소에는 항상 문서화 주석을 작성하라

DEINGVELOP·2023년 4월 16일
0

Effective Java

목록 보기
19/19

API 문서

  • API를 쓸모 있게 하려면 문서를 잘 작성해야 함
  • 사람이 직접 작성하려면 코드가 수정될 때마다 매번 함께 수정해줘야 함

Javadoc

  • Javadoc(자바독): API 문서 수정 등을 사람 대신 해줄 수 있는 자바의 유틸리티
  • 소스코드 파일에서 문서화 주석(doc comment; 자바독 주석)이라는 특수한 형태로 기술된 부분을 추려서, API 문서로 변환함

doc comment 업계 표준 규칙

  • 공식 언어 명세에는 속하지는 앟지만, 자바 프로그래머라면 응당 알아야 하는 업계 표준 API
    -「문서화 주석 작성법(How to Write Doc Comments)」웹페이지에 기술되어 있음
    👉🏻 How to Write Doc Comments for the Javadoc Tool
  • 자바 버전이 올라가며 추가된 몇 가지 중요한 태그
    • Java 5 - @literal, @code
    • Java 8 - @implSpec, @index
    • Java 9 - @index

API 문서화 주석 작성하기

공개 클래스

  • API를 올바로 문서화하려면, 공개된 모든 클래스, 인터페이스, 메서드, 필드 선언에 문서화 주석을 달아야 함
  • 직렬화할 수 있는 클래스라면 직렬화 형태에 관해서도 적어야 함
  • 기본 생성자에는 문서화 주석을 달 방법이 없으니 공개 클래스는 절대 기본 생성자를 사용하면 안 됨

📌 문서화 주석을 제대로 작성하지 않으면?

  • 문서화 주석이 없다면 Javadoc도 그저 공개 API 요소들의 선언만 나열해주는 것이 전부임!
  • 문서가 잘 갖춰지지 않은 API는 쓰기 헷갈려서 오류의 원인이 되기 쉬움

공개되지 않은 클래스

  • 유지보수까지 고려한다면 대다수의 공개되지 않은 클래스, 인터페이스, 생성자, 메서드, 필드에도 주석을 달아야 함(공개 API보다는 덜 상세해도 됨)

메서드용 문서화 주석

  • 해당 메서드와 클라이언트 사이의 규약을 명료하게 기술하기

  • 상속용으로 설계된 클래스의 메서드가 아니라면, 무엇을 하는지를 기술하기 - how (x), what (o)

  • 메서드의 계약(contract)를 완벽히 기술하려면,

    • 모든 매개변수에 @param 태그
    • 반환타입이 void가 아니라면 @return 태그
    • 발생할 가능성이 있는 모든 예외에 @throws 태그 (검사 예외, 비검사 예외 모두)

      📌 참고!
      만약 여러분이 따르는 코딩 표준에서 허락한다면 @return 태그의 설명이 메서드 설명과 같을 때에는 @return 태그 생략 가능

  • 전제조건(precondition)

    • 클라이언트가 해당 메서드를 호출하기 위한 조건들
    • 전제조건을 모두 나열해야 함
    • @throws 태그 : 비검사 예외를 선언하여 암시적으로 기술함. 비검사예외 하나가 전제조건 하나와 연결됨!
    • @param 태그 : 그 조건에 영향받는 매개변수에 기술함
  • 사후조건(postcondition)

    • 메서드가 성공적으로 수행된 후 만족해야 하는 조건들
    • 사후조건도 모두 나열하기
  • 부작용

    • 사후조건으로 명확히 나타나지는 않지만 시스템의 상태에 어떠한 변화를 가져오는 것을 뜻함
    • ex) 백그라운드 스레드를 시작시키는 메서드 - 그 사실을 문서에 밝혀야 함

태그 사용법

메서드용 주석 태그들

/**
* 이 리스트에서 지정한 위치의 원소를 반환한다.
*
* <p>이 메서드는 상수 시간에 수행됨올 보장하지 <i>않는다</i>. 구현에 따라
* 원소의 위치에 비례해 시간이 걸릴 수도 있다.
*
* @param  index 반환할 원소의 인덱스; 0 이상이고 리스트 크기보다 작아야 한다.
* @return 이 리스트에서 지정한 위치의 원소
* @throws IndexOutOfBoundsException index가 범위를 벗어나면,
*         즉, ({@code index < 0 || index >= this.size()}》이면 발생한다.
*/
E get(int index);

(영어 버전)

/**
* Returns the element at the specified position in this list.
*
* <p>This method is <i>not</i> guaranteed to run in constant
* time. In some implementations it may run in time proportional
* to the element position.
*
* @param index index of element to return; must be
*        non-negative and less than the size of this list
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException if the index is out of range
*         ({@code index < 0 || index >= this.size()})
*/
E get(int index);

💬 Javadoc 유틸리티는 문서화 주석을 HTML로 변환함

  • 문서화 주석에 HTML 태그를 사용 - <p>, <i>
  • HTML 표(table)까지 집어넣는 프로그래머도 있음
  • @param

    • 해당 매개변수가 뜻하는 값이나 반환값을 설명하는 명사구를 씀
    • 드물게는 명사구 대신 산술 표현식을 쓰기도 함
    • 관례상 설명에 마침표를 붙이지 않음
  • @return

    • 해당 매개변수가 뜻하는 값이나 반환값을 설명하는 명사구를 씀
    • 드물게는 명사구 대신 산술 표현식을 쓰기도 함
    • 관례상 설명에 마침표를 붙이지 않음
  • @throws

    • if로 시작해 해당 예외를 던지는 조건을 설명하는 절이 뒤따름
    • 관례상 설명에 마침표를 붙이지 않음
  • {@code} 태그

    • 첫번째 효과 : 태그로 감싼 내용을 코드용 폰트로 렌더링함
    • 두번째 효과 : 태그로 감싼 내용에 포함돈 HTML 요소나 다른 자바독 태그를 무시함 (HTML 메타 문자도 사용 가능)

      📌 여러 줄로 코드 예시를 넣으려면?

      • {@code} 태그를 다시 <pre> 태그로
        감싸면 됨 (<pre> {@code ... 코드 ... } </pre> 형태)
      • 단,@ 기호에는 무조건 탈출문자를 붙여야 하니 문서화 주석 안의 코드에서 애너테이션을 사용한다면 주의!
  • this

    • 관례상 인스턴스 메서드의 문서화 주석에 쓰인 this는 호출된 메서드가 자리하는 객체를 가리킴

상속용 클래스

  • 자기사용 패턴(self-use pattern)에 대해서도 문서에 남겨 다른 프로그래머들에게 그 메서드를 올바로 재정의하는 방법을 알려줘야 함
/**
* 이 컬렉션이 비었다면 true를 반환한다.
*
* @implSpec
* 이 구현은 {@code this.sizeO = 0}의 결과를 반환한다.
*
* @return o| 컬렉션이 비었다면 true, 그렇지 않으면 false
*/
public boolean isEmpty() { ... }

(원어 버전)

/**
* Returns true if this collection is empty.
*
* @implSpec
* This implementation returns {@code this.size() = 0}.
*
* @return true if this collection is empty
*/
public boolean isEmpty() { ... }
  • @impleSpec
    • 해당 메서드와 하위 클래스 사이의 계약을 설명함
    • 하위 클래스들이 그 메서드를 상속하거나, super 키워드를 이용하여 호출할 때 그 메서드가 어떻게 동작하는지를 명확히 인지하고 사용하기

      💬 impleSpec이 독특한 케이스!
      일반적인 문서화 주석은 해당 메서드와 클라이언트 사이의 계약을 설명함

      💬 @impleSpec 활용 방법
      자바 11까지도 자바독 명령줄에서 -tag "implSpec:a:Implementation Requirements:" 스위치를 켜주지 않으면@implSpec 태그를 무시해버린다. 다음 버전에
      서는 기본값으로 적용되길 기대해본다.


주석에 <, >, & 등의 HTML 메타문자 포함시키기

특별한 처리가 필요함!

  • {@literal}
    • 가장 좋은 방법
    • HTML 마크업이나 자바독 태그를 무시하게 해줌
    • 앞서 본 {@code} 태그와 비슷하지만, 코드 폰트로 렌더링하지는 않음
    * {@literal |r| < 1}이면 기하 수열이 수렴한다.
    • 기호만 {@literal}로 감싸도 결과는 같지만, 그러면 코드에서의 가독성이 떨어짐

      💡 원칙

      • 문서화 주석은 코드에서건 변환된 API 문서에서건 읽기 쉬워야 한다!
      • 단, 양쪽을 만족하지 못하겠다면 API문서에서의 가독성을 우선시!

문서화 주석 form

/**
* 이 리스트에서 지정한 위치의 원소를 반환한다.
*
* <p>이 메서드는 상수 시간에 수행됨올 보장하지 <i>않는다</i>. 구현에 따라
* 원소의 위치에 비례해 시간이 걸릴 수도 있다.
*
* @param  index 반환할 원소의 인덱스; 0 이상이고 리스트 크기보다 작아야 한다.
* @return 이 리스트에서 지정한 위치의 원소
* @throws IndexOutOfBoundsException index가 범위를 벗어나면,
*         즉, ({@code index < 0 || index >= this.size()}》이면 발생한다.
*/
E get(int index);

첫 번째 문장 : summary descripsion

  • 해당 요소의 요약 설명

    • 반드시 대상의 기능을 고유하게 설명해야 함
    • 헷갈리지 않으려면, 한 클래스/인터페이스 안에서 요약 설명이 똑같은 멤버/생성자가 둘 이상이면 안 됨
    • 다중정의된 메서드는 특히 더 조심하기! 같은 문장으로 시작하는 것이 허용되지 않음
  • 마침표(.) 주의하기!

    • 첫 번째 마침표가 나오는 부분까지만 요약 설명이 됨

      * 머스터드 대령이나 Mrs. 피콕 같은 용의자.

      📌 요약 설명이 끝나는 판단 기준

      • {<마침표><공백><다음 문장 시작>} 패턴의<마침표>
      • <다음 문장 시작>은 ‘소문자가 아닌’문자
      • 예시에서는 “Mrs.” 다음에 공백이 나오고 다음 단어인 ‘피’가 소문자가 아니므로 요약 설명이 끝났다고 판단한 것!
    • 가장 좋은 해결책은 의도치 않은 마침표를 포함한 텍스트를 {@literal}로 감싸주는 것

      /**
       * 머스타드 대령이나 {@literal Mrs. 피콕} 같은 용의자.
       */

      💡 Tip

      • 자바 10부터는 {@summary}라는 요약 설명 전용 태그가 추가되어, 다음처럼 한결 깔끔하게 처리할 수 있다.
      /**
      * {@summary 머스타드 대령이나 Mrs. 피콕 같은 용의자.}
      */
      public enum Suspect { ... }
  • 주석 작성 규약에 따르면, 요약 설명은 완전한 문장이 되는 경우가 드뭄(즉, 주어가 없을 때가 많음)

    • 메서드/생성자의 요약 설명 : 해당 메서드와 생성자의 동작을 설명하는 (주어가 없는) 동사구
      • ArrayList(int initialcapacity) : Constructs an empty list with the specified initial capacity.
      • Collection.size() : Returns the number of elements in this collection.
      • 2인칭 문장(return the number)이 아닌 3인칭 문장(returns the number)으로 써야 한다.
    • 클래스/인터페이스의 요약 설명 : 인스턴스를 설명하는 명사절
      • Instant : 타임라인상의 특정 순간(지점)
    • 필드의 요약 설명 : 필드 자신을 설명하는 명사절
      • Math.PI : 원주율(pi)에 가장 가까운 double 값

JavaDoc과 색인 기능

  • Java 9부터 추가됨
  • API 문서 페이지 오른쪽 위에 있는 검색창에 키워드를 입력하면 관련 페이지들이 드롭다운 메뉴로

방법

  • 클래스,메서드,필드 같은 API 요소의 색인은 자동으로 만들어짐
  • 원하면 {@index} 태그를 사용해 색인으로 만들 용어를 태그로 감싸 중요한 용어를 추가로 색인화할 수 있음
    * 이 메서드는 {@index IEEE 754} 표준을 준수한다.

제네릭

제네릭 타입이나 제네릭 메서드를 문서화할 때는 모든 타입 매개변수에 주석을 달아야 한다.

/**
* 키와 값을 매핑하는 객체. 맵은 키를 중복해서 가질 수 없다.
* 즉,키 하나가 가리킬 수 있는 값은 최대 1개다.
*
* (나머지 설명은 생략》
*
* @param <K> 이 맵이 관리하는 키의 타입
* Qparam <V> 매핑된 값의 타입
*/
public interface Map<K, V> { ... }

열거 타입

열거 타입을 문서화할 때는 상수들에도 주석을 달아야 한다. 열거 타입 자체와 그 열거 타입의 public 메서드도 물론이다. 설명이 짧다면 주석 전체를 한 문장으로 써도 된다.

/**
* 심포니 오케스트라의 악기 세션.
*/
public enum Orchestrasection {
    /** 폴루트,클라리넷, 오보 같은 목관악기. */
    WOODWIND,
    
    /** 프렌치 호른,트럼펫 같은 금관악기. */
    BRASS,
    
    /** 탐파니, 심벌즈 같은 타악기. */
    PERCUSSION,
    
    /** 바이울린,젤로 같은 현악기. */
    STRING;
}

애너테이션

애너테이션 타입을 문서화할 때는 멤버들에도 모두 주석을 달아야 한다. 애너테이션 타입 자체도 물론이다.

  • 필드 설명은 명사구로 한다.
  • 애너테이션 타입의 요약 설명은 프로그램 요소에 이 애너테이션을 단다는 것이 어떤 의미인지를 설명하는 동사구로 한다. (한글로 쓴다면 동사로 끝나는 평범한 문장이면 된다.)
/**
* 이 애너테이션이 달린 메서드는 명시한 예외를 던져야만 성공하는
* 테스트 메서드임을 나타낸다.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
    /**
    * 이 애너테이션을 단 테스트 메서드가 성공하려면 던져야 하는 예외.
    * (이 클래스의 하위 타입 예외는 모두 허용된다.》
    */
    Class<? extends Throwable> valueO;
}

패키지 & 모듈

  • 패키지를 설명하는 문서화 주석은 package-info.java 파일에 작성한다.
    • 이 파일은 패키지 선언을 반드시 포함해야 하며 패키지 선언 관련 애너테이션을 추가로 포함할 수도 있다.
  • 자바 9부터 지원하는 모듈 시스템을 사용한다면 모듈 관련 설명은 module-info.java 파일에 작성하면 된다

유의 사항

API 문서화에서 자주 누락되는 설명이 두 가지 있으니,바로 스레드 안전성과 직렬화 가능성이다.

  • 클래스 혹은 정적 메서드가 스레드 안전하든 그렇지 않든, 스레드 안전 수준을 반드시 API 설명에 포함해야 한다.

  • 직렬화할 수 있는 클래스라면 직렬화 형태도 API 설명에 기술해야 한다.

  • 자바독은 메서드 주석을 ‘상속’시킬 수 있다.

    • 문서화 주석이 없는 API 요소를 발견하면 자바독이 가장 가까운 문서화 주석을 찾아준다. 이때 상위 ‘클래스’보다 그 클래스가 구현한 ‘인터 페이스’를 먼저 찾는다.
    • {@inheritDoc} 태그를 사용해 상위 타입의 문서화 주석 일부를 상속할 수 있다. 클래스는 자신이 구현한 인터페이스의 문서화 주석을 (복사해 붙여넣지 않고) 재사용할 수 있다는 뜻이다. 이 기능을 활용하면 거의 똑같은 문서화 주석 여러 개를 유지보수하는 부담을 줄일 수 있지만,사용하기 까다롭고 제약도 조금 있다.
  • 비록 공개된 모든 API 요소에 문서화 주석을 달았더라도,여러 클래스가 상호작용하는 복잡한 API라면 문서화 주석 외에도 전체 아키텍처를 설명하는 별도의 설명이 필요할 때가 왕왕 있다.

    • 이런 설명 문서가 있다면 관련 클래스나 패키지의 문서화 주석에서 그 문서의 링크를 제공해주면 좋다.

JavaDoc

  • 자바독은 프로그래머가 자바독 문서를 올바르게 작성했는지 확인하는 기능을 제공하며,이번 아이템에서 소개한 권장사항 중 상당수를 검사해준다.
  • 자바 9와 10의 자바독은 기본적으로 HTML4.01 문서를 생성하지만,명령줄에서 -htmI5 스위치를 켜면 HTML 5 버전으로 만들어준다.

검사 방법

  • 자바 7에서는 명령줄에서 -Xdoclint 스위치를 켜주면 이 기능이 활성화되고,자바 8부터는 기본으로 작동한다.
  • 체크스타일(checkstyle) 같은 IDE 플러그인을 사
    용하면 더 완벽하게 검사된다.

HTML 유효성 검사기

  • 자바독이 생성한 HTML 파일을 HTML 유효성 검사기로 돌리면 문서화 주석의 오류를 한층 더 줄일 수 있다.
  • HTML 유효성 검사기는 잘못 사용한 HTML 태그를 찾아준다.
  • 로컬에 내려받아 사용할 수 있는 설치형 검사기도 있고,웹에서 바로 사용할 수 있는 W3C 마크업 검사 서비스[W3C-validator]도 있다.

참고 사이트


정리

  • 문서화 주석은 여러분 API를 문서화하는 가장 훌륭하고 효과적인 방법이다.

  • 공개 API라면 빠짐없이 설명을 달아야 한다.

  • 표준 규약을 일관되게 지키자.

    • 문서화 주석에 임의의 HTML 태그를 사용할 수 있음을 기억하라.
    • 단, HTML 메타문자는 특별하게 취급해야 한다.
  • 잘 쓰인 문서인지를 확인하는 유일한 방법은 자바독 유틸리티가 생성한 웹페이지를 읽어보는 길뿐이다.

  • 다른 사람이 사용할 API라면 반드시 모든 API 요소를 검토하라.

0개의 댓글