Code Quality
Assurance with PMD
(ongoing cleanups)
Herold Business Data
2004 to 2006


   Peter Kofler, ‘Code Cop’
       @codecopkofler
     www.code-cop.org
 Copyright Peter Kofler, licensed under CC-BY.
PETER KOFLER, CODE-COP.ORG                  FANATIC ABOUT CODE QUALITY




                             Peter Kofler
  • Ph.D. in Applied Math

  • Professional Software
    Developer

  • Developer at Herold Business Data

  • “fanatic about code quality”
Agenda
PETER KOFLER, CODE-COP.ORG   FANATIC ABOUT CODE QUALITY




        Status Daily Build
        Static Code Analysis
        Rule Categorisation
        Rules to fix/obey ;-)
PETER KOFLER, CODE-COP.ORG                 FANATIC ABOUT CODE QUALITY




                             Daily Build
  • Since three months
  • Trunk is compiling (at least more often)
        – missing files 
        – shared subproject complexity 
  • Build history
  • JavaDoc
  • XML validation
PETER KOFLER, CODE-COP.ORG                  FANATIC ABOUT CODE QUALITY




                             Next Steps

  • Static code analysis
        – check the source

  • JUnit integration
        – of few existing tests

  • Initialise application
        – integration tests (that would be cool)
Static Analysis
PETER KOFLER, CODE-COP.ORG             FANATIC ABOUT CODE QUALITY




          PMD Static Code Analyser
  • http://pmd.sourceforge.net/
  • Scans Java source
  • JavaCC-generated parser
        – Abstract Syntax Tree (AST)
  • Traverses AST
  • Reports violations
PETER KOFLER, CODE-COP.ORG                    FANATIC ABOUT CODE QUALITY




                             Eclipse Plugin
  • Install pmd-eclipse2-site-2.0RC3.zip
  • Patch plugin with current PMD:
        – extract pmd.jar from pmd-bin-1.5.zip
        – rename to pmd-1.3.jar and replace in
          pluginsnet.sourceforge.pmd.core_1.3.2lib
  • Customise rules:
        – delete all and import PMD20040427.xml
Rule
Categorisation
PETER KOFLER, CODE-COP.ORG             FANATIC ABOUT CODE QUALITY




                             “Error”

  • Really serious errors
        – e.g. bad practice
        – or correctness bugs

  • Currently (only ;-) 125
       in whole code base
PETER KOFLER, CODE-COP.ORG               FANATIC ABOUT CODE QUALITY




                             “Warning”
  • Other errors




  • Currently 4023
PETER KOFLER, CODE-COP.ORG            FANATIC ABOUT CODE QUALITY




                    “Info” (Information)
  • Minor errors
        – e.g. performance problems



  • Currently 4091
PETER KOFLER, CODE-COP.ORG              FANATIC ABOUT CODE QUALITY




                             “Format”
  • Formatting Problems
        – e.g. code style violations



  • Currently 6834
Fix It!
PETER KOFLER, CODE-COP.ORG                   FANATIC ABOUT CODE QUALITY




                             “Fix” Process
  • Activate not (yet) triggered rules
        – make sure there are no new violations
  • Fix few “bad guys” first
  • Activate their rules
  • Choose next error from list, repeat
  • In the end only low priority bugs left
PETER KOFLER, CODE-COP.ORG           FANATIC ABOUT CODE QUALITY




                   Not Triggered Errors
  •    BadComparison if (y == Double.NaN)
  •    EmptyFinalizer
  •    FinalizeOnlyCallsSuperFinalize
  •    FinalizeOverloaded
  •    ShortMethodName (<= 3)
  •    SuspiciousHashcodeMethodName
       public int hashcode() // <-> hashCode
PETER KOFLER, CODE-COP.ORG           FANATIC ABOUT CODE QUALITY



  • EmptyWhileStmt
    while (a == b) {
       // maybe here was some code before
    }
  • NonStaticInitializer
    // public void doSomething()
    {
       // this block gets run before any
       // call to any constructor
       System.out.println("construct myself");
    }
PETER KOFLER, CODE-COP.ORG          FANATIC ABOUT CODE QUALITY



             MethodWithSameName
               AsEnclosingClass

  public class MyClass
  {
    // bad because it is a method
    public void MyClass() { }
    // OK because it is a constructor
    public MyClass() { }
  }
