2014년 1월 16일 목요일

주석(comment)을 달지 말아야 하는 이유


일전에 애자일 개발에서의 문서화 작업에 대한 블로깅에서도 밝힌바와 같이 도큐멘테이션은 프로젝트의 목적(납품물)이 아닌 커뮤니케이션을 위한 수단이 되어야 한다. 올바른 문서화을 위한 원칙을 다시한번 간략히 살펴보자.



정보의 중복 금지: 같은 내용을 여러군데 적지 말라. 쓸데없는 노력이 들어갈 뿐만 아니라 결국에는 서로 다른 내용을 지닌 문서/코드를 보게될 것이다. 

코드에 포함 가능한 정보는 코드에 포함하라: 동일한 내용이 여러 장소에 적힐 수 있다면 코드가 우선시 되어야 한다. 코드에 표현하기 어려운 정보라면 그 다음 순위는 유지모델이 될 것이다.

라이프 사이클을 구분하여 사용하라: 프로젝트 내내 지속적으로 유지해야만 하는 유지모델과 특정 단계에서만 구성원들의 의식 통일을 위해 사용하는 임시모델을 구분하여 사용한다. 아키텍처 정의나 ER다이어그램과 같은 문서는 프로젝트가 끝난 후라 할 지라도 유지보수를 위해 여전히 유용한 반면, 특정 기능 구현을 위한 시퀀스 다이어그램이나 클래스 다이어그램과 같은 임시 모델은 회의를 진행하면서 화이트보드에 적은 내용을 디지털사진으로 남기는 것 만으로도 충분한 경우가 많다. 

주석을 달지 말아야 하는 이유

코드에 주석을 달지 말아야 하는 이유는 정보의 중복을 피하기 위해서입니다. 주석을 열심히 달기 보다는 읽기쉬운 코드를 만든는데 집중하세요. 메소드 내의 처리를 단일 기능 단위로 분할 하고 하고 각종 네이밍에 주의를 기울이십시오. 프로그램 사양에 대한 기술은 코드의 주석보다는 테스트 케이스의 Javadoc에 기대하는 동작을 기술하세요. 이렇게 작성된 Javadoc은 그 자체로서 훌륭한 상세설계서가 됩니다. - 나가사토(나가사토씨는 필자와 같은 Mamezou소속의 애자일 컨설턴트 이며 Disciplined Agile의 일본어판 번역을 비롯해 다수의 기술서적을 번역하였다.)

필자는 사실 테스트케이스의 Javadoc조차도 최소한의 내용만을 적는것이 좋다고 생각한다. 테스트 코드도 실행코드와 마찬가지로 코드 자체의 가독성을 최대화 하는것에 집중하는것이 좋다고 생각하기 때문이다.

잘 작성된 주석은 프로그램의 가독성을 매우 향상시킬 수 있는 반면, 잘못 작성된 주석은 프로그램의 가독성을 해칠 수 있다. 
코드 컴플리트(스티브 맥코넬, 2005)

주석을 달지 않는 코딩 유형은 자바의 코어 라이브러리 소스 코드를 비롯해 대부분의 오픈소스 코드에서 쉽게 확인 할 수 있다.

예제1) 스프링 소스코드
     @Override  
     public void initialize(  
             Servlet servlet, ServletRequest request, ServletResponse response,  
             String errorPageURL, boolean needsSession, int bufferSize, boolean autoFlush) {  
         throw new UnsupportedOperationException("Use appropriate constructor");  
     }  
     @Override  
     public void release() {  
     }  
     @Override  
     public void setAttribute(String name, Object value) {  
         Assert.notNull(name, "Attribute name must not be null");  
         if (value != null) {  
             this.attributes.put(name, value);  
         }  
         else {  
             this.attributes.remove(name);  
         }  
     }  
     @Override  
     public void setAttribute(String name, Object value, int scope) {  
         Assert.notNull(name, "Attribute name must not be null");  
         switch (scope) {  
             case PAGE_SCOPE:  
                 setAttribute(name, value);  
                 break;  
             case REQUEST_SCOPE:  
                 this.request.setAttribute(name, value);  
                 break;  
             case SESSION_SCOPE:  
                 this.request.getSession().setAttribute(name, value);  
                 break;  
             case APPLICATION_SCOPE:  
                 this.servletContext.setAttribute(name, value);  
                 break;  
             default:  
                 throw new IllegalArgumentException("Invalid scope: " + scope);  
         }  
     }  

예제로 제시한 코드는 주석이 필요 없을정도로 간결하다. 이번엔 테스트코드를 살펴보자.

예제2) 테스트코드
 /**  
  * Unit tests for the {@code MockPageContext} class.  
  *  
  * @author Rick Evans  
  */  
 public final class MockPageContextTests extends TestCase {  
     public void testSetAttributeWithNoScopeUsesPageScope() throws Exception {  
         String key = "foo";  
         String value = "bar";  
         MockPageContext ctx = new MockPageContext();  
         ctx.setAttribute(key, value);  
         assertEquals(value, ctx.getAttribute(key, PageContext.PAGE_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.APPLICATION_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.REQUEST_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.SESSION_SCOPE));  
     }  
     public void testRemoveAttributeWithNoScopeSpecifiedRemovesValueFromAllScopes() throws Exception {  
         String key = "foo";  
         String value = "bar";  
         MockPageContext ctx = new MockPageContext();  
         ctx.setAttribute(key, value, PageContext.APPLICATION_SCOPE);  
         ctx.removeAttribute(key);  
         assertNull(ctx.getAttribute(key, PageContext.PAGE_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.APPLICATION_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.REQUEST_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.SESSION_SCOPE));  
     }  
 }  

테스트 코드 역시 매우 간결한 모습을 띄고 있다.
코드의 가독석을 높이는 가장 좋은 방법은 코드를 심플하게 유지 하면서 네이밍, 특히 변수의 네이밍에 신경을 써 주는것이 효과적이다.

변수명과 네이밍에 대한 내용은 코드 컴플리트에서 더할나위 없이 훌륭하게 다루어지고 있으므로 아직 읽어보지 않은 분이라면 꼭 읽어들 것을 추천한다.