[Clean Code] 4장 주석

sky·2022년 10월 7일
0

Clean Code

목록 보기
4/4
post-thumbnail

나쁜 코드에 주석을 달지 마라. 새로 짜라.

  • 브라이언 W. 커니핸, P. J. 플라우거

주석은 불순하다

주석은 대체로 불순하다. 우리는 주로 이해하기 어려운 코드에 이해를 돕기 위해 주석을 다는데, 이때는 주석을 달아야 하는 것이 아니라 코드를 고쳐야 한다.

주석으로 설명하는 것이 그렇게 큰 문제인가?에 대한 질문에 저자는 '주석은 자주 거짓말을 한다'고 대답했다. 흔히 프로그래머들은 코드를 리팩토링하지 주석까지 리팩토링하는 경우는 많지 않다고 한다. 설사 한다고 한들, 모든 코드에 대한 주석을 100%로 유지하는 것은 당연히 쉽지 않다.

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

지저분한 코드에는 주석을 달기 전에 코드를 정리해야 한다.

코드로 의도를 표현하라

조건문 안에서 어떤 조건을 검사할때도 해당 조건도 읽으면 이해할 수 있을만큼 명확하게 작성해야 한다.

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

좋은 주석

법적인 주석

저작권 정보나 소유권 정보 등 소스 파일 첫머리에 법적인 이유로 들어가는 특정 주석은 붙여주어야 한다.

정보를 제공하는 주석

반환값이나 파라미터값을 설명하는 기본 정보 제공 주석은 때때로 도움이 된다.
하지만 이보다는 함수 이름에 정보를 담는 편이 좋다.

// 테스트 중인 Responder 인스턴스를 반환한다.
protected abstract Responder responderInstance();

의도를 설명하는 주석

겉으로 쉽게 드러나지 않는 저자의 의도를 주석으로 설명해주는 것도 좋다.

의미를 명료하게 밝히는 주석

반환값이나 인수를 다양한 이유로 커스텀하지 못해 복잡해보일 땐 의미를 명료하게 밝히는 주석을 달면 도움이 된다. 하지만 코드와의 일관성을 해치기 쉬우므로 더 나은 방법을 코드단에서 찾는 것이 중요하다.

결과를 경고하는 주석

테스트 케이스 위에 '~~때는 실행하지 마십시오'라고 다는 주석이 이에 해당한다.

TODO 주석

모든 코드가 한 번에 완성되거나 확정되지는 않는다. 이럴 때 TODO 주석을 남겨 어떤 식으로 확장해나가야 하는지 적어두면 도움이 된다.

중요성을 강조하는 주석

나쁜 주석

주절거리는 주석

꼭 필요하다고 판단하지 않은 주석을 그냥 매뉴얼대로 달아버리면 다음에 보는 사람은 이해할 수가 없다.

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

코드 내용을 그대로 서술하는 주석은 좋지 않다.

// 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");
  }
}

오해할 여지가 있는 주석

실제 코드가 동작하는 것과 살짝 다른 정보로 주석이 달려있을 경우

의무적으로 다른 주석

모든 함수에 Javadocs를 달거나 모든 변수에 주석을 달아야 한다는 규칙은 코드를 복잡하게 만들고 잘못된 정보를 제공할 여지를 만들게 됨

/*
@param tite CD 제목
@param author CD 저자
@param tracks CD 트랙 숫자
*/

public void addCD(String title, String author, int tracks) {
  CD cd = new CD();
  cd.title = title;
  cd.author = author;
  cd.tracks = tracks;
  cdList.add(cd);
  }

이력을 기록하는 주석

  • 모듈에 가한 변경을 모두 기록하는 주석
  • 소스 코드 관리 시스템이 없을 땐 많이 사용됨

있으나 마나 한 주석

너무 당연한 내용의 주석은 쓸모가 없다.

/**
* 기본 생성자
*/
protected AnnualDateRule() { ... }
//월 중 일자
private int dayOfMonth;

닫는 괄호에 다는 주석

함수의 의미를 닫는 괄호 뒤에 달아야 한다고 판단된다면 함수를 정리하자.

주석으로 처리한 코드

주석으로 처리된 코드는 다른 사람들이 지우기를 주저한다는 저자의 말이 정말 백번 맞다.

비공개 코드에서 Javadocs

Javadocs는 보통 시스템 내부에 속한 클래스와 함수를 설명하는 것이므로 비공개 코드에서는 Javadocs를 작성하지 마라.

코드 적용

변경 전

주석에 이상한 링크가 첨부되어 있다. 둘 다 카메라, 갤러리와 관련된 정보가 담긴 링크다.
이런 링크를 애초에 달지 않는 편이 나은 것 같다. 내가 저 정보를 완벽하게 이해하고 코드에 적용한 후, 문서로 따로 정리를 했어야 했는데 대충 이해하고, 대충 적용하고, 정리하기 귀찮으니까 이런 식으로 작성해버린 거다.

btnPhoto.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
     // 사진 불러오기
     //https://crazykim2.tistory.com/487
    int writePermission = ContextCompat.checkSelfPermission(JoinActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    int readPermission = ContextCompat.checkSelfPermission(JoinActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE);
	
    if(writePermission == PackageManager.PERMISSION_GRANTED && readPermission == PackageManager.PERMISSION_GRANTED) {
      // 권한 허용 
      Intent intent = new Intent(Intent.ACTION_PICK);
      intent.setType("image/*");
      startActivityForResult(intent, 102);
    } else {
       requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1000);
    }
      // https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=zoomen1004&logNo=110183313246
      Log.e("print", "카메라 화면 이동");
  }
});

변경 후

onClick 메서드를 오버라이딩한 것이라 이 부분만 봤을 땐 이 함수가 전체적으로 무슨 역할인지 알 수가 없다. 그래서 다음과 같은 부분을 변경했다.

  • 전체 함수를 설명하는 주석 추가
  • 코드를 읽었을 때 직관적이지 않은 주요 로직 설명하는 주석 추가

두번째 주석은 주요 로직을 함수로 떼어내어 주석을 삭제할 수 있을 것 같다.

public setCameraIntent
btnPhoto.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
     // 사진 불러오기
    int writePermission = ContextCompat.checkSelfPermission(JoinActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    int readPermission = ContextCompat.checkSelfPermission(JoinActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE);
	
    // 권한 허용 여부 확인 -> 이미지 pick
    if(writePermission == PackageManager.PERMISSION_GRANTED && readPermission == PackageManager.PERMISSION_GRANTED) {
      Intent intent = new Intent(Intent.ACTION_PICK);
      intent.setType("image/*");
      startActivityForResult(intent, 102);
    } else {
       requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1000);
    }
      Log.e("print", "카메라 화면 이동");
  }
});
profile
우당탕탕 개발일기

0개의 댓글