PETER KOFLER, CODE-COP.ORG                  FANATIC ABOUT CODE QUALITY



  • JumbledIncrementer
    for (int i = 0; i < 10; i++) {
      for (int k = 0; k < 20; i++) {
        System.out.println("Hello");
      }
    }
  • NonCaseLabelInSwitchStatement
       switch (a) {
         case 1 : // do something
                  break;
         mylabel : // legal but confusing
                  break;
       }
PETER KOFLER, CODE-COP.ORG     FANATIC ABOUT CODE QUALITY




             Not Triggered Warnings
  • DefaultLabelNotLastInSwitchStmt
  • DontImportJavaLang
  • EmptyStaticInitializer
  • EmptySwitchStatements
  • EmptySynchronizedBlock
  • EmptyTryBlock &
    EmptyFinallyBlock
  • ImportFromSamePackage
PETER KOFLER, CODE-COP.ORG          FANATIC ABOUT CODE QUALITY



  • ForLoopShouldBeWhileLoop
    for (; true;) {
      // no init or update part
      // may as well be: while (true)
    }

  • SuspiciousOctalEscape
    public void foo() {
      System.out.println("suspicious: 128");
      // interpreted as octal 12,
      // followed by character '8'
    }
Epic Evil
PETER KOFLER, CODE-COP.ORG                 FANATIC ABOUT CODE QUALITY




             10 Serious Errors (to fix)
  •    EmptyCatchBlock
  •    ExplicitCallToFinalize
  •    FinalizeDoesNotCallSuperFinalize
  •    FinalizeShouldBeProtected
  •    JUnitSpelling
        – framework methods are easy to misspell
  • JUnitStaticSuite
        – suite() method needs to be public and static
PETER KOFLER, CODE-COP.ORG                FANATIC ABOUT CODE QUALITY




    DoubleCheckedLocking (is broken)
  public Object getInstance() {
    if (inst == null) {        // may be non-null
       synchronized (this) { // yet not fully created
         if (inst == null)
            inst = new Object();
       }
    }
    return inst;
  }
PETER KOFLER, CODE-COP.ORG       FANATIC ABOUT CODE QUALITY




OverrideBothEqualsAndHashcode
   • Override both
     boolean Object.equals(Object o) and
     int Object.hashCode(),
     or override neither.

   • HashMap uses first hashCode() method
     and then equals() method inside the
     hash-bucket...
PETER KOFLER, CODE-COP.ORG           FANATIC ABOUT CODE QUALITY




                Contract of hashCode
  • Same objects must return same integer
  • If two objects are equals(), the
    hashCode() method on each of them
    must produce the same integer.
  • It is not required that if two objects are
    unequal according to the equals(), the
    two objects must produce distinct
    results.
PETER KOFLER, CODE-COP.ORG       FANATIC ABOUT CODE QUALITY




        hashCode Implementation
  private String member;
  public int hashCode() {
    // calculate hashCode from int-values
    // of all members and sum them up
    int result = 17;
    result = 37*result+member.hashCode();
    return result;
  }
PETER KOFLER, CODE-COP.ORG        FANATIC ABOUT CODE QUALITY




     ProperCloneImplementation
  • should be implemented with
    super.clone()

  public Object clone() {
    return new MyClass();    // wrong
  }
