Posted by B정상
download  : 프리젠테이션시 확대 및 밑줄등 필요한 툴~

10월쯤에 김광석대리님이 겁나 좋다고 소개해 줬는데 관심이 없어서
그냥 지나쳤다능~ 근데 내가 넘 편한 것 발견했다고 다시 보여 줬더니
자기가 보여줄때 겁나 무신경 하더니.. 넘하다고 하하;;; 



Posted by B정상
Posted by B정상

1.원칙없는 정치 

2.노동없는 부

3.양심없는 쾌락

4.인격없는 교육

5.도덕성 없는 경제

6.인간성 없는 과학

7.희생없는 신앙


현재 위의 모든 조건에 100% 싱크율을 보이는 한국.

Posted by B정상
2009년 컨퍼런스는 JCO 컨퍼런스의 열 번째 생일을 앞두고 있습니다.
이번 10회 컨퍼런스는 저희와 개발자들에게 상당히 의미 있고, 고무적인 행사입니다.
지난 10년 동안 (개발자인) 우리의 모습을 돌아보고, 새로운 비전을 소통하는 장으로 프로그램을 만들어보려고 합니다.
 
10회 JCO 컨퍼런스에 대한 정보는 아래와 같습니다.
 
  • 시간 : 2009년 2월 28일 (토, 오전 10시 ~ 오후 6시)
  • 장소 : 삼성동 COEX 그랜드볼룸, 아셈 회의실 2 룸 (203, 208호 각 100석)
  • 주최 : 한국자바개발자협의회
  • 주관 : 전자신문사
  • 강연(안) : 총 20개 세션 (5 트랙, 4세션)
  • 기타 프로그램(안) : 토론회, hands on lab, 저자 사인회 등
  • 참가 대상 : 자바에 관심 있는 모든 개발자, 학생, 또는 일반인, 자바 관련 비즈니스 업체 또는 관련자

 이에 JCO 컨퍼런스 후원사, 기관 모집 및 선정과 관련하여 이와 같이 공지하오니 많은 관심과 참여 바랍니다.

Posted by B정상
[원문출처] http://www.ibm.com/developerworks/kr/library/j-ap07088/index.html?ca=drs-kr

사람을 위한 자동화: 지속적인 리팩터링

고정적인 분석 도구를 사용하여 코드 냄새 감지하기

developerWorks
문서 옵션
수평출력으로 설정

이 페이지 출력

이 페이지를 이메일로 보내기

이 페이지를 이메일로 보내기

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

영어원문

영어원문


제안 및 의견
피드백

난이도 : 중급

Paul Duvall, CTO, Stelligent Incorporated

옮긴이: 백기선 dwkorea@kr.ibm.com

2008 년 11 월 04 일

리팩터링은 기존의 코드를 개선하는 방법으로 잘 수용된 실천법입니다. 하지만 일관적이고 반복적인 리팩터링이 필요한 코드를 어떻게 찾을까요? 이번 사람을 위한 자동화 기사에서는 역겨운 코드를 개선하는 예제를 통해 정적 분석 도구를 사용하여 리팩터링할 코드 냄새를 식별하는 방법을 살펴볼 것입니다.


수년 동안, 나는 많은 프로젝트에서 멋진 코드부터 종이 테이프로 마구 묶여있는 코드까지 상당히 많은 양의 코드를 봐왔다. 나는 새로운 코드를 작성하고 다른 개발자들이 작성한 소스 코드를 유지 보수했다. 차라리 코드를 새로 쓰고 싶었지만, 기존 코드를 가지고 메서드의 복잡도를 낮추거나 중복되는 코드를 별도 클래스로 빼내는 작업을 즐겨 하곤 했다. 내가 경
력을 쌓기 시작한 초기에는, 대부분 새로운 코드를 작성하지 않으면, 생산성이 떨어지는 것으로 생각했다.
다행히도, 1990년대 후반에, Martin Fowler의 책
Refactoring(
참고자료 참조)에서 표면상의 행위를 변경하지 않고 기존
 코드를 개선하는 방법들을 소개해주었다. 아주 멋지다.


내가 이
연재에서 다루는 것 중 대부분이 효율성에 관한 것이다. 시간을 잡아먹는 프로세스의 양을 줄이고 그 작업을
어떻게 하면 더 빨리 할 수 있는지에 관한 것이다. 나는 이 기사에서 다루는 작업을 위해 똑같은 일을 할 것이다.
그리고 그 일들을 좀 더 효율적으로 하는 방법에 대해 이야기하겠다.



