walkmodhttp://www.walkmod.com-­‐ twitter:  @walkmod Raquel  Pau  (rpau@walkmod.com) Let’s  start  working  with  clean  code! 1
A bit of me • Technical  lead  at  Walkmod • Software  engineer  at  Sparsity-­‐Technologies • JavaCodeGeekswriter • Research  publications  about  UML/OCL 2
First Law of Software Quality error  =  (more  code)2 E  =  mc2 Moral: some errors always come back 3
Ok, we need some help… 4
Really? 5
Developers principle DRY 6
Walkmod is for.. • Automatizing the  resolution  of  problems   detected  by  code  quality  tools • Automatizing the  practice  of  code   conventions  in  development  teams  (e.g create   CRUD  services) • Automatizing global  code  changes  (e.g migrations) 7
and it is... • Open source (LGPL  v3) – Discover  what  is  happening  with  your  code! – It  is  the  result  of  contributions  by  people  with  the   same  needs. • Editor/ide independent – Command  line  interface – Maven/Gradle plugin 8
challenges • Automatic  source  code  fixes  must  be  applied   without  re-­‐formatting • False-­‐positives are  not  allowed • Plugins support  for  custom  code  conventions • Automatic  software  updates. 9
LET’S PLAY APPLYING WALKMOD IN GOOGLE/GUAVA 10
commands (1) • walkmod  plugins • walkmod  inspect  ${pluginid} • walkmod  add  ${pluginid:transformationid} • walkmod  apply  /  check 11
commands (2) • walkmod  set-­‐reader  -­‐d  ${path}  ${reader} • walkmod  set-­‐writer  -­‐d  ${path}  ${writer} • walkmod  add-­‐excludes  ${file} • walkmod  add-­‐includes  ${file} 12
google/guava results 501  java  files  in  113  sec  ~  4,4  files/sec 13
HOW  IT  WORKS FROM BOTTOM TO TOP 14
Execution Workflow 1. Parsing  process   2. Semantic  analysis   3. Run  code  transformations 4. Write  the  applied  changes 15
parsing process CompilationUnit  cu =  ASTManager.parse( "public  class  Foo  {  "+ "public  boolean  test(int[]  x[])  {  "+ "return  false;"+ "  }"+ "  }  "); TypeDeclaration  td =  cu.getTypes().get(0); MethodDeclaration  md =  (MethodDeclaration)  td.getMembers().get(0); 16
semantic analysis: type resolution • Resolves  the  java.lang.Class of  every  single   expression “hello”.substring(1).indexOf(“o”)  +      3 • Resolves  the  java.lang.Method of  every  single   MethodCallExpression node. c.  getEmployees().get(0) string string int int int com.foo.Company#getEmployees() java.util.List#get(int) 17
semantic analysis: definitions and references class MyClass { private int my_field; } class MyClass { private int myField; } All  my_field references  need  to  be  updated! this.my_field = my_field; this.myField = my_field; 18
Semantic analysis: API • SymbolDataAware#getSymbolData() • SymbolDefinition#getUsages() • SymbolReference#getSymbolDefinition() • ScopeAware Interface  for  SymbolDefinition,  SymbolReference  &  BlockStmt – #getVariableDefinitions() – #getTypeDefinitions() – #getMethodDefinitions() • Refactorizable#rename(String name) Interface  for  VariableDeclaration  &  Parameter. Applies  safe  updates  to  all  the  references  to  that  variable/parameter. 19
semantic analysis: External symbol references RefactorConfigurationController #getMethodRefactorRules class MyClass { public int bar_(){} } class MyClass { public int bar(){} } {Foo:bar_() => Foo:bar()} 20
semantic analysis benefits • Ensures  non  false-­‐positives  J • Powerful  transformations: – Remove  dead  code – Naming  conventions  /  migrations – Class  hierarchy  queries 21
code transformations @RequiresSemanticAnalysys public class HelloVisitor   extends VoidVisitorAdapter<VisitorContext>   { ... @Override public void visit(MethodDeclaration  md,  VisitorContext  ctx){ //TODO super.visit(md,   ctx); } @Override public void visit(FieldDeclaration  fd,  VisitorContext  ctx){ //TODO fd.getType().accept(this,  ctx); } }   22
Semantic rules testing public class UseCollectionIsEmptyTest extends SemanticTest { @Test public void testEqualsToZero() throws Exception { CompilationUnit cu = compile( "import java.util.List; “+ ” public class Foo { “+ ”public boolean testIsEmpty(List list){“+ ” return list.size() == 0; }}"); UseCollectionIsEmpty visitor = new UseCollectionIsEmpty(); cu.accept(visitor, null); MethodDeclaration md = (MethodDeclaration) cu.getTypes() .get(0).getMembers().get(0); BlockStmt block = md.getBody(); ReturnStmt returnStmt = (ReturnStmt) block.getStmts().get(0); Assert.assertTrue(returnStmt.getExpr() instanceof MethodCallExpr); } } 23
writing the applied changes • eclipse-formatter (default):  files  are  written   using  an  eclipse  formatter  configuration. • javalang:string-writer:  files  are  written   applying  the  minimum  change  set. > walkmod set-writer ${writer} 24
CREATING  A  CODE  CONVENTION TO FIX A SONAR RULE VIOLATION 25
General working procedure 1. Fork  walkmod/walkmod-sonar-plugin 2. Git checkout  master 3. Create  a  new  visitor  per  rule 4. Create  a  test 5. Define  it  in  the  walkmod-sonar-plugin.xml 6. Create  pull  request 7. We  deploy  the  changes  under  a  new  version   to  the  maven  repository 26
Let’s go to implement this rule 27
Local integration tests 1. Go  to  the  walkmod-­‐sonar-­‐plugin  directory 2. Execute  mvn install 3. Replace  jars: 1. Open  the  following  directory: ${HOME}/.ivy2/cache/org.walkmod/walkmod-­‐sonar-­‐plugin/jars 2. Replace  the  jar  that  has  the  same  name  than   walkmod-­‐sonar-­‐plugin/target/walkmod-­‐sonar-­‐plugin-­‐${version}.jar 4. Run  walkmod  apply  -­‐-­‐offline 28
ROADMAP TO IMPROVE THE USER EXPERIENCE 29
our roadmap is • More  fine  incremental  execution • Report  the  changes  introduced  by  each   transformation.  Why  they  appear? • Support  more  sonar/checkstyle/pmd rules  ;) • Full  integration  with  Intellij/eclipse/netbeans 30
and...walkmodhub • SaaS  to  run  walkmod  after: – Every  push  or  pull  request  to  Github – Incremental  execution – Sends  a  pull  request  with  the  required  changes • Get  your  clean  code  sticker! 31
THANKS Raquel  Pau   rpau@walkmod.com 32

BarcelonaJUG2016: walkmod: how to run and design code transformations

  • 1.
    walkmodhttp://www.walkmod.com-­‐ twitter:  @walkmod Raquel  Pau  (rpau@walkmod.com) Let’s  start  working  with  clean  code! 1
  • 2.
    A bit ofme • Technical  lead  at  Walkmod • Software  engineer  at  Sparsity-­‐Technologies • JavaCodeGeekswriter • Research  publications  about  UML/OCL 2
  • 3.
    First Law ofSoftware Quality error  =  (more  code)2 E  =  mc2 Moral: some errors always come back 3
  • 4.
    Ok, we needsome help… 4
  • 5.
  • 6.
  • 7.
    Walkmod is for.. •Automatizing the  resolution  of  problems   detected  by  code  quality  tools • Automatizing the  practice  of  code   conventions  in  development  teams  (e.g create   CRUD  services) • Automatizing global  code  changes  (e.g migrations) 7
  • 8.
    and it is... •Open source (LGPL  v3) – Discover  what  is  happening  with  your  code! – It  is  the  result  of  contributions  by  people  with  the   same  needs. • Editor/ide independent – Command  line  interface – Maven/Gradle plugin 8
  • 9.
    challenges • Automatic  source  code  fixes  must  be  applied   without  re-­‐formatting • False-­‐positives are  not  allowed • Plugins support  for  custom  code  conventions • Automatic  software  updates. 9
  • 10.
  • 11.
    commands (1) • walkmod  plugins • walkmod  inspect  ${pluginid} • walkmod  add  ${pluginid:transformationid} • walkmod  apply  /  check 11
  • 12.
    commands (2) • walkmod  set-­‐reader  -­‐d  ${path}  ${reader} • walkmod  set-­‐writer  -­‐d  ${path}  ${writer} • walkmod  add-­‐excludes  ${file} • walkmod  add-­‐includes  ${file} 12
  • 13.
    google/guava results 501  java  files  in  113  sec  ~  4,4  files/sec 13
  • 14.
    HOW  IT  WORKS FROMBOTTOM TO TOP 14
  • 15.
    Execution Workflow 1. Parsing  process   2. Semantic  analysis   3. Run  code  transformations 4. Write  the  applied  changes 15
  • 16.
    parsing process CompilationUnit  cu=  ASTManager.parse( "public  class  Foo  {  "+ "public  boolean  test(int[]  x[])  {  "+ "return  false;"+ "  }"+ "  }  "); TypeDeclaration  td =  cu.getTypes().get(0); MethodDeclaration  md =  (MethodDeclaration)  td.getMembers().get(0); 16
  • 17.
    semantic analysis: type resolution •Resolves  the  java.lang.Class of  every  single   expression “hello”.substring(1).indexOf(“o”)  +      3 • Resolves  the  java.lang.Method of  every  single   MethodCallExpression node. c.  getEmployees().get(0) string string int int int com.foo.Company#getEmployees() java.util.List#get(int) 17
  • 18.
    semantic analysis: definitions andreferences class MyClass { private int my_field; } class MyClass { private int myField; } All  my_field references  need  to  be  updated! this.my_field = my_field; this.myField = my_field; 18
  • 19.
    Semantic analysis: API • SymbolDataAware#getSymbolData() •SymbolDefinition#getUsages() • SymbolReference#getSymbolDefinition() • ScopeAware Interface  for  SymbolDefinition,  SymbolReference  &  BlockStmt – #getVariableDefinitions() – #getTypeDefinitions() – #getMethodDefinitions() • Refactorizable#rename(String name) Interface  for  VariableDeclaration  &  Parameter. Applies  safe  updates  to  all  the  references  to  that  variable/parameter. 19
  • 20.
    semantic analysis: External symbolreferences RefactorConfigurationController #getMethodRefactorRules class MyClass { public int bar_(){} } class MyClass { public int bar(){} } {Foo:bar_() => Foo:bar()} 20
  • 21.
    semantic analysis benefits •Ensures  non  false-­‐positives  J • Powerful  transformations: – Remove  dead  code – Naming  conventions  /  migrations – Class  hierarchy  queries 21
  • 22.
    code transformations @RequiresSemanticAnalysys public classHelloVisitor   extends VoidVisitorAdapter<VisitorContext>   { ... @Override public void visit(MethodDeclaration  md,  VisitorContext  ctx){ //TODO super.visit(md,   ctx); } @Override public void visit(FieldDeclaration  fd,  VisitorContext  ctx){ //TODO fd.getType().accept(this,  ctx); } }   22
  • 23.
    Semantic rules testing publicclass UseCollectionIsEmptyTest extends SemanticTest { @Test public void testEqualsToZero() throws Exception { CompilationUnit cu = compile( "import java.util.List; “+ ” public class Foo { “+ ”public boolean testIsEmpty(List list){“+ ” return list.size() == 0; }}"); UseCollectionIsEmpty visitor = new UseCollectionIsEmpty(); cu.accept(visitor, null); MethodDeclaration md = (MethodDeclaration) cu.getTypes() .get(0).getMembers().get(0); BlockStmt block = md.getBody(); ReturnStmt returnStmt = (ReturnStmt) block.getStmts().get(0); Assert.assertTrue(returnStmt.getExpr() instanceof MethodCallExpr); } } 23
  • 24.
    writing the appliedchanges • eclipse-formatter (default):  files  are  written   using  an  eclipse  formatter  configuration. • javalang:string-writer:  files  are  written   applying  the  minimum  change  set. > walkmod set-writer ${writer} 24
  • 25.
    CREATING  A  CODE  CONVENTION TO FIX A SONAR RULE VIOLATION 25
  • 26.
    General working procedure 1.Fork  walkmod/walkmod-sonar-plugin 2. Git checkout  master 3. Create  a  new  visitor  per  rule 4. Create  a  test 5. Define  it  in  the  walkmod-sonar-plugin.xml 6. Create  pull  request 7. We  deploy  the  changes  under  a  new  version   to  the  maven  repository 26
  • 27.
    Let’s go toimplement this rule 27
  • 28.
    Local integration tests 1.Go  to  the  walkmod-­‐sonar-­‐plugin  directory 2. Execute  mvn install 3. Replace  jars: 1. Open  the  following  directory: ${HOME}/.ivy2/cache/org.walkmod/walkmod-­‐sonar-­‐plugin/jars 2. Replace  the  jar  that  has  the  same  name  than   walkmod-­‐sonar-­‐plugin/target/walkmod-­‐sonar-­‐plugin-­‐${version}.jar 4. Run  walkmod  apply  -­‐-­‐offline 28
  • 29.
    ROADMAP TO IMPROVE THEUSER EXPERIENCE 29
  • 30.
    our roadmap is •More  fine  incremental  execution • Report  the  changes  introduced  by  each   transformation.  Why  they  appear? • Support  more  sonar/checkstyle/pmd rules  ;) • Full  integration  with  Intellij/eclipse/netbeans 30
  • 31.
    and...walkmodhub • SaaS  to  run  walkmod  after: – Every  push  or  pull  request  to  Github – Incremental  execution – Sends  a  pull  request  with  the  required  changes • Get  your  clean  code  sticker! 31
  • 32.