walkmod - JUG talk

48
walkmod a tool to apply coding conventions @walkmod http://walkmod.com

Transcript of walkmod - JUG talk

Page 1: walkmod - JUG talk

walkmoda tool to apply coding conventions

@walkmod http://walkmod.com

Page 3: walkmod - JUG talk

how it works

introduction

query engine

merge engine

plugins

roadmap

transformations

Page 4: walkmod - JUG talk

motivation

• Don’t repeat yourself (DRY) principle. Multiple layer architectures contains lots of wrappers, which might be generated. E.g. Tests, DAOs, Facades..

• The application domain relevance. The business rules / domain logic can’t be generated (really?). We need to focus on this!

• Code review of ALL contributors. Who fixes the code?

Introduction

Page 5: walkmod - JUG talk

Introduction

Page 6: walkmod - JUG talk

What are coding conventions?

“coding conventions are a set of guidelines for a specific programming language that recommend programming style, practices and methods for

each aspect of a piece program written in this language.” wikipedia

Introduction

Page 7: walkmod - JUG talk

examples

• Naming conventions

• Code formatting

• Code licenses

• Code documentation

• Code refactoring

• Apply programming practices

• Architectural best practices

• More..

Introduction

Page 8: walkmod - JUG talk

examplesIntroduction

Page 9: walkmod - JUG talk

walkmod• automatizes the practice of code conventions in development teams

(i.e license usage).

• automatizes the resolution of problems detected by code quality tools (i.e PMD, , sonar, findbugs).

• automatizes the development and repetitive tasks i.e: creating basic CRUD services for the entire model.

• automatizes global code changes: i.e refactorings.

Introduction

Page 10: walkmod - JUG talk

walkmod is open!

• open source: feel free to suggest changes!

• free for everybody: tell it to your boss!

• extensible by plugins do it yourself and share them! DIY+S

• editor/IDE independent

• community support

Introduction

Page 11: walkmod - JUG talk

how it works

introduction

query engine

merge engine

plugins

roadmap

transformations

Page 12: walkmod - JUG talk

workflowhow it works

• All conventions are applied with blocks of transformations for each source file.

• Transformations may update the same sources or creating/updating another ones.

Page 13: walkmod - JUG talk

overview• reader: reads the sources. i.e retrieves all files from a directory

recursively.

• walker: executes a chain of transformations for each source.

• transformation: updates or creates sources for the following transformation. Transformations are connected like a pipe through a shared context.

• writer: writes the sources. i.e using the eclipse formatter.

how it works

Page 14: walkmod - JUG talk

reader

• Reads the sources. By default, reads the folder src/main/java.

• Works with multiple include/exclude rules.

• Creates a resource object, whose content is iterated from the walker.

• Works for sources of any programming language. The resource object could be a source folder, a parsed json file, etc..

how it works

Page 15: walkmod - JUG talk

walker• Executes a chain of transformations for each object allocated in a

resource. i.e all java source files of an specific folder.

• merges the output produced by transformations with existent resources.

• invokes the writer with the final (and merged) output.

• analyzes and reports which changes have been produced by the chain of transformations in each object.

how it works

Page 16: walkmod - JUG talk

transformations

• modifies or creates objects that will be written.

• There are three ways to design a transformation. Using:

templates,

scripts,

or visitors.

how it works

Page 17: walkmod - JUG talk

writer

• writes each object allocated in a resource. i.e all java source files of a specific folder.

• Has include/exclude rules.

• There are useful writer implementations, such as the storage of the contents of a toString() object method or the eclipse formatter.

how it works

Page 18: walkmod - JUG talk

rememberhow it works

Page 19: walkmod - JUG talk

introduction

query engine

merge engine

plugins

roadmap

transformations

how it works

Page 20: walkmod - JUG talk

why templates?transformations

• Templates are used to avoid manipulating the AST directly.

• Generates dynamic content querying the AST.

• DRY compliance.

• groovy is the default template engine, but can be customized.

Page 21: walkmod - JUG talk

template configuration

<!DOCTYPE walkmod PUBLIC "-//WALKMOD//DTD" "http://www.walkmod.com/dtd/walkmod-1.0.dtd"> <walkmod> ... <transformation type="walkmod:commons:template" >