본 기사 연재에 대하여

개발자로서, 우리는 고객의 프로세스를 자동화하기 위해 일한다. 하지만 우리 중 대부분은 우리 스스로의 개발 프로세스를 자동화할 수 있는 기회를 간과하곤 한다. 더 이상 그러지 않기 위해, 사람을 위한 자동화 연재를 기획하여 소프트웨어 개발 프로세스를 자동화하는 실용적인 사용법들과 성공적으로 자동화를 언제 어떻게 적용하는지 설명하겠다.

리팩터링에 관한 일반적인 접근방법은 여러분이 새로운 코드를 추가하거나 메서드를 변경할 때 기존 코드를 조금씩 변경하는 것이다. 이 기술에 있어 주요한 것은 팀 내의 개발자들간에 일관적이지 않은 방법으로 수행된며, 그 결과 리팩터링 할 기회를 잃기 쉬워진다. 바로 이것이 저자가 고정된 분석 도구를 사용하여 코드 위반 사항을 식별하자고 주장하는 이유다. 그것을 사용하면, 여러분은 코드 기반을 전체적인 시점과 클래스 또는 메서드 수준으로 바라볼 수 있는 시야를 갖게 될 것이다. 운 좋게도, Java™ 프로그래밍에서는, 무료로 이용할 수 있는 오픈 소스 분석 도구들이 있다. CheckStyle, PMD, FindBugs, JavaNVSS, JDepent 및 기타 도구들이 있다.


본 기사에서 독자들은 다음 내용을 배울 것이다.

  • CheckStyle을 사용해 순환 복잡도(cyclomatic complexity)를 측정하고 조건문을 다형성으로 교체하기(Replace Conditional with Polymorphism) 같은 리팩터링을 제공해 조건 복잡도(conditional complexity)라는 코드 냄새를 줄인다.

  • CheckStyle을 사용해 코드 중복을 평가(assess)하고 메서드 올리기(Pull Up Method) 같은 리팩터링을 제공하여 중복된 코드(duplicated code) 코드 냄새를 제거한다.

  • PMD나 JavaNCSS를 사용해 소스 코드 줄 수(source lines of code)를 세고 메서드 추출하기(Extract Method) 같은 리팩터링을 제공해 큰 덩어리 클래스(large class)를 얇게 만든다.

  • CheckStyle이나 JDepend를 사용해 클래스의 과도한 의존성(efferent coupling)을 측정하고 메서드 이전하기(Move Method) 리팩터링을 제공하여 너무 많은 임포트(too many imports)라는 코드 냄사를 없앤다.

각각의 코드 냄새를 설명할 때 다음 형식을 따르겠다.

  1. 코드에서 문제를 암시하는 냄새를 설명한다.
  2. 냄새를 찾을 수 있는 척도를 정의한다.
  3. 코드 냄새를 발견하는 도구를 보여준다.
  4. 각각의 경우에 적당한 리팩터링과 패턴을 적용하여 코드 냄새를 수정한다.

기본적으로, 이 접근 방법은 코드 전반에 걸쳐 코드 문제를 발견하고 그것을 수정하는 틀을 제공한다. 그리고 여러분은
수정하기 전에 코드 기반에 위험한 부분에 대한 정보를 더 잘 알 수 있을 것이다. 그 외에도 이 접근 방법을 어떻게
자동화된 빌드와 통합할 수 있는지 보여주겠다.

코드에서 냄새가 나나요?

코드 냄새란 간단히 말하면 무언가 잘못 될 수 있는 코드에 대한 힌트다. 패턴처럼, 코드 냄새는 흔히 사용하는 용어를 제공하는데 이 용어로 잠재적인 이슈를 빠르게 식별할 수 있다. 본 기사에서 실제 코드 냄새가 나는 코드를 제공하면 자칫 본 기사의 코드 수가 지나치게 많아지는 문제가 생길지도 모른다. 따라서 냄새의 일부만을 보여줄 테니 독자들의 경험을 바탕으로 냄새 나는 코드의 나머지를 추측하기 바란다.

조건 복잡도

냄새: 조건 복잡도(Conditional complexity)

척도: 순환 복잡도(Cyclomatic complexity)

도구: CheckStyle, JavaNCSS, PMD

리팩터링: 조건문을 다형성으로 대체하기(Replace Conditional with Polymorphism), 메서드 추출하기(Extract Method)

