ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Code Readability] 3장 코드 가독성을 높이는 주석(Comment) 작성 원칙
    kotlin/[Book] Code Readability 2025. 11. 9. 10:33

    Objective

    코드의 가독성(Readability) 과 유지보수성(Maintainability) 을 높이기 위해 주석(Comment)을 의미 있게필요한 곳에만명확하게 작성하는 원칙을 이해하고 실천한다.


    Key Results

    • [KR1] 코드 자체로 설명 가능한 경우, 주석을 생략한다.
    • [KR2] 주석은 “무엇을 하는가(What)”보다 “왜 이렇게 하는가(Why)”에 집중한다.
    • [KR3] 주석의 종류(Documentation / Informal / TODO 등)에 따라 목적과 사용 위치를 구분한다.
    • [KR4] 불필요한 주석을 없애기 위해 코드 리팩토링을 적극적으로 수행한다.
    • [KR5] 주석이 코드의 “행동”이 아닌 “의도”를 설명하도록 작성한다.

    Part 1. 주석의 개념과 목적

    개념

    주석(Comment)은 코드 동작을 보조적으로 설명하는 문장이다.

    컴파일러나 인터프리터는 주석을 무시하지만, 사람에게는 코드 이해의 단서가 된다.

    /**
     * Explanation of `fooFunction`
     */
    fun fooFunction(parameter: Parameter /* note of parameter */) {
        barFunction() // Why we call this function
        /* multi-line comment example */
    }
    

    문제

    • 많은 개발자가 주석을 “설명문”으로 오용한다.
    • 코드만으로 충분히 알 수 있는 내용을 주석으로 반복하거나,
    • 혹은 내부 구현 세부사항을 외부로 노출시키는 경우가 있다.

    해결 방법

    • 주석이 길다면, 그만큼 코드의 “의도 표현력”이 부족하다는 뜻이다.
    • → 리팩토링이 먼저, 주석은 나중이다.
    • “왜 이 코드를 작성했는가”를 중심으로 주석을 작성한다.

    예제

    문제 예제

    /**
     * Adds a new pair of keyword and definition to this dictionary.
     * If the keyword already exists, registration fails.
     */
    fun add(newData: Pair<String, String>): Boolean
    

    → 코드 이름(add)과 설명이 거의 동일하다.

    → 주석이 코드의 의미를 보강하지 못함.

    해결 예제

    /**
     * Adds or overwrites a definition for a given [keyword].
     * The registered definition can be obtained by [getDefinition(String)].
     */
    fun registerDefinition(keyword: String, definitionText: String)
    

    해결 풀이

    • “add” → “registerDefinition” 으로 함수명을 명확히 바꿈으로써
    • 원래 주석의 80%가 불필요해진다.
    • 이렇게 하면 주석은 짧고 본질적인 보조 설명만 남게 되어
    • 코드 자체의 가독성이 훨씬 높아진다.

    Part 2. 주석의 종류

    개념

    주석은 목적에 따라 여러 유형으로 나뉜다.

    구분 예시 설명
    Documentation /** ... */ 클래스, 함수, 변수 등의 공식 문서용
    Informal Comment // ... 코드 흐름 중간 설명용
    TODO/FIXME // TODO: 개선 필요 향후 수정 예정 코드 표시
    IDE/Compiler 전용 주석 // $COVERAGE-IGNORE$ 테스트나 자동화 도구용 메타 주석

    문제

    • 주석을 구분하지 않고 마구 섞어서 사용하면
    • 팀 전체의 코드 일관성이 깨진다.

    해결 방법

    • Documentation → “무엇을 하는가(What)” 중심
    • Informal → “왜 이렇게 하는가(Why)” 중심
    • TODO/FIXME → 향후 개선 계획 명시
    • IDE 주석 → 빌드/테스트 자동화용

    해결 풀이

    • 각 주석은 대상 독자(reader) 가 다르다.
      • Documentation은 외부 개발자를 위한 문서
      • Informal은 현재/미래의 코드 작성자를 위한 해설
    • 독자에 맞는 레벨의 설명을 제공해야 한다.

    Part 3. 문서화 주석 (Documentation Comments)

    개념

    문서화 주석은 IDE(KDoc/Javadoc)에서 인식하는 공식 문서용 설명이다.

    코드를 읽지 않아도 “이게 무슨 일을 하는지” 알 수 있게 만든다.

    잘못된 패턴들 (Anti-Patterns)

    1. 자동 생성된 주석 그대로 방치
    2. 함수 이름을 그대로 복사
    3. 코드 흐름을 그대로 번역
    4. 내부(private) 변수나 구현 세부사항 언급
    5. 호출자(caller) 정보를 언급

    문제 예제

    /**
     * Gets the description for a keyword.
     */
    fun getDescription(keyword: String): String
    

    → 함수명과 주석이 동일.

    → “무엇을”은 설명했지만, “왜”나 “언제” 가 없음.

    개선 예제

    /**
     * Returns description text of a given [keyword].
     * Returns an empty string if keyword is not registered.
     */
    fun getDescription(keyword: String): String
    

    해결 풀이

    • 문서화 주석은 “무엇을/왜/언제” 를 한 줄로 요약해야 한다.
    • “호출자”나 “내부 구현”은 변경 가능성이 높기 때문에,
    • 문서화 주석에 포함시키면 유지보수 시 혼란을 초래한다.

    Part 4. 세부 내용(Details) 작성법

    개념

    함수의 행동, 반환값, 제약조건, 예제 등 구체적 설명을 보충한다.

    예시 구성

    /**
     * Short summary.
     *
     * Specification/Usage:
     * ...
     * Return:
     * ...
     * Limitations:
     * ...
     * Example:
     * ...
     */
    

    문제 1: 반환값 의미 불명확

    fun setSelectedState(isSelected: Boolean): Boolean
    

    → 반환값이 무엇을 의미하는지 알 수 없음.

    개선 예제

    /**
     * Updates selection state.
     * @return true if the previous state was selected.
     */
    fun setSelectedState(isSelected: Boolean): Boolean
    

    풀이

    • 함수명이 명확하더라도, 반환값의 의미가 애매하면
    • “이 값이 무엇을 보장하는지” 주석으로 명시해야 한다.

    문제 2: 제약조건(Precondition) 누락

    fun play() // 언제 호출 가능한가 불분명
    

    개선 예제

    /**
     * Must call [prepare] before calling [play].
     * Throws [ResourceNotReadyException] otherwise.
     */
    fun play()
    

    풀이

    • 특정 순서나 상태에서만 호출 가능한 함수라면,
    • 사전 조건(precondition) 을 주석으로 반드시 명시해야 한다.
    • 그렇지 않으면 “사용자 실수”로 인한 런타임 오류가 증가한다.

    문제 3: 예제 미제공

    fun splitByComma(string: String): List<String>
    

    개선 예제

    /**
     * Splits a comma-separated string.
     * For example: `"a,bc,,d"` → `listOf("a", "bc", "", "d")`
     */
    fun splitByComma(string: String): List<String>
    

    풀이

    • 예제는 코드보다 더 빠른 “이해의 진입점”이다.
    • 특히 문자열, 데이터 처리, 변환 함수에선 입력-출력 예제가 필수다.

    Part 5. 비공식 주석 (Informal Comments)

    개념

    • 코드 중간에 “이유”나 “맥락”을 설명하는 주석
    • 형식: //, /* ... */
    • “코드가 무엇을 하는지”보다 “왜 그렇게 하는지”를 설명

    필요 조건

    • 코드가 길거나 복잡할 때
    • 동작이 직관적이지 않을 때
    • 임시 해결책(Workaround)이 있을 때

    문제 예제

    wordReplacementData.reverse()
        .forEach { (start, end, text) ->
            stringBuilder.replace(start, end, text)
        }
    

    → reverse()의 이유를 알 수 없음.

    개선 예제

    // Replace in reverse order to avoid index shift after each replacement.
    wordReplacementData.reverse()
        .forEach { (start, end, text) ->
            stringBuilder.replace(start, end, text)
        }
    

    풀이

    • 이런 주석은 코드가 “이상해 보이지만 정당한 이유가 있는 경우”를 보호한다.
    • 즉, 잘못된 리팩토링으로 인한 논리 오류를 예방하는 역할을 한다.

    Workaround 예제

    // We restore previous state here because libraryFunction()
    // may break the receiver state.
    libraryFunction()
    restorePreviousState()
    
    // To avoid Device-X specific tinting bug (see ISSUE-123456)
    

    풀이

    • 임시 방편(Workaround)을 쓸 땐 반드시 이유를 기록해야 한다.
    • 시간이 지나면 버그는 잊혀지지만, 주석은 “역사적 근거”를 남긴다.

    Part 6. Kotlin 통합 예제

    /**
     * Loads profile image and displays it as a circular thumbnail.
     *
     * Must call on the main thread.
     * Example: loadProfileThumbnail(user.id)
     */
    fun loadProfileThumbnail(userId: String) {
        // Retrieve cached image if available
        val cached = imageCache[userId]
    
        // Load from network if cache miss
        if (cached == null) {
            // TODO: Optimize network layer
            loadFromNetwork(userId)
        }
    
        // Display final image
        profileView.setImage(cached)
    }
    

    풀이

    • 공식 문서용(/** ... */)과 내부 해설용(// ...)이 구분되어 있다.
    • 각 주석은 “무엇을”과 “왜”를 분리해, 코드의 역할을 명확히 표현한다.

    최종 요약 (정리표)

    항목 내용 목적 작성 기준
    Documentation 클래스/함수 문서화 외부 개발자용 “무엇을 하는가” 요약 + 세부사항
    Informal Comment 내부 코드 설명 코드 독자용 “왜 이렇게 하는가” 중심
    TODO/FIXME 개선 계획 팀 협업용 수정 대상 명시
    IDE/Compiler 주석 자동화 설정 도구용 테스트 커버리지 제어 등

Designed by Tistory.