주석을 달지 않는 이유, 달아야 하는 이유

주싱·2023년 1월 7일
3

더 나은 코드

목록 보기
4/14


동료와 주석을 달아야 하는지, 달지 말아야 하는지 대화를 하다가 생각난 것들을 정리해봅니다.

1. 주석을 달지 않는 이유

(X) 변수 이름을 그대로 주석으로

예를 들면 이런 주석이 있습니다. frequency 라는 변수명에 주파수라는 주석을 달아놓았습니다. 영어를 그냥 한글로 해석한 것인데 javadoc으로 문서 생성을 할 때에만 약간의 의미를 가질 것 같습니다. 문서 생성도 하지 않는다면 불필요한 관리 포인트가 하나 더 늘어난다고 생각합니다.

/**
 * 주파수
 */
private double frequency; 

(X) 의미있는 정보를 주석으로

그리고 이런 상황도 있을 수 있습니다. 주파수를 표현하는 변수인데 단위가 Mhz 라는 것을 주석으로 설명하는 경우입니다. 중요하고 의미 있는 정보인 것이 사실이지만 주석보다는 변수명 자체에 Mhz를 나타내는 변수임을 나타내는게 훨씬 낫다고 생각합니다.

/**
 * 주파수 (Mhz)
 */
private double frequency; // 1. 주석에 의미 부여하기
private double frequencyMhz; // 2. 변수명에 의미 부여하기 

(X) 무엇을 하는지 주석으로

변수 선언 말고 코드에 대해서도 생각해 볼 수 있습니다. 아래 코드는 다음 수학식을 통해 주파수 스펙트럼의 채널 파워를 구하는 식인데 코드만 봐서는 도저히 무슨일을 하는지 알기 어렵습니다. 그래서 주석에 채널 파워를 계산하는 것임을 명시해 줄 수 있습니다.

(계산식 참조 : Channel power measurements )

	...
	// Channel Power 계산
    double sum = 0;
    for (int i = 0; i < points; i++) {
        sum = sum + Math.pow(10, (trace.get(i).floatValue() / 10.0));
    }
    double channelPower = 10 * Math.log10(((double) bandWidth / (double) resolution) * (1.0 / (double) points) * sum);
	... 

그러나 개인적으로는 이런 경우 함수로 모듈화해서 함수 이름에 의미를 부여해 주는 것이 훨씬 낫다고 생각합니다. 아래 처럼 바꾸면 오히려 가독성이 향상되고 채널 파워 계산에 사용되는 지역 변수들도 고립시켜서 다른 곳에서 잘못 사용할지 모르는 기회를 차단할 수 있습니다.

	... 
	double channelPower = calculateChannelPower(trace, bandWidth, resolution, int points);
	... 
}

public double calculateChannelPower(List<Double> trace, long bandWidth, long resolution, int points) {
    double channelPower;
    double sum = 0;

    for (int i = 0; i < points; i++) {
        sum = sum + Math.pow(10, (trace.get(i).floatValue() / 10.0));
    }

    channelPower = 10 * Math.log10(((double) bandWidth / (double) resolution) * (1.0 / (double) points) * sum);
    return channelPower;
}

2. 주석을 달아야 하는 이유

주석을 다는게 좋은 경우도 있다고 생각합니다.

(O) 직관적으로 표현하기 힘든 무엇을 하고 있을 때

아래는 사실 한글로도 풀어서 설명하기 힘든 코드인데, 안테나가 방위각 축에서 바라보는 방향을 180도 반대 방향을 바라보도록 보정하는 코드입니다. 위에서 주석 대신 함수로 모듈화한 경우와 유사하지만 함수 이름만으로 무엇을 표현하는지 직관적으로 표현하기가 힘듭니다.

	...
	// 방위각이 180도 반대방향을 바라보게 합니다.
    if (azimuth >= 180 ) {
        return azimuth + 180 - 360;
    } else {
        return azimuth + 180;
    }
	... 

함수 이름을 reverseAzimuth 라고 지어봤지만 직관적으로 의미를 전달하기 쉽지 않습니다. 이런 경우에는 반드시 주석을 달아서 코드가 무엇을 하는지 설명해 주는게 좋다고 생각합니다.

        ...
        reverseAzimuth(azimuth);
        ...
    }

    /**
     * 특정 안테나의 방위각을 입력받아 180도 반대 방향을 바라보도록 보정한 방위각을 반환합니다.
     */
    private Float reverseAzimuth(Float azimuth) {
        if (azimuth >= 180 ) {
            return azimuth + 180 - 360;
        } else {
            return azimuth + 180;
        }
    }