냄새

조건 복잡도는 소스 코드에서 여러 형태로 나타날 수 있다. 코드 냄새 예제 중 하나는 if, while이나 for 문과 같이 여러 가지 조건문을 사용하는 것이다. 또 다른 종류의 조건 복잡도는 Listing 1에 있는 switch 문에 존재할 수도 있다.


Listing 1. switch 문을 사용하여 조건에 따라 다른 처리하기
...
switch (beerType) {
  case LAGER:  
    System.out.println("Ingredients are..."); 
	...
	break;
  case BROWNALE:
    System.out.println("Ingredients are..."); 
	...
	break;
  case PORTER  
    System.out.println("Ingredients are..."); 
	...
	break;
  case STOUT:
    System.out.println("Ingredients are..."); 
	...
	break;
  case PALELAGER:
    System.out.println("Ingredients are..."); 
	...
	break;
  ...
  default:
    System.out.println("INVALID."); 
	...
	break;
}
...

switch 문 자체로는 나쁜 것이 아니다. 하지만 각각의 케이스에서 너무 많은 선택지와 너무 많은 코드를 가지고 있다면,
리팩터링할 여지가 있는 코드로 인식할 수 있다.

척도

조건 복잡도 코드 냄새는 메서드의 순환 복잡도로 판단할 수 있다. 순환 복잡도는 1975년 Thomas McCabe가 정의한 척도다. 순환 복잡도 수(Cyclomatic Complexity Number, CCN)는 메서드에 있는 각각의 경우의 수를 측정한 것이다. 각각의 메서드는 1 CCN으로 시작해 얼마나 많은 경로가 존재하는지 알 수 있다. if, switch, while, for 문과 같은 구조는 각각 1부터 시작해 추가 경로에 따라 점수가 부가된다. 전반적으로 메서드 CCN은 그 자체의 복잡도를 암시한다. 대부분 10 CCN 이상을 대체로 복잡한 메서드로 본다.

도구

CheckStyle, JavaNCSS, PMD는 순환 복잡도를 측정할 수 있는 오픈 소스 도구다. Listing 2는 XML에 정의한 CheckStyle 규칙에 관한 코드 조각을 보여준다. CyclomaticComplexity 모듈은 CCN 최대값을 설정하고 있다.


Listing 2. CheckStyle을 설정하여 순환 복잡도가 10 이상인 메서드 찾아내기
<module name="CyclomaticComplexity">
  <property name="max" value="10"/>
</module>