<param name="templates">["src/main/walkmod/templates/jpa-entities.groovy"]

</param></transformation>

... </walkmod>

transformations

Page 22: walkmod - JUG talk

why scripts?

• Scripts allow the design of inline transformations.

• Scripts should be used to apply simple modifications in source files.

• Support for multiple languages. Those which implement the standard Java scripting interface. i.e. groovy, javascript, python..

transformations

Page 23: walkmod - JUG talk

script configurationtransformations

... <transformation type="walkmod:commons:scripting" >

<param name="language">groovy

</param><param name="location">

src/main/walkmod/scripts/fields.groovy</param>

</transformation> ...

Page 24: walkmod - JUG talk

why visitors?

• Visitors are developed and compiled in java.

• To include transformations as plugins to be shared inside the community.

• Visitors should be used to apply complex modifications in source files.

transformations

Page 25: walkmod - JUG talk

visitor transformations

public class HelloVisitor extends VoidVisitor<VisitorContext>{...@Overwritepublic void visit(MethodDeclaration md, VisitorContext ctx){//TODO

}

@Overwritepublic void visit(FieldDeclaration fd, VisitorContext ctx){//TODO

}...

}

transformations

Page 26: walkmod - JUG talk

visitor configurationtransformations

<!DOCTYPE walkmod PUBLIC "-//WALKMOD//DTD" "http://www.walkmod.com/dtd/walkmod-1.0.dtd"> <walkmod>

<plugins> <plugin groupId="mygroupId" artifactId="myartifactId" version="versionNumber"> </plugin> </plugins>

... <transformation type="mygroupId:myartifactId:my-visitor" >

<param name="param1">value1

</param><param name="paramN">

valueN</param>

</transformation> ... </walkmod>

Page 27: walkmod - JUG talk

how it works

introduction

query engine

merge engine

plugins

roadmap

transformations

Page 28: walkmod - JUG talk

query engine• Write less to do the same!

• All queries have an object context and a query expression. By default, the context is the root element of a parsed source file.

• The default query language is gPath (groovy), but you can change it for your favorite language.

• Common used large query expressions can be referenced from Alias. “TypeDeclaration.metaClass.getMethods = { -> delegate.members.findAll({it instanceof MethodDeclaration}); }”

query engine

Page 29: walkmod - JUG talk

query engine

MethodDeclaration method = null;

Collection members = type.getMembers();

Iterator it = members.iterator();

