FireDrago
[Clean Code] 4장 - 주석 본문
주석은 나쁜 코드를 보완하지 못한다.
- 주석은 코드로 의도를 표현하지 못할때 사용한다. 코드만이 정확한 정보를 제공하는 유일한 출처다
주석을 줄이도록 꾸준히 노력해야 한다.
코드로 의도를 표현하라
- 깔끔하며 주석이 없는 코드가, 복잡하고 어수선하며 주석이 많은 코드보다 훨씬 좋다.
좋은 주석 - 유익하거나 필요한 주석
법적인 주석
- 소스파일 첫머리에 깔끔하게 정리된 저작권 정보와 소유권 정보
정보를 제공하는 주석
- 기본적인 정보를 제공하는 주석, 하지만 이때도 코드로 주석을 없앨 수 있다.
//테스트 중인 Responder 인스턴스를 반환한다
protected abstract Responder responderInstance();
//위 주석은 나쁘지 않지만, 함수명을 바꿔줌으로써 주석이 필요없어진다.
protected abstract Responder responderBeingTested();
// kk:mm:ss EEE, MMM dd yyyy 형식이다. (정규표현식을 설명)
pattern timeMatcher = pattern.compile("\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*");
의도를 설명하는 주석
- 구현을 이해하는것을 넘어서 결정에 깔린 의도까지 설명하는 경우
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; //좋은 유형이므로 정렬 순위가 더 높다
}
(WikiPagePath 클래스의 객체와 비교하여 두 WikiPagePath 객체의 names 배열을 합친 문자열을 비교하고 그 결과에 따라 정렬 순서를 결정하는 코드 ( wikiPagePath 객체가 아니면 무조건 this 객체가 우선))
public void testConcurrentAddWidgets() throws Exception {
WidgetBuilder widgetBuilder = new WidgetBuilder(new Class[]{BoldWidget.class});
String text = "'''bold text'''";
PratentWidget parent = new BoldWidget(new MockWidgetRoot(), "'''bold text'''");
AtomicBoolean failFlag = new AtomicBoolean();
failFlag.set(false);
// 스레드를 대량 생성하는 방법으로 어떻게든 경쟁 조건을 만들려 시도한다.
for (int i=0; i<25000; i++) {
WidgetBuilderThread widgetBuilderThread = new WidgetBuilderThread(widgetBuilder, text, parent, failFlag);
Thread thread = new Thread(widgetBuilderThread);
thread.start();
}
assertEquals(false, failFlag.get());
}
}
( 솔직히 이 코드 이해못했다.;; 어렵다)
의미를 명료하게 밝히는 주석
- 인수나 반환값을 명확하게 바꾸기 어려운 표준라이브러리나 변경불가 코드인 경우 의미를 밝혀주는 주석
결과를 경고하는 주석
- 다른 프로그래머에게 결과를 경고하는 주석
// 여유시간이 충분하지 않다면 실행하지 마십시오
public void _testWithReallyBigFile( ) {
writeLinesToFile(10000000);
response.setBody(testFile);
response.readyToSend(this);
String responseString = output.toString( );
assertSubString("Content-Length: 1000000000", responsestring);
assertTrue(bytesSent > 1000000000);
}
(큰 파일을 생성하고 해당 파일의 내용을 HTTP 응답으로 보내고, 그 응답의 내용과 길이를 확인하는 코드)
public static SimpleDataformat makeStandardHttpDateFormat( ) {
// SimpleDateFomat은 스레드에 안전하지 못하다.
// 따라서 각 인스턴스를 독립적으로 생성해야 한다.
SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
return df;
}
TODO 주석
- TODO 주석을 통해 '앞으로 할 일'을 주석으로 남긴다.
- 필요없는 기능의 삭제 알림, 문제를 봐달라는 요청, 좋은 이름을 부탁, 발생할 이벤트에 맞춰 수정할것 등
// TODO-MdM 현재 필요하지 않다.
// 체크아웃 모델을 도입하면 함수가 필요 없다.
protected VersionInfo makeVersion() throws Exception {
return null;
}
중요성을 강조하는 주석
- 자칫 넘어갈 수 있는 중요한 내용을 강조하는 주석
String listItemContent = match.group(3).trim();
// 여기서 trim은 정말 중요하다. trim 함수는 문자열에서 시작 공백을 제거한다.
// 문자열에 시작 공백이 있으면 다른 문자열로 인식되기 때문이다.
공개 API에서 Javadocs
- 공개 API를 구현한다면 반드시 Javadocs도 깔끔하게 작성해야한다.
Javadocs도 주석처럼 잘못된 정보를 전달하지 않도록 주의해야한다.
나쁜 주석 - 대부분의 주석은 여기에 속한다
주절거리는 주석
- 올바른 의미 판독이 불가능한 주석
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");
}
}
(의도나 근거도 없는데 부정확한 주석, this.closed가 true로 변하는 순간에 메서드는 반환되지 않는다.)
/**
* 컨테이너 관련된 Logger 구현
*/
protected Log logger = null;
/**
* 관련된 logger 이름
*/
protected string logName = null;
/**
* 사람이 읽을 수 있는 컨테이너 이름
*/
protected string name = null;
(주석의 목적에 기여하지 못한다.)
의무적으로 다는 주석
- 모든 함수에 Javadocs를 달거나 모든 변수에 주석을 달아야 한다는 법칙은 없다. 오히려 혼동을 초래할 수 있다.
/**
* @param title CD 제목
* @oaram author CD 저자
* @oaram 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);
}
이력을 기록하는 주석
- 더이상 편집 로그를 주석에 달지마라, github 에 맡겨라
있으나 마나 한 주석
- 너무 당연한 사실을 언급하여, 새로운 정보제공이 없는 주석을 사용하지마라
//기본 생성자
protected AnnualDateRule()
//월 중 일자
private int dayOfMonth;
try {
response.add(ErrorResponder.makeExceptionString(e));
response.closeAll();
} catch {
// 이게뭐야!!!
}
(코드 짜다가 빡쳤나보다.....)
무서운 잡음
- Javadocs 문서도 잡음이 될 수 있다.
/** The name. */
private String name;
/** The version */
private String version;
함수나 변수로 표현 할 수 있다면 주석을 달지마라
- 주석은 코드를 개선하여 표현할 방법이 없을 때 사용하는 것이다.
// 전역목록 <smodule>에 속하는 모듈이 우리가 속한 하위 시스템에 의존하는가?
if (smodule.getDependSubsystems().contains(subSysMod.getSubSystem()))
ArrayList moduleDependees = smodule.getDependendSubsystems();
String ourSubsystem = subsysMod.getSubSyste();
if (moduleDependees.contains(ourSubSystem))
(코드로 상세하게 표현하면 주석은 필요없어진다.)
위치를 표시하는 주석
- 소스코드에 위치를 표시하기위한 주석은 가독성을 낮춘다.
닫는 괄호에 다는 주석
- 닫는 괄호에 주석을 달고싶어진다면, 함수를 줄이도록 시도해보자
try {
while ((line = in.readLine()) != null) {
lineCount++;
charCount += line.length();
string words[] = line.split("\\W");
wordCount += words.length;
} //while
System.out.println("wordCount = " + wordCount);
System.out.println("lineCount = " + lineCount);
System.out.println("charCount = " + charCount);
} // try
(코드가 길면 주석으로 끝을 표시해주고 싶어진다. 주석대신 코드를 줄이자)
공로를 돌리거나 저자를 표시하는 주석
- Github 는 누가 언제 어떻게 추가했는지 똑똑히 기억한다. 주석으로 표시해줄 필요는 없다.
주석으로 처리한 코드
- 주석으로 처리된 코드는 다른 사람들이 지우는것을 주저하게 만든다. 점점 쓸모없는 코드가 쌓인다.
- 코드를 기억하는 것은 Github에 맡겨라
HTML 주석
- HTML 주석은 가독성이 매우 떨어진다. 사용하지 말자
전역정보
- 주석은 근처의 코드만 설명해야한다. 시스템 어딘가에 있는 다른 코드를 여기서 설명하지 마라
// 적합성 테스트가 동작하는 포트: 기본값은 <b>8082</b>
public void setFitnessePort(int fitnessePort) {
this.fitnessePort = fitnesseport;
}
(이 함수에서는 포트 기본값을 다루지 않는다. 다른 함수에 달아야할 주석인 것이다. HTML 주석은 덤이다.)
너무 많은 정보
- 주석에다 관련없는 정보를 장황하게 늘어놓지 마라
모호한 관계
- 주석과 주석이 설명하는 코드는 둘 사이의 관계가 명확해야 한다.
/*
* 모든 픽셀을 담을 만큼 충분한 배열로 시작한다(여기에 필터 바이트를 더한다.)
* 그리고 헤더 정보를 위해 200바이트를 더한다.
*/
this.pngBytes = new byte[((this.width+1) * this.height * 3) + 200];
(필터바이트의 의미가 불명확하다. 필터바이트는 +1인가? *3인가?)
함수 헤더
- 짧은 함수는 설명이 필요없다. 이름을 잘 붙이고 한가지 일을 수행하는 짧은 함수는 함수헤더 주석이 필요없다.
비공개 코드에서 Javadocs
- 공개하지 않을 코드라면 Javadocs는 필요없다.
사용하지 말아야할 여러 주석 유형이 있는 것 처럼 보이지만 결국 코드로 드러나지 않는 정보를 짧게 제공하는 주석이 중요하다는 것을 알 수 있다. 하지만 그 어떤 경우에도 주석은 없는 것이 최고다. 코드가 그만큼 잘 표현되었다는 의미니까
'책' 카테고리의 다른 글
| [Clean Code] 6장 - 객체와 자료구조 (0) | 2023.09.22 |
|---|---|
| [Clean Code] 5장 - 형식 맞추기 (0) | 2023.09.21 |
| [Clean Code] 3장 - 함수 (0) | 2023.09.19 |
| [Clean Code] 2장 - 의미있는 이름 (0) | 2023.09.18 |
| [Clean Code]1장 - 깨끗한 코드 (0) | 2023.09.16 |
