[클린코드] - 주석

주석이란

  • 잘 달린 주석은 유용하지만 그렇지 않으면 안다는만 못하다.
  • 표현을 하고 싶으면 주석대신 코드로 표현하라.
  • 표현을 제대로 하지 못했기 때문에, 만회하기 위해서 주석을 사용하는 것이다.

주석까지 유지보수는 힘들다

  • 시간이 지날 수록 아래 코드는 유지가 힘들다.
  • 부정확한 주석는 아예 없는 주석보다 이해가 힘들다
MockRequest request;
private final String HTTP_DATE_REGEXP =
 "[SMTWF][a-z]{2}\\,\\s[0-9]{2}s[JFMASOND][a-z]{2}\\s"+
 "[0-9]{4}\\s[0-9]{2}\\:[0-9]{2}\\:[0-9]{2}\\sGMT";
private Response response;
private FitNesseContext context;
private FileResponder responder;
private Locale saveLocale;
//Excample : "Tue, 02 Apr 2003 22:18:49 GMT

코드로 의도를 표현하라!

//직원에게 복지 혜택을 받을 자격이 있는지 검사한다.

if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)

if (employee.isEligibleForFullZBenefits())

좋은 주석들

법적인 주석

저작권정보, 계약 조건, 법적인 정보

// Copyright (C) 2003,2004,2005 by Object Mento, Inc. All rights reserved.
// GNU General Public License 버전 2 이상을 따르는 조건으로 배포한다

정보를 제공하는 주석

기본적인 정보를 주석으로 제공, 하지만 코드로 만드는 편이 낫다

// 테스트 중인 Responder 인스턴스를 반환한다

protected abstract Responder responderInstance();


protected abstract Responder responderBeingTested();

의도를 설명하는 주석

구현으로 이해하게 도와주는 선을 넘어서 결정에 깔린 의도까지 설명

public int compareTo(Object o) {
 if (o instanceof WikiPagePath) {
 WikiPagePath p = (WikiPagePath) o;
 String compressedName = StringUtil.join(names, "");
 String compressedArgumentName = StringUtil.join(p.names, "");
 return compressedName.compareTo(compressedArgumentName);
 }
 return 1; // 오른쪽 유형이므로 정렬 순위가 더 높다.

}
public void testConcurrentAddWidgets() throws Exception {
 WidgetBuilder widgetBuilder =
 new WidgetBuilder(new Class[]{BoldWidget.class});
 String text = "'''bold text'''";
 ParentWidget parent =
 new BoldWidget(new MockWidgetRoot(), "'''bold text'''");
 AtomicBoolean failFlag = new AtomicBoolean();
 failFlag.set(false);
 // 스레드를 대량으로 생성하는 방법으로 어떻게든 경쟁 조건을 만들려고 시도한다

 for (int i = 0; i < 25000; i++) {
 WidgetBilderThread widgetBilderThread =
 new WidgetBuilderThread(widgetBuilder, text, parent, failFlag);
 Thread thread = new Thread(widgetBilderThread);
 thread.start();
 }
 assertEquals(false, failFlag.get());
} 

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

public void testCompareTo() throws Exception {
 WikiPagePath a = PathParser.parse("PageA");
 WikiPagePath ab = PathParser.parse("PageA.PageB");
 WikiPagePath b = PathParser.parse("PageB");
 WikiPagePath ba = PathParser.parse("PageB.PageA");
 WikiPagePath aa = PathParser.parse("PageA.PageA");
 WikiPagePath bb = PathParser.parse("PageB.PageB");
 assertTrue(a.compareTo(a) == 0); // a == a

 assertTrue(a.compareTo(b) != 0); // a != b

 assertTrue(ab.compareTo(ab) == 0); // ab == ab

 assertTrue(a.compareTo(b) == -1); // a < b

 assertTrue(aa.compareTo(ab) == -1); // aa < ab

 assertTrue(ba.compareTo(bb) == -1); // ba < bb

 assertTrue(b.compareTo(a) == 1); // b > a

 assertTrue(ab.compareTo(aa) == 1); // ab > aa

 assertTrue(bb.compareTo(ba) == 1); // bb > ba

} 

결과를 경고하는 주석

// 여유 시간이 충분하지 않다면 실행하지 마십시오

public void _testWithReallyBigFile() {
 writeLinesToFile(1000000000);
 response.setBody(testFile);
 response.readyToSend(this);
 String responseString = output.toString();
 assertSubString("Content-Length: 1000000000", responseString);
 assertTrue(bytesSent > 1000000000);
}

