'PMD'에 해당되는 글 1건

  1. 2006/10/25 PMD 자바 프로그램 분석기

PMD is a Java source code analyzer. It finds unused variables, empty catch blocks, unnecessary object creation, and so forth.


http://pmd.sourceforge.net/




원문 링크 : http://network.hanbitbook.co.kr/view.php?bi_id=623&pg=8

자바 프로그램 분석기 - PMD
[한빛미디어] 2003-04-25 13:55 / 조회수 685 글자 크게 글자 작게
저자: 한빛리포터 김영익

이 기사에서는 자바 프로그램의 소스 코드를 분석하여 프로그램의 불필요한 부분을 찾아내고 성능을 높이도록 도와주는 도구인 PMD에 대해서 소개할 것이다. PMD는 오픈 소스이고 콘솔용과 여러 에디터를 지원하므로 다양한 환경에서 자바 프로그램을 개발하는 사용자들에게 아주 유용한 물건(?)이 될 것이다.

1. PMD?

다음 사이트에 가면 PMD의 소개가 아래와 같이 간단히 있다.

http://sourceforge.net/projects/pmd/ PMD is a Java source code analyzer. It finds unused variables, empty catch blocks, unnecessary object creation, and so forth.
PMD는 자바 소스 코드 분석기로 사용하지 않는 변수, 아무 처리도 안하는 catch 블록, 불필요한 객체 생성 등등을 찾아낸다.

이 한마디가 PMD에 대한 소개의 전부이다. 그러나 PMD가 가진 기능은 정말 대단하다. 정말 위에서 말했던 기능을 전부 제공한다면 수많은 자바 개발자들이 뜨끔해 할 것이다. 하지만 이와 같은 도구를 사용하여 자신의 소스 코드를 정리하고 최적화시킨다는 것은 정말 가치 있는 일이라고 생각한다.

예전에 오라클에서 만든 JDeveloper라는 IDE에서 "Code Coach" 기능을 지원하는 것을 잠시 본적이 있었는데 PMD의 기능과 거의 유사한 기능을 가지고 있었던 기억이 난다. 그러나 JDeveloper는 상용제품이므로 많은 개발자들이 사용하지는 못할 것이다. 하지만 PMD는 오픈 소스이므로 전혀 비용부담이 없다. 게다가 여러 에디터를 지원하므로 자신의 입맛에 맞도록 선택만하면 된다. 그럼 이제부터 PMD의 설치부터 간단한 사용법에 대해서 살펴보겠다.

2. PMD 설치 및 사용

PMD는 앞에서처럼 http://sourceforge.net/projects/pmd/에 가면 다운로드 받을 수 있다. 다양한 버전이 있으므로 자신의 환경에 맞는 것을 골라서 다운로드 받도록 하자. 이 기사에서는 사용하기 편한 JBuilder용을 다운로드 받고 설명한다. 다운로드 받은 파일로 압축을 풀면 다음과 같은 2개의 파일이 있다. PMDOpenTool.jar pmd-1.02.jar 이 두 파일을 JBuilder 설치 폴더 밑의 \lib\ext에 두고 JBuilder를 실행하면 아래 그림처럼 툴바에 버튼이 3개 추가된다.


[그림 1]

첫 번째 주황색 버튼은 하나의 파일에 대해서 분석하는 "PMD Check File"이다. 두 번째 파란 버튼은 전체 프로젝트에 대해서 분석한다. 마지막 녹색 버튼은 "CPD Check Project"라고 하는데 도대체 무슨 기능인지 모르겠다. 실행을 하면 너무 오랫동안 작업진행 상태로만 있고 끝이 보이지 않는다. 이번에는 JBuilder의 왼쪽 프로젝트 트리의 화면을 보도록 하자.


[그림 2]

패키지별로 "PMD Check" 기능을 사용할 수 있다. 역시 CPD 기능은 모르겠다. 이번에는 파일 하나를 선택했을 경우이다.


[그림 3]

개별적으로 파일 하나에 대해서도 분석이 가능한 것이다. 원하는 패키지나 소스 코드에 대해서 분석을 하면 메시지가 나타나며 선택하면 해당 소스코드의 위치로 이동한다. 아래 그림은 사용되지 않는 변수에 대해서 선택했을 경우, 해당 소스 코드 부분이 노란색으로 선택된 화면이다. 빨간 메시지에 따라 적절히 소스 코드를 수정하고 다시 실행하면 빨간 줄이 없어진 것을 확인할 수 있다. 빨간 줄이 줄어들수록 얼마나 뿌듯한가?


