4. 주석

백현균·2023년 1월 29일
0

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

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

2. 깔끔하고 주석이 거의 없는 코드가 주석이 많은 코드보다 훨씬 좋다!

2. 코드로 의도를 표현하라!

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

주석대신 함수로 만들어 표현해도 충분하다!

3. 좋은 주석

1. 법적인 주석

 각 소스파일 첫머리에 들어가는 저작권이나 소유권 정보
// Copyright (C) 2003, 2004, 2005 by Object Montor, Inc. All right reserved.
// GNU General Public License

2. 정보를 제공하는 주석

// 테스트 중인 Responder 인스턴스를 반환
protected abstract Responder responderInstance();
더 나은 예시) 함수의 이름을 responderInstance -> responderBeingTested로 바꾸면 주석이 필요 없다!

// kk:mm:ss EEE, MMM dd, yyyy 형식이다.
Pattern timeMatcher = Pattern.compile("\\d*:\\d*\\d* \\w*, \\w*, \\d*, \\d*");
- 정규표현식이나 포맷터 같은 것은 코드만 보고 어떤 결과물을 만들어 내는지 어려우니 주석을 통해 추가적인 설명을 한다.

3. 의도를 설명하는 주석

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

4. 의미를 명확하게 밝히는 주석

- 때때로 의미가 모호한 인수나 반환 값은 그 의미에 대해 주석을 통해 명료하게 밝힐 수 있다.
	assertTrue(a.compareTo(a) == 0 ) // a == a
    assertTrue(a.compareTo(b) != 0   // a != b
    assertTrue(a.compareTo(c) == -1) // a < c
- 이 방식을 사용할 땐 그릇된 주석을 달지 않도록 해야한다.

5. 결과를 경고하는 주석

- 다른 프로그래머에게 결과를 경고할 목적으로 주석을 사용한다.
    @Ignore("여유 시간이 충분하지 않다면 실행하지 마십시오.")
    public void testCode(){
        ...
    }
- 예시로 특정 테스트 케이스를 꺼야하는 경우 @Ignore 어노테이션을 통해 구체적인 설명을 넣어준다.

6. TODO 주석

- 앞으로 할 일을 주석으로 남겨두면 편하다.
- 당장 구현하지 않아도 되는 일을 주석으로 남겨두거나, 우선순위가 높지 않은 경우, 미래에 해도 되는 일의 경우 남겨 
  놓으면 좋다
- 요새는 IDE에서 TODO 주석을 전부 찾아주는 기능이 있기 때문에 이용하면 편하다!

4. 나쁜 주석

1. 주절거리는 주석

public void loadProperties(){
	try{
    	String propertiesPath = propertiesLocation + "/" + PROPERTIES_FILE;
        FileInputStream propertiesStream = new FileInputStream(propertiesPath);
        loadProperties.load(propertiesStream);
    }
    catch(IOException ex){
    	// 속성파일이 없다면 기본 값을 모두 메모리로 읽어 들었다는 의미이다.
    }
}

- catch에 있는 주석이 무엇이 의미하는지 알 수 없다.
- 작성한 저자에겐 의미가 있을지 모르지만, 그외 다른 사람들에게는 전해지지 않는다.
- 다른 모듈까지 찾아가면서 이해해야 하는 주석은 좋은 주석이 아니다.

2. 같은 이야기를 중복하는 주석

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

- 코드의 내용을 중복으로 주석으로 작성하는 경우가 있다.
- 이런 주석은 코드보다 더 많은 정보를 제공하지 못하고, 코드보다 읽기가 어렵다.
- 실제 코드보다 정보가 부정확하기 때문에 무시하고 넘어간다.

  // 이 컴포넌트를 위한 컨테이너 이벤트 리스너
  protected ArrayList listeners = new ArrayList();

  // 컨테이너와 관련된 Logger구현
  protected Log logger = null;

- 이런 코드들은 지저분하고, 정신없게 만든다. 기록이라는 목적이외에 의미가 없다.

3. 오해할 여지가 있는 주석

- void waitForClose(final long timeoutMills) 함수를 다시 봤을 때 중복이면서도 오해할 여지가 존재한다.
- '주석에는 this.closed가 true면 반환된다!'라고 명시되어 있지만, 실제 메소드는 반환하지 않는다.
	👍 처음부터 this.closed가 true거나, 무조건 타임아웃을 기다리는 메소드

4. 의무적으로 다는 주석

/**
 * @param title CD 제목
 * @param author CD 저자
 * @param tracks CD 트랙 숫자
 * @param durationInMinutes CD 길이(단위: 분)
 */
public void addCD(String title, String author, int tracks, int durationInMinutes) {
    CD cd = new CD();
    cd.title = title;
    cd.author = author;
    cd.tracks = tracks;
    cd.duration = durationInMinutes;
    cdList.add(cd);
}

- 모든 메소드에 javadocs 주석을 달거나, 모든 변수에 주석을 다는 것은 어리석은 짓이다.
- 이러한 주석은 코드를 복잡하게 만들고, 혼동을 일으킨다.
- 나중에 코드 내용이 바뀌었을 경우 해당 주석도 변경하지 않으면 거짓된 정보가 된다.   

5. 이력을 기록하는 주석

  * 변경 이력 (11-Oct-2001부터)
  * ------------------------------------------------
  * 11-Oct-2001 : 클래스를 다시 정리하고 새로운 패키징
  * 05-Nov-2001: getDescription() 메소드 추가
  * 이하 생략
  
  - 때때로 사람들은 모듈을 편집할 때마다 모듈 첫 머리에 이력 주석을 추가한다.
  	- 저자는 첫 머리 주석만 10페이지 이상인 경우도 봤다.
  - 예전에는 이러한 이력을 기록하고 관리하는게 바람직했으나, 지금은 소스관리시스템이 존재하므로 혼란만 가중시킨다.

6. 있으나 마나한 주석

  - 너무나도 당연한 사실을 언급하며, 새로운 정보를 제공하지 못하는 주석
  /*
   * 기본 생성자
   */
  protected AnnualDateRule() {

  }
  
  /**월 중 일자 **/
 private int dayOfMonth;
 
 - 이러한 주석들은 지나친 참견이라, 개발자가 주석을 무시하는 습관 빠지게하고, 코드를 읽으로 자동으로 주석을 건너뛴다.

7. 무서운 잡음

- 때론 Javadocs도 잡음이다. 단지 문서형태로 제공해야 한다는 잘못된 욕심으로 탄생한 잡음

/** The Name. **/
private String name;

/** The Version. **/
private String version;

/** The Version. **/
private String info;

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

// 전역 목록 <smodule>에 속하는 모듈이 우리가 속한 하위 시스템에 의존하는가?
if (module.getDependSubsystems().contains(subSysMod.getSubSystem()))
						⬇️
ArrayList moduleDependencies = smodule.getDependSubSystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem))		