Listing 2에 있는 CheckStyle 규칙 파일을 사용하여, Listing 3에 있는 갠트(Gant) 예제는 CheckStyle을 자동화된 빌드의
일부로 실행하는 방법을 보여준다("
갠트는 무엇인가?"를 참조하라).


Listing 3. 갠트 스크립트를 사용하여 CheckStyle 확인 수행하기
target(findHighCcn:"Finds method with a high cyclomatic complexity number"){
  Ant.mkdir(dir:"target/reports")
  Ant.taskdef(name:"checkstyle", 
    classname:"com.puppycrawl.tools.checkstyle.CheckStyleTask",
    classpathref:"build.classpath")
  Ant.checkstyle(shortFilenames:"true", config:"config/checkstyle/cs_checks.xml", 
    failOnViolation:"false", failureProperty:"checks.failed", classpathref:"libdir") {
    formatter(type:"xml", tofile:"target/reports/checkstyle_report.xml")
    formatter(type:"html", tofile:"target/reports/checkstyle_report.html")
    fileset(dir:"src"){
      include(name:"**/*.java")
    }
  }
}  

갠트는 무엇인가?

갠트는 자동화 빌드 도구이며 빌드 의존성 기능을 지원하는 표현력이 좋은 프로그래밍 언어를 제공한다. 개발자들은 그루비(Groovy) 프로그래밍 언어의 힘을 사용하여 갠트 스크립트를 작성한다. 갠트는 앤트(Ant) API에 모든 접근을 허용하므로 갠트 스크립트에서 앤트로 할 수 있는 모든 것을 할 수 있다(갠트에 대해 알고 싶다면, "Build software with Gant" 튜토리얼을 참고하라).

Listing 3에 있는 갠트 스크립트는 그림 1에 보이는 CheckStyle 보고서를 생성한다. 그림 맨 아래쪽에 메서드의 CheckStyle 순환 복잡도 위반사항을 확인할 수 있다.













그림 1. 최대 CCN을 위반한 메서드를 알려주는 CheckStyle 보고서
최대 CCN을 위반한 메서드를 알려주는 CheckStyle 보고서

리팩터링

그림 2는 조건을 다형성으로 교체하기(Replace Conditional with Polymorphism) 리팩터링을 표현한 UML 그림이다.


그림 2. 조건을 다형성으로 교체하기
조건을 다형성으로 교체하기

전체 그림은 여기서 확인하라.

그림 2에서 나는 다음 일을 했다.

  1. BeerType이라는 자바 인터페이스를 만든다.
  2. showIngredients()라는 공통 메서드를 정의한다.
  3. 각각의 BeerType을 구현한 클래스를 만든다.

간략하게 각각의 클래스당 메서드 하나만 제공했다. 표면상으로는 인터페이스를 만들 때 메서드를 하나 이상 정의할 수도 있다. 조건을 다형성으로 교체하기와 메서드 추출하기(뒤에서 설명하겠다) 같은 리팩터링은 코드를 더 유지 보수하기
 쉽게 만들어준다.




위로


중복 코드

냄새: 중복된 코드

척도: 코드 중복

도구: CheckStyle, PMD

리팩터링: 메서드 추출, 메서드 올리기, 템플릿 메서드 만들기, 알고리즘 교체하기

냄새

중복 코드는 아무도 모르는 새에 코드에 침투해 들어갈 수 있다. 별도 클래스로 일반화하는 것보다 코드를 복사하여 붙여 넣는 것이 더 쉬울 때도 있다. 복사-붙여넣기의 문제 중 하나는 복사한 다수의 코드가 있다는 것을 알아야 한다는 압박이고 그것들을 관리해야 한다는 것이다. 그보다 좀 더 교활한 문제는 복사한 코드를 약간씩 수정하여 메서드에 따라 그 행위가 일관적으로 동작하지 않을 때다. Listing 4는 데이터베이스 연결을 닫는 코드 예제로, 같은 코드를 두 개의 메서드가 가지고 있다.


Listing 4. 중복 코드
public Collection findAllStates(String sql) {
...
  try {
    if (resultSet != null) {
      resultSet.close();
    }
    if (stmt != null) {
      stmt.close();
    }
    if (conn != null) {
     conn.close();
   } 
   catch (SQLException se) {
     throw new RuntimeException(se);
   }
 }
...
}
...
public int create(String sql, Beer beer) {
...
  try {
    if (resultSet != null) {
      resultSet.close();
    }
    if (stmt != null) {
      stmt.close();
    }
    if (conn != null) {
     conn.close();
   } 
   catch (SQLException se) {
     throw new RuntimeException(se);
   }
 }
...
}

좀 더 좋은 IDE

본 기사의 예제에서는 갠트를 사용하여 특정 냄새를 찾았지만, 독자들은 IDE를 사용하여 이런 문제들을 발견할 수 있다. 이클립스 IDE는 다양한 분석 도구가 플러그인 형태로 제공된다. 그렇지만 IDE를 사용할 수 없는 환경에서 통합 빌드를 실행할 수 있도록 자동화 빌드 도구를 사용할 것을 권장한다.

척도

중복 코드를 찾는 데 사용할 척도는 코드 기반에 있는 클래스 내부에서, 그리고 여러 클래스 사이에서 코드 중복을 검색하는 것이다. 클래스들 사이에서의 중복을 도구의 도움 없이 찾기란 매우 힘들다. 코드를 약간 변경한 것도 종종 있기 때문에, 단순하게 복사한 코드만 측정하는 것뿐 아니라, 비슷한 코드도 측정하는 것이 중요하다.

도구

PMD의 복사/붙여넣기 디텍터( Copy/Paste Detector, CPD)와 CheckStyle은 자바 코드 기반에서 비슷한 코드를 찾는 데 사용할 수 있는 오픈 소스 도구다. CheckStyle 설정 파일
예제는 Listing 5에 있으며
StrictDuplicateCode 모듈을 사용한다.


Listing 5. CheckStyle을 사용하여 최소 열 줄의 중복 코드 찾기
<module name="StrictDuplicateCode">
  <property name="min" value="10"/>
</module>

Listing 5에서 min 속성은 CheckStyle이 다시 봐야 할 코드로 구분할 최소 중복 코드 줄 수에 해당한다. 여기서는,
최소한 열 줄의 코드가 비슷하거나 중복되었을 때만 알려주도록 설정했다.

그림 3은 Listing 5의 설정으로 자동화 빌드를 실행한 결과를 보여준다.


그림 3. 최소 중복 코드 라인 수를 초과한 코드를 나타내는 CheckStyle 보고서
최소 중복 코드 라인 수를 초과한 코드를 나타내는 CheckStyle 보고서

리팩터링

Listing 6에서 나는 Listing 4의 중복 코드를 메서드 추출하기 리팩터링을 사용하여 중복을 제거했다. 이 리팩터링은
덩어리가 큰 메서드에서 일부 행위를 추상 클래스 메서드로 추출하는 것이다.


Listing 6. 메서드 추출하기
...
} finally {
  closeDbConnection(rs, stmt, conn);
}
...