annotation으로 대체 가능

public static SimpleDateFormat makeStandardHttpDateFormat() {
 // SimpleDateFormat은 스레드에 안전하지 못하다

 // 따라서 각 인스턴스를 독립적으로 생성해야 한다.

 SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
 df.setTimeZone(TimeZone.getTimeZone("GMT"));
 return df;
} 

TODO 주석

앞으로의 할일을 남겨 놓으면 편하다.
IDE에서 TODO주석이 달린것을 잘 정리해주지만 그래도 정리를 해서 나쁜 코드를 남겨 놓은 핑계가 되어서는 안되다.

// TODO-MdM 현재 필요하지 않다.

// 체크아웃 모델을 도입하면 함수가 필요 없다.

protected VersionInfo makeVersion() throws Exception {
    return null;
}

중요성을 강조하는 주석

대수롭지 않다고 여겨질 뭔가의 중요성을 강조

String listItemcontent = match.group(3).trim();
// 여기서 trim은 굉장히 중요하다. trim 함수는 문자열에서 시작 공백을 제거한다

// 문자열에 시작 공백이 있으면 다른 문자열로 인식되기 때문이다.

new ListItemWidget(this, listItemcontent, this.level + 1);
return buildList(text.substring(match.end()));

나쁜 주석

  • 허술하고 엉성하고 주절거리는 독백

주절거리는 주석

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

 }
}

메모리를 읽어들였다는게 무슨 의미인지 코드를 살펴보지 않으면 알 수가 없다.

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

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

코드만 있어도 알 수 있다.

/**
 * 이 컴포넌트의 프로세서 지연값
 */
protected int backgroundProcessorDelay = -1;
/**
 * 이 컴포넌트를 지원하기 위한 생명주기 이벤트
 */
protected LifecycleSupport lifecycle = new LifecycleSupport(this); 

javadoc의 예제들 쓸데없다고 하는데 별로 동의는 못하겠다.

있으나 마나 한 주석

코드를 정리하라

 try {
 doSending();
 } catch (SocketException e) {
 // 정상 누군가 요청을 멈췄다

 } catch (Exception e) {
 try {
 response.add(ErrorResponder.makeExceptionString(e));
 response.closeAll();
 } catch (Exception e1) {
 // 이게 뭐야

 }
 }
}
private void startSending() {
 try {
 doSending();
 } catch (SocketException e) {
 // 정상 누군가 요청을 멈췄다

 } catch (Exception e) {
 addExceptionAndCloseResponse(e);
 }
}
private void addExceptionAndCloseResponse(Exception e) {
 try {
 response.add(ErrorResponder.makeExceptionString(e));
 response.closeAll();
 } catch (Exception e) {
 }
}

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

//전역 목록 <smodule>에 속하는 모듈이 우리가 속한 하위시스템에 의존하는가

if (smodule.getDependSubsystems().contains(subSysMod.getSubSystem())) {
}

ArrayList moduleDependees = smodule.getDependSubsystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem)){
} 

애매한 정의 같다.

기타

의무적으로 다는 주석

javadocs같은 형식은 코드만 헷갈리게 만들며 거짓말할 가능성을 높이며 잘못된 정보 제공 (무슨뜻인진 알지만 형식하된 포맷을 제공하면 유지보수에 더 좋을 수도 있다고 생각)

이력을 기록하는 주석

무서운 잡음

c,p 하면서 생긴 복사의 잔여물들

위치를 표시하는 주석 - 특정위치에 파일 표시

// Actions ///////////////////////////////

닫는 괄호에 다는 주석

for가 끝났는지, while이 끝났는지 등
캡슐화가 잘되어 있으면 필요 없음

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

주석으로 처리한 코드

IDE가 혹은 git이 다해줌

HTML주석

이제 주석에 HTML태그를 삽입할 필요가 없다.

전역 정보

포트값 같은 정보들(전역적이지만 바뀔수있는)은 삭제

함수헤더

비공개 코드에서 JavaDocs

api공개 할것이 아니면 javadocs 형식의 쓸데없는 코드는 필요가 없음

이 포스트는 Clean Code를 읽고 정리한 내용입니다.
http://www.yes24.com/24/goods/11681152?scode=032&OzSrank=1

Comments

comments powered by Disqus
comments powered by Disqus