PETER KOFLER, CODE-COP.ORG              FANATIC ABOUT CODE QUALITY




                 clone Implementation
  public Object clone() {
    try {
      return super.clone();
    } catch (CloneNotSupportedException e) {
      // should not happen, we are Cloneable
      throw new InternalError(”error in clone");
    }
  }
PETER KOFLER, CODE-COP.ORG            FANATIC ABOUT CODE QUALITY




            ReturnFromFinallyBlock
  public String bugga() {
     try {
        throw new Exception("My Exception");
     } catch (Exception e) {
        throw e;
     } finally {
        return ”O.K.";    // bad
     }
  }
Avoid!
PETER KOFLER, CODE-COP.ORG                        FANATIC ABOUT CODE QUALITY




          More Warnings (to avoid)
  • AvoidCatchingThrowable
        – there will be some exceptions to this rule...
  • ExcessiveClass- & -MethodLength
  • ExcessiveParameterList
  • FinalizeOverloaded
  • SignatureDeclareThrowsException
  • SwitchStmtsShouldHaveDefault
PETER KOFLER, CODE-COP.ORG                 FANATIC ABOUT CODE QUALITY




              ExceptionTypeChecking
  try {
    returnString = sdf.format(value);
  } catch (Exception e) {
    /* BAD STUFF */
    if (e instanceof NumberFormatException)
       System.out.println("NumberFormat!!!");
    if (ex instanceof IllegalArgumentException)
       System.out.println("illegal argument...!!!");
  }
PETER KOFLER, CODE-COP.ORG             FANATIC ABOUT CODE QUALITY



                ConstructorCalls
             OverridableMethodRule
  public class Senior {
   public Senior() {
     toString(); // may throw a NPE if overridden
   }

      public String toString() {
        return "IAmSenior";
      }
  }
PETER KOFLER, CODE-COP.ORG              FANATIC ABOUT CODE QUALITY



            ConstructorCalls
       OverridableMethodRule #2
  public class Junior extends Senior {
    private String name;
    public Junior() {
       super(); // inserted by compiler -> NPE
       name = "JuniorClass";
     }
    public String toString() {
       return name.toUpperCase();
    }
  }
Update
PETER KOFLER, CODE-COP.ORG                  FANATIC ABOUT CODE QUALITY




    Second Iteration (November)
  • Improve quality 
  • 1st iteration removed all 125 errors 
     – 100 seems to be a good work package 
  • In the meantime ...
        – PMD has been updated
        – New rules are available (and in use ;-)
  • Now let’s fix another 8 rules
        – With approx. 100 violations
PETER KOFLER, CODE-COP.ORG                       FANATIC ABOUT CODE QUALITY




                             5 Errors (to fix)
  • AvoidCatchingNPE
  • AvoidThrowingCertainExceptionTypes
  • EmptyStatementNotInLoop
     if (false);
     {
       // will be executed
     }
  • ForLoopsMustUseBraces &
    WhileLoopsMustUseBraces
PETER KOFLER, CODE-COP.ORG               FANATIC ABOUT CODE QUALITY




                       3 Warnings (to fix)
  • BooleanInstantiation
    new Boolean(*)  Boolean.valueOf(*)
  • UnnecessaryReturn
  • UnusedImports – Eclipse warning
PETER KOFLER, CODE-COP.ORG             FANATIC ABOUT CODE QUALITY




          New and Not Triggered #1
  • DontImportSun (not in HP’s JDK)
  • EqualsNull
    if (x.equals(null)) { // never true
  • BrokenNullCheck
    if (s!=null || !s.equals(””)) { // use && !

  • JUnitTestsShouldIncludeAssert
  • TestClassWithoutTestCases
PETER KOFLER, CODE-COP.ORG        FANATIC ABOUT CODE QUALITY




         New and Not Triggered #2
  • SimplifyStartsWith
    startsWith(”a”) charAt(0)=='a'
  • AppendCharacterWithChar
    b.append(”a”) b.append('a')
  • UseIndexOfChar
    s.indexOf(”a”) s.indexOf('a')

  • AvoidProtectedFieldInFinalClass
PETER KOFLER, CODE-COP.ORG     FANATIC ABOUT CODE QUALITY




                             Thank
                              You
PETER KOFLER, CODE-COP.ORG          FANATIC ABOUT CODE QUALITY




                             Peter Kofler

                    @codecopkofler

      www.code-cop.org
PETER KOFLER, CODE-COP.ORG                                FANATIC ABOUT CODE QUALITY




                             CC Images
  •    cleaning: http://www.flickr.com/photos/inf3ktion/4477642894/
  •    agenda: http://www.flickr.com/photos/24293932@N00/2752221871/
  •    micro: http://www.flickr.com/photos/wessexarchaeology/183177852/
  •    trash: http://www.flickr.com/photos/togr/244902037/
  •    building: http://www.flickr.com/photos/stephen_rees/440201126/
  •    evil: http://www.flickr.com/photos/legofenris/4476593087/
  •    avoid: http://www.flickr.com/photos/howardlake/4850758742/
  •    repeat: http://www.flickr.com/photos/cyanocorax/288232991/
  •    questions: http://www.flickr.com/photos/seandreilinger/2326448445/

Code Quality Assurance with PMD (2004)

  • 1.
    Code Quality Assurance withPMD (ongoing cleanups) Herold Business Data 2004 to 2006 Peter Kofler, ‘Code Cop’ @codecopkofler www.code-cop.org Copyright Peter Kofler, licensed under CC-BY.
  • 2.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Peter Kofler • Ph.D. in Applied Math • Professional Software Developer • Developer at Herold Business Data • “fanatic about code quality”
  • 3.
  • 4.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Status Daily Build Static Code Analysis Rule Categorisation Rules to fix/obey ;-)
  • 5.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Daily Build • Since three months • Trunk is compiling (at least more often) – missing files  – shared subproject complexity  • Build history • JavaDoc • XML validation
  • 6.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Next Steps • Static code analysis – check the source • JUnit integration – of few existing tests • Initialise application – integration tests (that would be cool)
  • 7.
  • 8.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY PMD Static Code Analyser • http://pmd.sourceforge.net/ • Scans Java source • JavaCC-generated parser – Abstract Syntax Tree (AST) • Traverses AST • Reports violations
  • 9.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Eclipse Plugin • Install pmd-eclipse2-site-2.0RC3.zip • Patch plugin with current PMD: – extract pmd.jar from pmd-bin-1.5.zip – rename to pmd-1.3.jar and replace in pluginsnet.sourceforge.pmd.core_1.3.2lib • Customise rules: – delete all and import PMD20040427.xml
  • 10.
  • 11.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY “Error” • Really serious errors – e.g. bad practice – or correctness bugs • Currently (only ;-) 125 in whole code base
  • 12.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY “Warning” • Other errors • Currently 4023
  • 13.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY “Info” (Information) • Minor errors – e.g. performance problems • Currently 4091
  • 14.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY “Format” • Formatting Problems – e.g. code style violations • Currently 6834
  • 15.
  • 16.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY “Fix” Process • Activate not (yet) triggered rules – make sure there are no new violations • Fix few “bad guys” first • Activate their rules • Choose next error from list, repeat • In the end only low priority bugs left
  • 17.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Not Triggered Errors • BadComparison if (y == Double.NaN) • EmptyFinalizer • FinalizeOnlyCallsSuperFinalize • FinalizeOverloaded • ShortMethodName (<= 3) • SuspiciousHashcodeMethodName public int hashcode() // <-> hashCode
  • 18.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY • EmptyWhileStmt while (a == b) { // maybe here was some code before } • NonStaticInitializer // public void doSomething() { // this block gets run before any // call to any constructor System.out.println("construct myself"); }
  • 19.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY MethodWithSameName AsEnclosingClass public class MyClass { // bad because it is a method public void MyClass() { } // OK because it is a constructor public MyClass() { } }
  • 20.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY • JumbledIncrementer for (int i = 0; i < 10; i++) { for (int k = 0; k < 20; i++) { System.out.println("Hello"); } } • NonCaseLabelInSwitchStatement switch (a) { case 1 : // do something break; mylabel : // legal but confusing break; }
  • 21.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Not Triggered Warnings • DefaultLabelNotLastInSwitchStmt • DontImportJavaLang • EmptyStaticInitializer • EmptySwitchStatements • EmptySynchronizedBlock • EmptyTryBlock & EmptyFinallyBlock • ImportFromSamePackage
  • 22.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY • ForLoopShouldBeWhileLoop for (; true;) { // no init or update part // may as well be: while (true) } • SuspiciousOctalEscape public void foo() { System.out.println("suspicious: 128"); // interpreted as octal 12, // followed by character '8' }
  • 23.
  • 24.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY 10 Serious Errors (to fix) • EmptyCatchBlock • ExplicitCallToFinalize • FinalizeDoesNotCallSuperFinalize • FinalizeShouldBeProtected • JUnitSpelling – framework methods are easy to misspell • JUnitStaticSuite – suite() method needs to be public and static
  • 25.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY DoubleCheckedLocking (is broken) public Object getInstance() { if (inst == null) { // may be non-null synchronized (this) { // yet not fully created if (inst == null) inst = new Object(); } } return inst; }
  • 26.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY OverrideBothEqualsAndHashcode • Override both boolean Object.equals(Object o) and int Object.hashCode(), or override neither. • HashMap uses first hashCode() method and then equals() method inside the hash-bucket...
  • 27.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Contract of hashCode • Same objects must return same integer • If two objects are equals(), the hashCode() method on each of them must produce the same integer. • It is not required that if two objects are unequal according to the equals(), the two objects must produce distinct results.
  • 28.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY hashCode Implementation private String member; public int hashCode() { // calculate hashCode from int-values // of all members and sum them up int result = 17; result = 37*result+member.hashCode(); return result; }
  • 29.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY ProperCloneImplementation • should be implemented with super.clone() public Object clone() { return new MyClass(); // wrong }
  • 30.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY clone Implementation public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { // should not happen, we are Cloneable throw new InternalError(”error in clone"); } }
  • 31.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY ReturnFromFinallyBlock public String bugga() { try { throw new Exception("My Exception"); } catch (Exception e) { throw e; } finally { return ”O.K."; // bad } }
  • 32.
  • 33.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY More Warnings (to avoid) • AvoidCatchingThrowable – there will be some exceptions to this rule... • ExcessiveClass- & -MethodLength • ExcessiveParameterList • FinalizeOverloaded • SignatureDeclareThrowsException • SwitchStmtsShouldHaveDefault
  • 34.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY ExceptionTypeChecking try { returnString = sdf.format(value); } catch (Exception e) { /* BAD STUFF */ if (e instanceof NumberFormatException) System.out.println("NumberFormat!!!"); if (ex instanceof IllegalArgumentException) System.out.println("illegal argument...!!!"); }
  • 35.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY ConstructorCalls OverridableMethodRule public class Senior { public Senior() { toString(); // may throw a NPE if overridden } public String toString() { return "IAmSenior"; } }
  • 36.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY ConstructorCalls OverridableMethodRule #2 public class Junior extends Senior { private String name; public Junior() { super(); // inserted by compiler -> NPE name = "JuniorClass"; } public String toString() { return name.toUpperCase(); } }
  • 37.
  • 38.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Second Iteration (November) • Improve quality  • 1st iteration removed all 125 errors  – 100 seems to be a good work package  • In the meantime ... – PMD has been updated – New rules are available (and in use ;-) • Now let’s fix another 8 rules – With approx. 100 violations
  • 39.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY 5 Errors (to fix) • AvoidCatchingNPE • AvoidThrowingCertainExceptionTypes • EmptyStatementNotInLoop if (false); { // will be executed } • ForLoopsMustUseBraces & WhileLoopsMustUseBraces
  • 40.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY 3 Warnings (to fix) • BooleanInstantiation new Boolean(*)  Boolean.valueOf(*) • UnnecessaryReturn • UnusedImports – Eclipse warning
  • 41.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY New and Not Triggered #1 • DontImportSun (not in HP’s JDK) • EqualsNull if (x.equals(null)) { // never true • BrokenNullCheck if (s!=null || !s.equals(””)) { // use && ! • JUnitTestsShouldIncludeAssert • TestClassWithoutTestCases
  • 42.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY New and Not Triggered #2 • SimplifyStartsWith startsWith(”a”) charAt(0)=='a' • AppendCharacterWithChar b.append(”a”) b.append('a') • UseIndexOfChar s.indexOf(”a”) s.indexOf('a') • AvoidProtectedFieldInFinalClass
  • 43.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Thank You
  • 44.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY Peter Kofler @codecopkofler www.code-cop.org
  • 45.
    PETER KOFLER, CODE-COP.ORG FANATIC ABOUT CODE QUALITY CC Images • cleaning: http://www.flickr.com/photos/inf3ktion/4477642894/ • agenda: http://www.flickr.com/photos/24293932@N00/2752221871/ • micro: http://www.flickr.com/photos/wessexarchaeology/183177852/ • trash: http://www.flickr.com/photos/togr/244902037/ • building: http://www.flickr.com/photos/stephen_rees/440201126/ • evil: http://www.flickr.com/photos/legofenris/4476593087/ • avoid: http://www.flickr.com/photos/howardlake/4850758742/ • repeat: http://www.flickr.com/photos/cyanocorax/288232991/ • questions: http://www.flickr.com/photos/seandreilinger/2326448445/