[그림 4]

3. PMD 설정

PMD를 처음 실행하면 소스 코드를 수정하라고 권고하는 빨간 줄이 아주 많이 나타나게 된다. 내용을 살펴보면 굳이 수정하지 않아도 되는 부분에 대해서도 기분 나쁘게 보이는 경우가 있다. 이럴 때는 주저하지 말고 PMD를 자기 입맛에 맞도록 설정하여 사용하면 된다.


[그림 5]

위의 그림처럼 메뉴를 선택하면 아래 그림과 같은 PMD 설정 화면이 나타난다.


[그림 6]

다른 기능에 대해서는 잘 모르겠다. 두 번째에 있는 "PMD RuleSet Properties" 탭을 선택하고 체크 박스를 원하는 대로 설정하면 귀찮은 메시지는 출력되지 않고 자신이 작업하기를 원하는 결과에 대해서만 출력할 수 있다. 아래에 보이는 "Example Code" 탭을 선택하면 예제 소스까지 보여준다. 정말 멋진 기능이라고 할 수 있다!


[그림 7]

4. 마치면서

지금까지 간단하게 PMD를 소개하고 사용하는 법에 대해서 살펴보았다. 본인도 모르는 기능이 많아서 죄송스럽게 생각한다. 하지만 위에 소개된 기능만으로도 분명 가치있는 도구라는 점에는 여러분도 동의할 것이다. 마지막으로 자신이 예전에 작성한 프로그램에 직접 PMD를 적용해보길 권한다. 무수히 쏟아지는 빨간 메시지와 함께 자기 자신을 되돌아 볼 수 있는 계기가 될 것이다.







한국 IBM developerWorks

http://www-128.ibm.com/developerworks/kr/library/j-pmd/



PMD로 버그 잡기

손쉬운 정적 분석 툴로 버그 잡기

developerWorks
문서 옵션
이 페이지를 이메일로 보내기'); // :badtag -->
이 페이지를 이메일로 보내기

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


난이도 : 중급

Elliotte Rusty Harold, 조교수, Polytechnic University

2005 년 1 월 07 일

소스, 정적 분석 툴인 PMD는 버그를 잡기위한 툴로 손색이 없다. PMD의 사용법을 설명한다.

Tom Copeland의 PMD는 오픈 소스(BSD 라이센스) 툴로서 자바 소스 코드를 분석하여 잠재적인 버그를 찾아낸다. 일반적인 부분에서는 FindBugs와 Lint4j(참고자료)같은 툴과 비슷하다. 하지만 이 모든 툴들은 다른 버그들을 찾아내기 때문에 주어진 코드 기반에서 이들 각자를 실행하는 것이 적합하다. 이 글에서 PMD를 사용하는 방법과 활용법을 설명하겠다. PMD의 명령행 인터페이스도 연구할 예정이다. PMD를 Ant와 통합하여 자동 소스-코드 체크를 수행할 수 있고 주요 IDE와 프로그래머의 에디터를 위한 플러그인도 있다.

PMD의 설치와 실행

PMD는 자바로 작성되고 JDK 1.3 또는 이후 버전이 필요하다. 명령행을 사용하는 것이 익숙하다면 PMD의 설치와 실행은 단순하다. zip 파일을 다운로드하고(참고자료), /usr 또는 홈 디렉토리에 저장한다. 이 글에서는 /usr에 저장하는 것으로 간주하겠다.

PMD 를 실행하는 가장 쉬운 방법은 pmd.sh 스크립트(Unix/Linux) 또는 pmd.bat 스크립트(Windows)를 호출하는 것이다. 이 스크립트들은 bin 디렉토리 보다는 pmd-2.1/etc에 있다. 스크립트에는 세 개의 명령행 인자들이 있다:

  • 체크 할 .java 파일로 가는 경로
  • 아웃풋 포맷을 가르키는 html 또는 xml 키워드
  • 실행 할 규칙 세트 이름들

예를 들어, 다음 명령어는 네이밍 규칙 세트를 사용하여 ImageGrabber.java 파일을 검사하여 XML 아웃풋을 만든다:

$ /usr/pmd-2.1/etc/pmd.sh ImageGrabber.java xml rulesets/naming.xml




위로


결과 분석

위 명령어에서 나온 아웃풋은 기본적으로 System.out으로 보내지며 리포트 형식을 취한다(Listing 1):