테스트 작성을 잊지 말라

기존 코드를 수정할 때마다 JUnit 같은 프레임워크를 사용하여 그에 상응하는 자동화 테스트를 반드시 작성해야 한다. 기존 코드를 수정하는 위험은 항상 존재한다. 그 위험을 최소화하는 방법은 현재 그리고 미래에도 잘 동작할지 테스트를 통해 검증하는 것이다.

중복 코드는 항상 나타난다. 나는 팀 내에서 무조건 모든 중복 제거라는 비현실적인 목표를 설정하는 것을 절대로 권장하지 않는다. 그 대신, 적절한 목표를 세워 코드 기반에서 중복 코드가 늘어나지 않도록 한다. PMD의 CPD 또는 CheckStyle 같은, 고정적인 분석 도구를 사용하여 지속적인 빌드의 일부로 고도의 코드 중복에 대한 판단을 계속해서 할 수 있을 것이다.




위로


긴 메서드(그리고 큰 클래스)

냄새: 긴 메서드(그리고 큰 클래스)

척도: 소스 코드 줄(Source lines of code, SLOC)

도구: PMD, JavaNCSS, CheckStyle

리팩터링: 메서드 추출, 임시 변수를 질의로 대체, 매개변수 객체 도입, 전체 객체 보존, 메서드를 메서드 객체로 대체

냄새

내가 지키려고 노력하는 최우선 규칙은 메서드 코드 줄 수를 스무 줄 이하로 하는 것이다. 물론, 이 규칙에 예외는 있을 수 있다. 하지만 내가 스무 줄이 넘는 메서드를 작성했는지, 그것을 알고 싶기도 하다. 보통, 긴 메서드와 조건 복잡도 사이에는
연관이 있기도 하다. 그리고 큰 클래스와 긴 메서드에도 연관이 있다. 내가 유지 보수해야만 했던 프로젝트에서 발견한 2200줄짜리 메서드 예제를 보여주는 것을 좋아한다. 2만 5000 줄에 달하는 전체 클래스를 출력하여 내 동료에게 버그를 찾아보라고 했다. 그 때 출력한 코드는 바닥에 던져버렸다.

Listing 7에서 굵게 표시한 부분은 긴 메서드 코드 냄새 예제의 일부를 보여준다.