9. 위치를 표시하는 주석

- 때때로 프로그래머는 소스파일에서 특정 위치를 표시하려 주석을 사용한다.
	예) // Actions /////////////////////////////////////////////
- 이러한 주석은 가독성만 맞추므로 제거해야한다. 특히 뒷 부분의 슬래시로 이어지는 잡음은 제거하는 편이 좋다.
  너무 자주 사용하지 않는다면 예시는 눈에 띄며 주의를 환기할 수 있다. 그러므로 반드시 필요할 때 아주 드물게 사용하는 것이 
  바람직하다.

10. 닫는 괄호에 다는 주석

public void foo(){
	try{
    	while(true){
        	...
        } // while
    } // try
    catch(Exception e){
    } // catch
} // foo

- 때때로 프로그래머들이 닫는 괄호에 특후한 주석을 달아놓는다.
- 중첩이 심하고, 장황한 함수일 경우 유의미 할 수 있겠지만, 우리가 추구하는 작고 캡슐화된 함수에선 잡음이다.
- 닫는 괄호에 주석을 달아야겠다라는 생각보다는 함수를 줄이려 시도하자.

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

/* 릭이 추가함 */
public void foo(){
	...
}

- 소스코드관리시스템은 누가 언제 무엇을 추가하였는지 기억하기 때문에 코드를 오염시킬 필요가 없다.