Listing 1. PMD XML 리포트
<?xml version="1.0"?><pmd> <file name="/Users/elharo/src/ImageGrabber.java"> <violation line="32" rule="ShortVariable" ruleset="Naming Rules" priority="3"> Avoid variables with short names like j </violation> <violation line="105" rule="VariableNamingConventionsRule" ruleset="Naming Rules" priority="1"> Variables that are not final should not contain underscores (except for underscores in standard prefix/suffix). </violation> </file> <error filename="/Users/elharo/src/ImageGrabber.java" msg="Error while processing /Users/elharo/ImageGrabber.java"/> </pmd>

Listing 1에서 PMD 가 두 개의 문제들을 발견했음을 알 수 있다: ImageGrabber.java의 32번째 줄에서 짧은 변수 이름과 105번째 줄에서 밑줄을 포함하는 이름이 그것이다. 작은 문제인 것 처럼 보이지만 결과는 엄청날 수 있다. 이 경우, 105번째 줄의 밑줄은 10년 묵은 코드의 그저 픽스하기 쉬운 코드의 단편이였다. 하지만 첫 번째 문제를 검사해보면 j 변수를 완전히 제거할 수 있었다는 것을 깨닫게 된다. 왜냐하면 각각 증가되고 있었던 또 다른 변수의 기능들을 중복시키기 때문이다. 프로그램은 작동했지만 앞으로의 변화에 대비해야 하는 것보다는 훨씬 더 위험한 것이었다. 여러분이 제거한 모든 코드 라인들은 버그가 들어올 수 있는 하나의 작은 장소이다.

PMD 아웃풋을 파일로 리다이렉트 하거나 일반적인 방식으로 에디터로 전달(pipe)할 수 있다. 나는 HTML로 아웃풋을 만들어서 이것을 웹 브라우저에 로딩해 보곤 한다. (그림 1)


그림 1. PMD 아웃풋(HTML)
PMD sample output

아웃풋을 파일로 보내는 것은 소스 트리를 검사할 때 특히 유용하다. 디렉토리 이름, zip 파일, JAR 아카이브 파일을 첫 번째 인자로서 전달한다면 PMD 는 그 디렉토리 또는 아카이브에 있는 모든 .java 파일을 반복적으로 검사한다. 소량의 아웃풋이 위협적이다. 특히 PMD가 많은 오류 가능성을 만들어 낼 때 그렇다. 예를 들어 XOM 코드 베이스(참고자료)에서 PMD를 실행할 때, "in과 같은 짧은 이름을 가진 변수를 피하라(Avoid variables with short names like in" 는 보고를 지속적으로 보낸다. "in"은 InputStream을 나타내는 변수 이름으로서 완벽하다고 생각한다. 그럼에도 불구하고 괜찮은 텍스트 에디터에서 아웃풋을 검사한다면 빈번한 오류를 인식하고 지우는 것이 쉽다는 것을 알게 된다. 이들은 매우 비슷하기 때문이다. 그때 다른 재명명 문제를 픽스 할 수 있다.

PMD에서 유일하게 부족한 한 가지 기능은 "lint comment"를 소스 코드에 추가하여 명백히 위험한 연산을 수행한다는 것을 나타내는 기능이다. 이것은 기능이지 버그는 아니다. 이것 외에는 PMD는 대체적으로 괜찮다. 예를 들어, 오랜 시간동안 try-catch 블록은 XOM의 다양한 장소에서 발생했다:

try { this.data = data.getBytes("UTF8"); } catch (UnsupportedEncodingException ex) { // All VMs support UTF-8 }

PMD는 이것을 빈 catch 블록으로 플래그를 단다. VM이 UTF-8 인코딩을 인식하지 못한다는 것을 발견하게 될 때 까지는 문제가 없을 것처럼 보였다. 그래서 이 블록을 다음과 같이 바꾸고 PMD는 괜찮아졌다:

try { this.data = data.getBytes("UTF8"); } catch (UnsupportedEncodingException ex) { throw new RuntimeException("Broken VM: Does not support UTF-8"); }




위로


규칙

PMD는 16 가지 규칙 세트가 있고 자바 코드의 다양한 일반 문제들을 다룬다. 이중 어떤 것은 문제가 있는 것도 있다:

규칙 이름

명령행에서 전달되는 규칙들의 이름은 문서화가 잘 되어있지 않다. 이들을 파악하려면 여러 시도와 오류 과정을 거쳐야 한다. 괄호 안에 있는 이름들을 사용할 수 있다.

  • Basic (rulesets/basic.xml) -- 대부분의 개발자들이 동의하는 규칙: catch 블록들은 비어있어서는 안되고, equals()를 오버라이딩 할 때 마다 hashCode()를 오버라이드한다.

  • Naming (rulesets/naming.xml) -- 표준 자바 네이밍 규약을 위한 테스트: 변수 이름들은 너무 짧아서는 안된다; 메소드 이름은 너무 길어서는 안된다; 클래스 이름은 대문자로 시작해야 하고, 메소드와 필드 이름들은 소문자로 시작해야 한다.

  • Unused code (rulesets/unusedcode.xml) -- 결코 읽히지 않은 프라이빗 필드와 로컬 변수, 접근할 수 없는 문장, 결코 호출되지 않는 프라이빗 메소드 등을 찾기.

  • Design (rulesets/design.xml) -- 다양한 좋은 디자인 원리 체크, 이를 테면: switch 문장은 default 블록을 갖고 있어야 하고, 심하게 중첩된 if 블록은 피해야 하고, 매개변수들은 재할당되어서는 안되며, 더블(double)이 동일함(equality)과 비교되어서도 안된다.

  • Import statements (rulesets/imports.xml) -- 임포트 문장에 대한 작은 문제들 점검. 같은 클래스를 두 번 반입하는 것이나 java.lang에서 클래스를 임포팅하는 것 등.

  • JUnit tests (rulesets/junit.xml) -- 테스트 케이스와 테스트 메소드 관련 특정 문제 검색. 메소드 이름의 정확한 스펠링과 suite() 메소드가 정적이고 퍼블릭인지 여부.

  • Strings (rulesets/string.xml) -- 스트링 관련 작업을 할 때 발생하는 일반적인 문제들 규명. 스트링 리터럴 중복, String 구조체 호출, String 객체에 toString() 호출하기 등.

  • Braces (rulesets/braces.xml) -- for, if, while, else 문장이 괄호를 사용하는지 여부 검사.

  • Code size (rulesets/codesize.xml) -- 과도하게 긴 메소드, 너무 많은 메소드를 가진 클래스, 리팩토링에 대한 유사한 후보들을 위한 테스트.

  • Javabeans (rulesets/javabeans.xml) -- 직렬화 될 수 없는 bean 클래스 같이 JavaBeans 코딩 규약을 위배하는 JavaBeans 컴포넌트 검사.

  • Finalizers -- finalize() 메소드는 자바에서 일반적인 것은 아니기 때문에 사용법에 대한 규칙이 비교적 익숙하지 않다. 이 그룹의 검사는 finalize() 메소드 관련한 다양한 문제들을 찾는다. 이를 테면, 비어있는 finalizer, 다른 메소드를 호출하는 finalize() 메소드 finalize()로의 호출 등이 그것이다.

  • Clone (rulesets/clone.xml) -- clone() 메소드에 대한 규칙: clone()을 오버라이드하는 클래스는 Cloneable을 구현해야 하고, clone() 메소드는 super.clone()을 호출해야 하며, clone() 메소드는 실제로 던지지 않더라도 CloneNotSupportedException을 던지도록 선언되어야 한다.

  • Coupling (rulesets/coupling.xml) -- 클래스들간 과도한 커플링 표시 검색. 지나치게 많은 임포트, supertype 또는 인터페이스가 충분한 곳에서 subclass 유형 사용하기, 너무 적은 필드, 변수, 클래스 내의 리턴 유형 등.

  • Strict exceptions (rulesets/strictexception.xml) -- 예외 테스트: 메소드는 java.lang.Exception을 던지도록 선언되어서는 안되고, 예외는 플로우 제어에 사용되어서는 안되며, Throwable은 잡혀서는 안된다.

  • Controversial (rulesets/controversial.xml) -- 일부 PMD 규칙들은 유능한 자바 프로그래머가 받아들일 수 있는 것들이다. 하지만 어떤 것은 논쟁의 여지가 충분하다. 이 규칙 세트에는 좀더 의심스러운 검사들이 포함되어 있다. 변수에 null 할당하기, 메소드에서 온 다중의 리턴 포인트 sun 패키지에서 임포팅 등이 포함된다.

  • Logging (rulesets/logging-java.xml) -- java.util.logging.Logger를 위험하게 사용하는 경우 검색: 끝나지 않고 정적이지 않은 logger와 한 클래스에 한 개 이상의 logger 등.

명령행에서 이름과 콤마를 분리하여 여러 규칙 세트들을 한번에 검사할 수 있다:

$ /usr/pmd-2.1/etc/pmd.sh ~/Projects/XOM/src html rulesets/design.xml,rulesets/naming.xml,rulesets/basic.xml




위로


자신의 규칙 세트 구현하기

특정 규칙 세트로 종종 검사하고 있다면 이들을 자신만의 규칙 세트 파일로 결합할 수도 있다.(Listing 2) 이 규칙 세트는 기본 규칙, 네이밍 규칙, 디자인 규칙들을 반입한다:


Listing 2. 기본 규칙, 네이밍 규칙, 디자인 규칙들을 반입하는 규칙 세트
<?xml version="1.0"?> <ruleset name="customruleset"> <description> Sample ruleset for developerWorks article </description> <rule ref="rulesets/design.xml"/> <rule ref="rulesets/naming.xml"/> <rule ref="rulesets/basic.xml"/> </ruleset>

좀더 세분화 된 것을 원한다면 각 세트에서 원하는 개별 규칙들을 선택할 수 있다. 예를 들어 Listing 3은 세 개의 빌트인 세트에서 11 개의 특정 규칙들을 선택한 커스텀 규칙 세트를 보여주고 있다. 큰 코드 기반을 검사하는 것은 많은 시간이 걸리기 때문에 찾고자 하는 특정 문제를 보다 빨리 찾을 수 있다.


Listing 3. 11 가지 특정 규칙을 반입한 규칙 세트
<?xml version="1.0"?> <ruleset name="specific rules"> <description> Sample ruleset for developerWorks article </description> <rule ref="rulesets/design.xml/AvoidReassigningParametersRule"/> <rule ref= "rulesets/design.xml/ConstructorCallsOverridableMethod"/> <rule ref="rulesets/design.xml/FinalFieldCouldBeStatic"/> <rule ref="rulesets/design.xml/DefaultLabelNotLastInSwitchStmt"/> <rule ref="rulesets/naming.xml/LongVariable"/> <rule ref="rulesets/naming.xml/ShortMethodName"/> <rule ref="rulesets/naming.xml/VariableNamingConventions"/> <rule ref="rulesets/naming.xml/MethodNamingConventions"/> <rule ref="rulesets/naming.xml/ClassNamingConventions"/> <rule ref="rulesets/basic.xml/EmptyCatchBlock"/> <rule ref="rulesets/basic.xml/EmptyFinallyBlock"/> </ruleset>

세트 안에 대부분의 규칙들을 포함시킬 수 있지만 동의하지 않는 것이나 또는 오류 가능성들이 있는 것들은 배제할 수 있다. 예를 들어, XOM은 테이블 검색을 수행할 때 종종 switch 문장을 디폴트 블록 없이 사용한다. 나는 대부분의 디자인 규칙들을 지킬 수 있지만 <exclude name="SwitchStmtsShouldHaveDefault"/> 자식 요소를 디자인 규칙을 반입하는 규칙 요소에 추가하여 default블록을 놓치는 지에 대한 검사를 하지 않는다:


Listing 4. switch 문장이 디폴트를 가져야 한다는 디자인 규칙을 배제한 규칙 세트
<?xml version="1.0"?> <ruleset name="dW rules"> <description> Sample ruleset for developerWorks article </description> <rule ref="rulesets/design.xml"> <exclude name="SwitchStmtsShouldHaveDefault"/> </rule> </ruleset>

(PMD가 옳다면 대신 디폴트 블록을 추가해야 한다.)

빌트인 규칙에는 제한이 없다. 자바 코드를 작성하고 PMD를 재컴파일 하거나 XPath 식을 작성하여 새로운 규칙을 추가할 수 있다.





결론

(매우 비싼) 빌트인 규칙들을 사용해서 PMD는 코드의 실제 문제들을 반드시 찾아낸다. 이들 중 어떤 것은 미미하지만 어떤 것은 그렇지 않다. 모든 버그를 찾는 것은 아니다. 단위 테스트와 수락 테스트를 수행해야 한다. 또한 PMD는 알려진 버그를 잡을 때 훌륭한 디버거용 대체도 아니다. 하지만 알지 못했던 버그를 찾을 때 빛을 발한다. PMD가 문제를 찾을 수 없었던 코드 베이스를 보지 못했다. PMD는 싸고 쉬우며 재미있는 방식으로 프로그램을 향상시킨다. 전에 PMD를 사용하지 않았다면 시도해보라.







Improving Code Quality with PMD and Eclipse

http://www.eclipsezone.com/articles/pmd/

TAG