Listing 7. 긴 메서드 코드 냄새
public void saveLedgerInformation() {
...
try {
  if (ledger.getId() != null && filename == null) {
    getLedgerService().saveLedger(ledger);
  } else {
    accessFiles().decompressFiles(files, filenames);
  } 
  if (!files.get(0).equals(upload)) {
    upload = files.get(0);
    filename = filenames.get(0);
  }
  if (invalidFiles.isUnsupported(filename)) {
    setError(fileName, message.getMessage());
  } else {
  LedgerFile entryFile = accessFiles().add(upload, filename);
  if (fileType != null && FileType.valueOf(fileType) != null) {
    entryFile.setFileType(FileType.valueOf(fileType));
  }
  getFileManagementService().saveLedger(ledger, entryFile);
  if (!FileStatus.OPENED.equals(entryFile.getFileStatus())) {
    getFileManagementService().importLedgerDetails(ledger);
  }
  if (uncompressedFiles.size() > 1) {
    Helper.saveMessage(getText("ledger.file"));
  }
  
  if (user.getLastName() != null) {
    SearchInfo searchInfo = ServiceLocator.getSearchInfo();
    searchInfo.setLedgerInfo(null);
    isValid = false;
    setDefaultValues();
    resetSearchInfo();
    if (searchInfoValid && ledger != null) {
      isValid = true;
    }
  }
  
} catch (InvalidDataFileException e) {
  ResultType result = e.getResultType();
  for (ValidationMessage message : result.getMessages()) {
    setError(fileName, message.getMessage());
  }
  ledger.setEntryFile(null);


} ...

척도

SLOC 측정은 최근까지 생산성을 측정하는 용도로 오용되어 왔다. 그렇지만 이제 우리는 더 많은 코드를 작성하는 것이 꼭 더 좋은 것만은 아님을 알고 있다. 그래도 SLOC는 복잡도를 나태내는 척도로 사용할 수 있다. 메서드(또는 클래스) 줄 수가 길수록, 미래에 해당 코드를 유지 보수하는 것이 더 힘들어질 것이다.

도구

Listing 8의 스크립트는 긴 메서드(와 그 외에 큰 클래스)의 SLOC 측정치를 찾아낸다. Listing 8의 스크립트는 긴 메서드(와 그 외에 큰 클래스)의 SLOC 측정치를 찾아낸다.


Listing 8. 큰 클래스와 메서드를 식별하는 갠트 스크립트
target(findLongMethods:"runs static code analysis"){
 Ant.mkdir(dir:"target/reports")
 Ant.taskdef(name:"pmd", classname:"net.sourceforge.pmd.ant.PMDTask",
   classpathref:"build.classpath")
 Ant.pmd(shortFilenames:"true"){
   codeSizeRules.each{ rfile ->
    ruleset(rfile)
   }
   formatter(type:"xml", tofile:"target/reports/pmd_report.xml")
   formatter(type:"html", tofile:"target/reports/pmd_report.html")
   fileset(dir:"src"){
     include(name:"**/*.java")
   }
  }  
}

다시 한 번, 갠트를 사용하여 앤트 API에 접근하여 앤트 태스크를 실행했다. Listing 8에서 나는 PMD 정적 분석 도구를 호출하여 코드 기반에서 긴 메서드를 검색했다. PMD(JavaNCSS와 CheckStyle과 함께)는 또한 긴 메서드, 큰 클래스, 그리고 많은 다른 코드 냄새를 찾는 데 활용할 수 있다.

리팩터링

Listing 9는 메서드 추출하기 리팩터링을 사용하여 Listing 7의 긴 메서드 냄새를 줄이는 예제를 보여준다. Listing 7의
메서드에서 행위를 추출하여 Listing 9의 코드로 옮겼다. 이제 새로 만든
isUserValid() 메서드를 Listing 7의 saveLedgerInformation() 메서드에서 호출할 수 있다.


Listing 9. 메서드 추출 리팩터링
private boolean isUserValid(User user) {
  boolean isValid = false;
  if (user.getLastName() != null) {
    SearchInfo searchInfo = ServiceLocator.getSearchInfo();
    searchInfo.setLedgerInfo(null);
    setDefaultValues();
    resetSearchInfo();
    if (searchInfoValid && ledger != null) {
      isValid = true;
    }
  }
  return isValid;
}

보통, 긴 메서드와 큰 클래스는 조건 복잡도와 중복 코드 같은 여타 코드 냄새를 암시한다. 이런 메서드와 클래스를
발견함으로써 다른 문제들을 수정할 수 있다.




위로


너무 많은 임포트(import)

냄새: 너무 많은 임포트

척도: 과도한 의존성(클래스당 팬 아웃(fan-out))

도구: CheckStyle

리팩터링: 메서드 이전, 클래스 추출

냄새

너무 많은 임포트는 클래스가 너무 많은 다른 클래스에 의존한다는 것을 암시한다. 이 코드 냄새 때문에 어떤 클래스를
변경하면 너무 많은 다른 클래스들도 함께 수정해야 하는 경우가 생김을 알아챌 수 있을 것이다. 이는 해당 클래스가
변경에 너무 밀접하게 의존하기 때문이다. Listing 10은 여러 임포트 문을 가지고 있는 예제다.


Listing 10. 하나의 클래스에 여러 임포트 문
import com.integratebutton.search.SiteQuery;
import com.integratebutton.search.OptionsQuery;
import com.integratebutton.search.UserQuery;
import com.integratebutton.search.VisitsQuery;
import com.integratebutton.search.SiteQuery;
import com.integratebutton.search.DateQuery;
import com.integratebutton.search.EvaluationQuery;
import com.integratebutton.search.RangeQuery
import com.integratebutton.search.BuildingQuery;
import com.integratebutton.search.IPQuery;
import com.integratebutton.search.SiteDTO;
import com.integratebutton.search.UrlParams;
import com.integratebutton.search.SiteUtil;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
...

척도

너무 많은 책임을 지닌 클래스를 찾는 방법은 과도한 의존성을 측정하는 것이다. 이는 팬 아웃 복잡도(fan out complexity)
라고 하기도 한다. 팬 아웃 복잡도는 해당 클래스의 의존도에 따라 1씩 증가한다.

도구

Listing 11은 CheckStyle을 사용하여 팬 아웃 복잡도 최대치를 설정하는 예제다.


Listing 11. CheckStyle을 사용하여 팬 아웃 복잡도 최대치 설정하기
<module name="ClassFanOutComplexity">
  <property name="max" value="10"/>
</module>

패턴을 활용한 리팩터링

팩토리 메서드(Factory Method) 패턴은 리팩터링을 할 때 적용할 수 있는 다양한 디자인 패턴 중 하나다. 팩토리 메서드는 명시적으로 생성하려는 실제 클래스 타입을 정의할 필요가 없도록 하는 접근 방법이다. 이 패턴은 구체적인 클래스가 아닌 인터페이스를 사용하도록 하는 한 기술이다. 코드 냄새를 리팩터링할 때 다른 디자인 패턴을 적용할 수도 있다. 참고자료를 참조하여 이 주제에 관한 책 링크를 확인하라.

리팩터링

너무 많은 임포트로 인해 생기는 밀접한 의존도를 수정하는 방법에는 여러 가지가 있다. Listing 10과 같은 코드의 경우, 메서드 이전(Move Method) 리팩터링을 적용할 수 있다. 나는 메서드를 *Query 클래스에서 다른 Query 클래스들이 반드시 구현할 인터페이스에 메서드를 정의했다. 그러고 나서, 팩토리 메서드 패턴을 이용하여 인터페이스를 사용하여 의존하게 했다.

갠트 자동 빌드 스크립트를 사용하여 CheckStyle 앤트 태스크를 실행한다. 나는 자신의 코드 베이스에서 너무 많은 클래스에 의존하는 클래스를 찾을 수 있다. 이런 클래스들의 코드를 수정할 때, 유지 보수성을 높이기 위해 메서드 이전 같은 리팩터링과 특정 디자인 패턴을 같이 활용한다.




위로


일찍 그리고 자주 리팩터링하라

지속적인 통합(CI)은 변경 사항을 자주 통합하는 실천 기법이다. 일반적인 실천 사항으로, 자동화 CI 서버, 별도 빌드 머신을
 갖추고, 자동화 빌드를 버전 관리 저장소에 프로젝트 변경 사항을 반영할 때마다 실행한다.
Listing 3Listing 8이 코드 기반의 모든 변경 사항에 일관적으로 적용되는지 확인할 때, Hudson(참고자료 참조) 같은 CI 서버에 설정할 수 있을 것이다.

Listing 3Listing 8에 있는 예제가 갠트를 사용하기 때문에, 허드슨 CI 서버에 갠트 스크립트를 설정하는 과정을 설명하겠다.

  1. 허드슨 대시보드에서 허드슨용 갠트 플러그인을 설치한다. Manage Hudson을 선택하고 Available 탭을 선택한다. 이 탭에서 갠트 플러그인 체크 박스를 선택하고 Install 버튼을 클릭한다.

  2. 웹 컨테이너를 다시 시작한다(예, 톰캣).

  3. Manage Hudson을 선택하고, Configure System을 선택한다. Gant installation 섹션에서, 식별할 이름을 주고 허드슨을 실행하는 머신에 설치된 그루비 설치 위치를 설정한다. 변경 사항들을 저장한다.

  4. 대시보드로 돌아가(Hudson 링크를 클릭한다) existing Hudson Job을 선택한다. Configure를 선택하고, Add build step 버튼을 클릭한다. 그리고 Invoke Gant script 옵션을 선택한다.

갠트로 작성한 자동 빌드 스크립트를 실행하기 위한 허드슨 설정으로, 코드 기반에 생기는 긴 메서드, 조건 복잡도 같은 코드 냄새에 대한 측정치를 빠른 피드백으로 얻을 수 있다.




위로


다른 냄새와 리팩터링

모든 냄새가 그것을 측정할 척도를 가진 것은 아니다. 하지만 고정적인 분석 도구로 여기서 살펴본 냄새 하나를 통해 다른 냄새들까지 발견할 수 있다. 표 1은 다른 코드 냄새 예제, 도구, 가능한 리팩터링을 나열한 것이다.


표 1. 다른 냄새와 리팩터링
냄새 도구 리팩터링
죽은 코드 PMD 코드 제거
임시 필드 PMD 인라인 임시 변수
일관되지 않고 알 수 없는 이름 CheckStyle, PMD 메서드, 필드 이름 바꾸기
긴 매개변수 목록 PMD 매개변수를 메서드로 대체, 전체 객체 보존, 매개변수 객체 도입

본 기사는 자동 고정 분석 도구에 끼워 넣을 수 있는 설정으로 코드 냄새와 관련이 있는 척도를 측정하는 패턴을 제공한다. 디자인 패턴을 사용하거나 사용하지 않고도 리팩터링할 수 있다. 이것으로 반복적으로 수정할 코드 냄새를 찾아낼 수 있는 어떤 틀을 제공한다. 이 글의 예제를 통해 독자들이 고정적인 분석 도구를 사용하여 여기서 설명하지 않은 다른 종류의 코드 냄새도 찾아낼 수 있으리라 확신한다.



참고자료

교육

제품 및 기술 얻기
  • 갠트(Gant): 갠트를 다운로드하고 예측 가능하며 반복 가능한 소프트웨어 구축을 시작하라.

  • CheckStyle: CheckStyle을 다운로드하여 특정 코드 냄새를 더 잘 발견하고 그에 대한 정보를 얻으라.

  • PMD: PMD을 다운로드하여 특정 코드 냄새를 더 잘 발견하고 그에 대한 정보를 얻으라.

  • 허드슨(Hudson): 무료로 사용할 수 있는 오픈 소스 CI 서버


토론


필자소개

Paul Duvall

Paul Duball은 Stelligent Incorporated의 CTO로, 개발팀이 배포 준비가 된 소프트웨어를 도출할 수 있도록 돕는 애자일 컨설팅을 하고 있다. Paul Duball은 Addison-Wesley 시그너처 시리즈 책인, Continuous Integration: Improving Software Quality and Reducing Risk(Addison-Wesley Professional, 2007년, 2008 졸트 상 수상작)의 공동 저자이기도 하다. 또 UML 2 Toolkit(Wiley, 2003년)과 No Fluff Just Stuff Anthology(Programatic Programmers, 2007년)에도 기여했다

Posted by B정상
지난 주말 nhn에서 개발된 소프트웨어를 오픈하였습니다.
그중 자바로 개발된 neptune 프로젝트도 같이 오픈되었는데 같이 개발을 진행할 개발자를 찾고 있습니다.

http://dev.naver.com/projects/neptune

neptune은 수십 ~ 수백대의 분산된 서버에 수십 TB 이상 대규모의 구조화된 데이터를 저장, 서비스하는 데이터 관리 시스템입니다. neptune을 이용하면 실시간 데이터 서비스뿐만 아니라 Hadoop MapReduce와 같은 분산컴퓨팅 플랫폼과 유기적으로 동작하여 쉽고 빠르게 저장된 데이터를 분석할 수 있습니다. neptune과 같은 대용량 데이터 저장소는 클라우드 컴퓨팅 환경에서 기반 플랫폼으로 반드시 필요합니다.

neptune은 자바로 개발되었으며 neptune 내부에는 다음과 같은 기술을 사용하고 있습니다.

- 분산된 서버들 간의 통신을 위한 RPC(Remote Procedure Call)
- 신뢰성 높은 changelog 처리
- Hadoop 분산파일시스템 활용
- Hadoop MapReduce 활용
- 분산 락 메커니즘
- Java NIO
- Java Concurrency
- AOP(Aspect Oriented Programming)
- 분산 아키텍처
- JavaCC
- JGroup

neptune 프로젝트에 참여하시면 위의 모든 기술을 직접 접할 수 있습니다.개발뿐만 아니라 문서화, QA, 문서영문화 등 많은 부분에서 여러분의 참여가 필요합니다.(다음달 해외 오픈도 추진 예정입니다.)
한국 개발자들이 많이 참여해서 좋은 오픈소스 프로젝트로 발전했으면 합니다. 감사합니다.

* 프로젝트 참여 관련: http://dev.naver.com/wiki/neptune/index.php/참여방법
Posted by B정상