(O) 왜 하는건지 설명이 필요할 때

위에서 주석을 통해서 코드가 무엇을 하는지 설명했습니다. 그러나 내가 코드를 처음 읽는 사람이 되어보면 이 코드가 무엇을 하는지는 알겠지만 도대체 왜 하는 건지 이해하기가 어렵습니다. 멀쩡한 방위각을 위 180도 반대방향을 보도록 뒤집어야 하는걸까요? 이유는 이렇습니다. 안테나는 선형적으로 움직이는 위성을 따라가야 합니다. 그런데 현재 안테나의 방위각 구동 범위가 0도에서 360도로 (1바퀴만 회전할 수 있기 때문에) 359도에서 1도를 넘어갈 때 선형적으로 안테나 구동이 불가하게 됩니다. 따라서 위성의 이동 경로에 선형적으로 이동이 불가한 구간(359도 1도를 넘는)이 포함되는 경우에는 안테나를 뒤집어서 179도에서 181도를 넘어가도록 합니다. 그리고 고도각을 기존에 10도 였다면 뒤로 뒤집어 170도를 바라보게 하면 최종적으로 안테나는 선형적으로 이동할 수 있게 됩니다.

/**
 * 특정 안테나의 방위각을 입력받아 180도 반대 방향을 바라보도록 보정한 방위각을 반환합니다.
 * 
 * 이와 같은 보정이 필요한 이유는 다음과 같습니다. 안테나는 선형적으로 움직이는 위성을 따라
 * 가야 합니다. 그런데 현재 안테나의 방위각 구동 범위가 0도에서 360도로 (1바퀴만 회전할 수
 * 있기 때문에) 359도에서 1도를 넘어갈 때 선형적으로 안테나 구동이 불가하게 됩니다. 따라서
 * 위성의 이동 경로에 선형적으로 이동이 불가한 구간(359도 1도를 넘는)이 포함되는 경우에는 
 * 안테나를 뒤집어서 179도에서 181도를 넘어가도록 합니다. 그리고 고도각을 기존에 10도 였다
 * 면 뒤로 뒤집어 170도를 바라보게 하면 최종적으로 안테나는 선형적으로 이동할 수 있게 됩니다.
 */
private Float reverseAzimuth(Float azimuth) {
    if (azimuth >= 180 ) {
        return azimuth + 180 - 360;
    } else {
        return azimuth + 180;
    }
}

마치며

사실 주석을 달아야 하는지, 달지 말아야 하는지 깊이 생각해 본적이 없었습니다. 주석을 중요시 여기는 팀에서 일해보지 않아서 개인적으로 주석보다는 코드에 직관적으로 의미가 드러나게 하자 정도만 다짐하며 코드를 작성했습니다. 이번에 동료랑 대화를 통해 주석이 반드시 필요한 경우가 있음을 다시 생각하게 됩니다. 끝으로 Javadoc 관련 검색을 하다가 종립님의 블로그 글(링크)을 보고 배우게 됩니다. 블로그에서 읽은 인상 깊은 내용들을 정리하며 글을 마무리합니다.

  • 레거시 코드를 읽다가 이해하기 어려운 내용이 있으면 주석을 작성해서 PR을 보냈다고 합니다. 함께 일하지 않지만 정말 멋진 동료의 모습 같습니다.
  • 메서드 레벨의 Javadoc에 어떤 입력을 받아서 어떤 출력을 주는지 기술하는데 집중한다고 합니다. 저도 따라해봐야 겠습니다. 설명이 많이 공감됩니다.
  • 코드를 읽는 사람 입장에서 3초 안에 대략을 파악할 수 있게 기술하는 걸 목표한다고 합니다. 주석이 일단 장황하면 읽기가 꺼려지는 경우가 있습니다. 어쩔 수 없이 자세히 설명해야 하는 경우도 있지만 이런 마음의 자세를 가지는 건 매우 유익할 것 같습니다.
  • 내부 구현에 대해서는 설명하지 않는다고 합니다. 내부 구현은 리팩토링되고 계속해서 바뀔 가능성이 높습니다. 내부 구현을 주석으로 설명하면 주석도 늘 함께 관리해야할 대상이 되는 것 같습니다. 현업에서 코드보다 옛날 설명이 달린 주석을 종종 보는데 내부 구현을 설명하고 있기 때문일 때가 많은 것 같습니다.
profile
소프트웨어 엔지니어, 일상

0개의 댓글