12. 주석으로 처리한 코드

this.bytePos = writeBytes(pngIdBytes, 0);
//hdrPos = bytePos;
writeHeader();
writeResolution();
//dataPos = bytePos;
if (writeImageData()) {
    wirteEnd();
    this.pngBytes = resizeByteArray(this.pngBytes, this.maxPos);
} else {
    this.pngBytes = null;
}
return this.pngBytes;

- 1960년대에는 주석으로 처리한 코드가 유용했으나, 우리는 우수한 코드관리시스템을 사용하고있고, 우리를 대신해 코드를 기억해준다. 
- 주석으로 된 코드는 삭제한다.

13. HTML 주석

/**
  * <p>적합성 테스트를 수행하기 위한 과업
  	....
    </p>
    <pre>
**/

- HTML주석은 혐오 그 자체이다.
- 무슨말인지도 알아보기 힘들고, IDE에서조차 읽이 어렵다.

14. 전역 정보

/**
 * 적합성 테스트가 동작하는 포트: 기본값은 <b>8082</b>.
 *
 * @param fitnessePort
 */
public void setFitnessePort(int fitnessePort) {
    this.fitnewssePort = fitnessePort;
}    

- 주석을 달아야할 경우 근처에 있는 코드만 기술해야한다.
- 코드 일부에 주석을 달되, 시스템의 전반적인 정보를 기술하지마라.
- 위의 예시의 경우 시스템의 기본 포트명을 주석으로 달았으나, 해당 함수 자체가 기본 포트 값을 통제하지 못한다.
	😀 즉, 기본포트 이외에 다른 포트가 들어 올 수있으며, 주석은 거짓된 주석이 될 수 있음

15. 너무 많은 정보

- 주석을 주제에 대한 역사나, 관련없는 정보를 장황하게 늘어놓지 마라.
	🤬 소설 처럼 쓰지 말라는 의미

16. 모호한 관계

/**
  * 모든 픽셀을 담을 만큼 충분한 버퍼로 시작합니다(여기에 필터 바이트를 더합니다.)
  * 그리고 헤더 정보를 위해 200바이트를 더합니다.
  **/
  this.pngBytes = new ArrayBuffer((this.width + 1) * this.height * 3 + 200);
  
  - 주석과 주석이 설명하는 코드는 둘 사이 관계가 명백해야 한다.
  - 주석을 달기로 결정했다면 충분한 시간을 들여 최고의 주석을 달도록 노력한다.
  - 이해가 안돼서, 다른 모듈까지 찾아야하는 주석은 좋지 못한 주석이다.
  - 예시에서 필터바이트가 무엇인지, 1과 200을 왜 더해야하는지, 3을 곱하는 이유가 무엇인지 알 수가 없다. 
  - 주석을 작성하는 목적은 코드만으로 설명이 부족하기 때문이다.

17. 함수 헤더

- 짧은 함수는 긴 설명이 필요없다. 
- 짧고 한 가지만 수행하는 함수의 이름을 잘 붙이면 주석으로 헤더를 추가한 함수보다 훨씬 좋다.

18. 비공개 코드에서 JavaDocs

- 공개 API는 JavaDocs가 유용한 주석이지만, 공개되지 않을 경우 JavaDocs는 쓸모가 없다.
- 시스템 내부에 속한 클래스와 함수에 JavaDocs를 생성할 필요가 없고, 오히려 코드만 보기 싫고, 산만해질 뿐이다.

0개의 댓글