while (it.hasNext()){

BodyDeclaration member = (BodyDeclaration)it.next();

if (member instance of MethodDeclararion){

MethodDeclarion aux = (MethodDeclaration) member;

if(“execute”.equals(aux.getName()){

method = aux;

break;

}

}

}

type.methods.find({it.name.equals(“execute”)})

Page 30: walkmod - JUG talk

queries from templates

Using the query object: ${query.resolve(“expr”)}.

query engine

import org.apache.log4j.Logger;

public class ${query.resolve("type.name")}{

public static Logger log = Logger.getLogger(${query.resolve("type.name")}.class);

}

template to add Loggers

Page 31: walkmod - JUG talk

queries from scripts

accessing through a binding called query

query engine

..

for( type in node.types) {

def result = query.resolve(type, “methods”);

...

}

...

groovy script querying the type methods

Page 32: walkmod - JUG talk

queries from visitors

Implementing QueryEngineAware or extending VisitorSupport.

query engine

public class MyVisitor extends VisitorSupport{

@Overwrite

public void visit(TypeDeclaration td, VisitorContext ctx){

Object result = query(

td, //context

“methods.find({it.name.equals(“foo”)})” //expr

);

}

}

visitor code with a gpath query

Page 33: walkmod - JUG talk

how it works

introduction

query engine

merge engine

plugins

roadmap

transformations

Page 34: walkmod - JUG talk

why a merge engine?

• To avoid duplicate results by transformations (i.e duplicate a method) in existing code.

• Simplify transformations. Otherwise, transformations must check many conditions to avoid repeating code or overwriting it.

• Sometimes, developer changes (i.e. adding a new method) must be respected by the engine.

merge engine

Page 35: walkmod - JUG talk

walkmod merges outputs with existential sources

Page 36: walkmod - JUG talk

semantic merge

• Code is merged according to the meaning of its elements instead of simply merging text.

• Only elements with the same identifier are merged. Indentifiable element types must implement the interface mergeable.

merge engine

Page 37: walkmod - JUG talk

previous concepts

• local object is the current version of an element.

• remote object is the modified version of an element generated by a single transformation. It may be a fragment to add in a local object.

merge engine

Page 38: walkmod - JUG talk

merge policiesConfigurable and extensible merge policies for each object type.

merge engine

Object merge policy

Finds the equivalent local version of a remote (and thus, generated) object and merge recursively their children.

These objects must be identifiable to be searched and found.

These policies should be applied for fields, , methods, , types …

Type merge policy

select which merge action do for local and remote objects which are not identifiable, although being instances of the same class. i.e policies for the statements of an existent method.

Page 39: walkmod - JUG talk

object merge policies

• append policy only writes new values for null fields. Otherwise, these are not modified.

• overwrite policy modifies all field values of a local object for those generated by a transformation.

merge engine

Page 40: walkmod - JUG talk

type merge policies• assign policy only writes the remote values. i.e replacing the list of

statements of a method for the generated list.

• unmodify policy only writes the local values. i.e to respect the developer changes in the statements of an old transformation.

• addall policy that appends the remote values into the local values.

merge engine

Page 41: walkmod - JUG talk

how it works

introduction

query engine

merge engine

plugins

roadmap

transformations

Page 42: walkmod - JUG talk

why and how to extend walkmod?

• You can extend walkmod with new components or override the existing ones (visitors, readers, writers, walkers, merge policies…)

• Creating new plugins (java libraries) and deploying them into a maven repository (public or private). See repo.maven.apache.org

• All walkmod extensions need a plugin descriptor of their components in the META-INF/walkmod directory inside the jar library.

plugins

Page 43: walkmod - JUG talk

plugin descriptor• Plugin descriptor is a XML file with the name walkmod-xxx-plugin.xml

which follows the spring bean configuration.

• New readers, writers, walkers or transformations must be specified with a unique name “groupId:artifactId:name” as a spring bean in the plugin descriptor.

plugins

<beans> ... <bean id="walkmod:commons:import-cleaner" class="org.walkmod.visitors.ImportOrganizer" /> ...</beans>

Page 44: walkmod - JUG talk

plugin usage (I)

<walkmod> <plugins> <plugin groupId="walkmod" artifactId="walkmod-commons-plugin" version="1.0"> </plugin> </plugins>

<chain name="my-chain"> ... </chain><walkmod>

plugins

<plugins> <plugin groupId="walkmod" artifactId="walkmod-commons-plugin" version="1.0"> </plugin> </plugins>

Plugins are declared into ${project}/walkmod.xml

Page 45: walkmod - JUG talk

plugin usage (II)

Beans declared in a plugin descriptor can be referenced from walkmod.xml using the type attribute.

plugins

<walkmod><plugins>

<plugin groupId="walkmod" artifactId="walkmod-commons-plugin" version="1.0"> </plugin> </plugins> <chain name="my-chain"> ... <transformation type="walkmod:commons:imports-cleaner" /> ... </chain></walkmod>

<transformation type="walkmod:commons:imports-cleaner" />

Page 46: walkmod - JUG talk

plugins backend• Walkmod embeds apache ivy to download plugins from maven

repositories in runtime.

• Custom repositories are in ${walkmod-home}/conf/ivysettings.xml

• All plugin jars and their dependencies are files loaded dynamically into a new classloader.

• All beans used and declared in plugin descriptors are resolved by the spring source engine using the new classloader.

plugins

Page 47: walkmod - JUG talk

how it works

introduction

query engine

merge engine

plugins

roadmap

transformations

Page 48: walkmod - JUG talk

next steps• modularization: split the project in modules in GitHub and deploy them in a

Maven public repository.

• Java 8 support (lambda expressions)

• + plugins: Create and publish new plugins (e.g. refactoring or support for other programming languages).

• - less configuration: reutilization by inheritance / include rules of the XML elements.

• saas: publish online services for running walkmod and all its plugins (also private).

roadmap