Slide 1

Slide 1 text

Codenarc Revisited: Part 2 Jenn Strater @codeJENNerator

Slide 2

Slide 2 text

@codeJENNerator Note For Those Viewing Slides Online • Bulleted text like this indicates the key points mentioned on a previous slide. They may not have been included in the official presentation. • If this view does not support links, the links will work in the pdf. Click the ‘download pdf’ button on the right.

Slide 3

Slide 3 text

@codeJENNerator https://speakerdeck.com/jlstrater/codenarc-part-2-gr8conf-eu-2017 Follow Along

Slide 4

Slide 4 text

@codeJENNerator About Me

Slide 5

Slide 5 text

@codeJENNerator About Me Starting at Zenjob in Berlin on Monday June 5!

Slide 6

Slide 6 text

@codeJENNerator About Me - Took classes at the Technical University of Denmark and worked on a research project - Also explored Danish Culture with funding from the US Fulbright Grant program - Prior to the Fulbright Grant, I was a senior consultant at Object Partners, Inc. in Minneapolis, MN, USA. - Co-founder of Gr8Ladies and talk about women in the Groovy Community all over the world - Passionate about bring new people into the Groovy community through free introductory workshops called Gr8Workshops. - Moving to Berlin and starting at Zenjob in June 2017.

Slide 7

Slide 7 text

@codeJENNerator Background

Slide 8

Slide 8 text

@codeJENNerator Background • Uses Codenarc • Has written a Custom Rule • Contributed back to Codenarc

Slide 9

Slide 9 text

@codeJENNerator Agenda • Part I Recap • What’s New Since Part I • Creating a Custom Rule • Bytecode Analysis and Optimization Project

Slide 10

Slide 10 text

Recap of Part I https://www.youtube.com/watch?v=3v18NB7pyCY

Slide 11

Slide 11 text

@codeJENNerator What is ?

Slide 12

Slide 12 text

@codeJENNerator “CodeNarc is a static analysis tool for Groovy source code, enabling monitoring and enforcement of many coding standards and best practices… CodeNarc is similar to popular static analysis tools such as PMD or Checkstyle. Unlike those tools which analyze Java code, CodeNarc analyzes Groovy code.” What is ?

Slide 13

Slide 13 text

@codeJENNerator Why use Codenarc? • Improves readability • Saves time with code reviews • Code with fewer bugs • Help onboard new team members

Slide 14

Slide 14 text

@codeJENNerator Terms Formatting Space After Switch Braces for Class Trailing Whitespace

Slide 15

Slide 15 text

@codeJENNerator Not Just Formatting • Concurrency • JDBC • Security • Complexity

Slide 16

Slide 16 text

@codeJENNerator Setup Plugin

Slide 17

Slide 17 text

One Year Later https://github.com/CodeNarc/CodeNarc/blob/master/CHANGELOG.txt

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

@codeJENNerator What coming next?

Slide 22

Slide 22 text

@codeJENNerator GR8Conf Hackergarten

Slide 23

Slide 23 text

@codeJENNerator 0.28.0

Slide 24

Slide 24 text

@codeJENNerator Creating a Custom Rule

Slide 25

Slide 25 text

@codeJENNerator ->groovy codenarc.groovy create-rule Enter your name:Jenn Strater Enter the rule name:TestExampleRule Enter the rule category. Valid categories are: basic braces concurrency convention design dry exceptions formatting generic grails groovyism imports jdbc junit logging naming security serialization size unnecessary unused unnecessary Enter the rule description:A test example rule that removes some unnecessary piece of code Created ./src/main/groovy/org/codenarc/rule/unnecessary/TestExampleRule.groovy Created ./src/test/groovy/org/codenarc/rule/unnecessary/TestExampleRuleTest.groovy Updated ./src/main/resources/codenarc-base-messages.properties Updated ./src/main/resources/rulesets/unnecessary.xml Updated ./src/site/apt/codenarc-rules-unnecessary.apt Updated ./CHANGELOG.txt adding to git... add 'src/main/groovy/org/codenarc/rule/unnecessary/TestExampleRule.groovy' adding to git... add 'src/test/groovy/org/codenarc/rule/unnecessary/TestExampleRuleTest.groovy' Finished

Slide 26

Slide 26 text

@codeJENNerator TextExampleRule.groovy /*
 * Copyright 2017 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 package org.codenarc.rule.unnecessary
 
 import org.codenarc.rule.AbstractAstVisitorRule
 import org.codenarc.rule.AbstractAstVisitor
 
 /**
 * A test example rule that removes some unnecessary piece of code
 *
 * @author Jenn Strater
 */
 class TestExampleRule extends AbstractAstVisitorRule {
 
 String name = 'TestExample'
 int priority = 2
 Class astVisitorClass = TestExampleAstVisitor
 }
 
 class TestExampleAstVisitor extends AbstractAstVisitor {
 
 }


Slide 27

Slide 27 text

@codeJENNerator TextExampleRuleTest.groovy package org.codenarc.rule.unnecessary
 
 import org.codenarc.rule.Rule
 import org.junit.Test
 import org.codenarc.rule.AbstractRuleTestCase
 class TestExampleRuleTest extends AbstractRuleTestCase {
 
 @Test
 void testRuleProperties() {
 assert rule.priority == 2
 assert rule.name == 'TestExample'
 }
 
 @Test
 void testNoViolations() {
 final SOURCE = '''
 // todo: replace with source for passing edge case(s)
 '''
 assertNoViolations(SOURCE)
 }
 
 @Test
 void testSingleViolation() {
 final SOURCE = '''
 // todo: replace with source that triggers a violation
 '''
 assertSingleViolation(SOURCE, 1, '...')
 }
 
 @Test
 void testMultipleViolations() {
 final SOURCE = '''
 // todo: replace with source that triggers 2 violations
 '''
 assertViolations(SOURCE,
 [lineNumber:1, sourceLineText:'...', messageText:'...'], // todo: replace line number, source line and message
 [lineNumber:1, sourceLineText:'...', messageText:'...']) // todo: replace line number, source line and message
 }
 
 protected Rule createRule() {
 new TestExampleRule()
 }
 }

Slide 28

Slide 28 text

@codeJENNerator Could Be Switch Rule

Slide 29

Slide 29 text

Switch in Groovy http://mrhaki.blogspot.dk/2009/08/groovy-goodness-switch-statement.html

Slide 30

Slide 30 text

@codeJENNerator CouldBeSwitchRule.groovy class CouldBeSwitchStatementRule extends AbstractAstVisitorRule { String name = 'CouldBeSwitchStatement' int priority = 3 Class astVisitorClass = CouldBeSwitchStatementAstVisitor String errorMessage = 'Code could use switch statement' }

Slide 31

Slide 31 text

@codeJENNerator CouldBeSwitchRule.groovy class CouldBeSwitchStatementAstVisitor extends AbstractAstVisitor { private BinaryExpression prev = null private Integer ifCounter = 0 private firstIfNode = null @Override void visitIfElse(IfStatement node) { checkIfStatementCanBeSwitch(node) super.visitIfElse(node) } private void checkIfStatementCanBeSwitch(IfStatement node) { def current = node.booleanExpression?.expression if (current instanceof BinaryExpression && isSupportedLeftExpressionType(current.leftExpression) && inSupportedOperation(current.operation)) { if (isSameLeftExpressionAsPreviousIfStatement(current.leftExpression, prev?.leftExpression)) { ifCounter++ } else { ifCounter = 1 firstIfNode = current } if (ifCounter > 2) { addViolation(firstIfNode, rule.errorMessage) ifCounter = 0 prev = null } prev = current } else { ifCounter = 0 prev = null } } . . .

Slide 32

Slide 32 text

@codeJENNerator CouldBeSwitchRule.groovy private Boolean inSupportedOperation(Token operation) { operation.type in [Types.COMPARE_EQUAL, Types.KEYWORD_INSTANCEOF] } private Boolean isSupportedLeftExpressionType(def expression) { switch(expression) { case PropertyExpression: case VariableExpression: case ConstantExpression: return true default: return false } } private Boolean isSameLeftExpressionAsPreviousIfStatement(def current, def prev) { if (!prev || current.class != prev.class) { return false } switch(current) { case PropertyExpression: return isSameLeftExpressionAsPreviousIfStatement(current.objectExpression, prev?.objectExpression) && isSameLeftExpressionAsPreviousIfStatement(current.property, prev.property) case VariableExpression: return current.variable == prev?.variable case ConstantExpression: return current.value == prev.value default: false } }

Slide 33

Slide 33 text

@codeJENNerator codenarc-base-messages.properties 
 # todo: manually sort your messages into the correct location
 TestExample.description=A test example rule that removes some unnecessary piece of code
 TestExample.description.html=A test example rule that removes some unnecessary piece of code

Slide 34

Slide 34 text

@codeJENNerator codenarc-rules-unnecessary.apt 
 * {TestExample} Rule
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
 A test example rule that removes some unnecessary piece of code
 
 Example of violations:
 
 ------------------------------------------------------------------------ -------
 // TODO: Add examples
 ------------------------------------------------------------------------ -------


Slide 35

Slide 35 text

@codeJENNerator Limitations of Codenarc

Slide 36

Slide 36 text

@codeJENNerator Codenarc Conclusion

Slide 37

Slide 37 text

@codeJENNerator

Slide 38

Slide 38 text

@codeJENNerator • Codenarc is a lot more than just formatting

Slide 39

Slide 39 text

@codeJENNerator • Codenarc is a lot more than just formatting • There is still a lot of work to do

Slide 40

Slide 40 text

@codeJENNerator • Codenarc is a lot more than just formatting • There is still a lot of work to do • You can add your own custom rules and contribute back

Slide 41

Slide 41 text

@codeJENNerator Bytecode Analysis and other forms of static analysis in Groovy

Slide 42

Slide 42 text

Groovy Compiler Project https://jlstrater.github.io/groovy-compiler-project/html/index.html

Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

@codeJENNerator Legacy

Slide 46

Slide 46 text

@codeJENNerator Invoke Dynamic

Slide 47

Slide 47 text

@codeJENNerator Static Compilation

Slide 48

Slide 48 text

@codeJENNerator Indy vs Static Compilation

Slide 49

Slide 49 text

@codeJENNerator Potential for Optimization

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

@codeJENNerator https://github.com/apache/groovy/blob/master/src/main/ org/codehaus/groovy/classgen/asm/StatementWriter.java

Slide 53

Slide 53 text

@codeJENNerator Post Pass Optimization Project

Slide 54

Slide 54 text

@codeJENNerator

Slide 55

Slide 55 text

@codeJENNerator • Simple Groovy project

Slide 56

Slide 56 text

@codeJENNerator • Simple Groovy project • Uses an ASM reader and writer to read bytecode compiled using each of the groovy compiler options

Slide 57

Slide 57 text

@codeJENNerator • Simple Groovy project • Uses an ASM reader and writer to read bytecode compiled using each of the groovy compiler options • Iterates over the method instructions to find the unneccessary instructions

Slide 58

Slide 58 text

@codeJENNerator • Simple Groovy project • Uses an ASM reader and writer to read bytecode compiled using each of the groovy compiler options • Iterates over the method instructions to find the unneccessary instructions • Removes the instructions and outputs the new bytecode

Slide 59

Slide 59 text

@codeJENNerator • Simple Groovy project • Uses an ASM reader and writer to read bytecode compiled using each of the groovy compiler options • Iterates over the method instructions to find the unneccessary instructions • Removes the instructions and outputs the new bytecode • https://github.com/jlstrater/groovy-compiler-project

Slide 60

Slide 60 text

Results https://jlstrater.github.io/groovy-compiler-project/ bytecode/index.html

Slide 61

Slide 61 text

@codeJENNerator

Slide 62

Slide 62 text

@codeJENNerator • There was no difference in performance

Slide 63

Slide 63 text

@codeJENNerator • There was no difference in performance • as explained on the mailing list

Slide 64

Slide 64 text

@codeJENNerator • There was no difference in performance • as explained on the mailing list • Also probable problem with benchmarking procedure

Slide 65

Slide 65 text

@codeJENNerator • There was no difference in performance • as explained on the mailing list • Also probable problem with benchmarking procedure • Output file sizes are being reduced. Some by up to 10% or more.

Slide 66

Slide 66 text

@codeJENNerator Bytecode Analysis Next Steps

Slide 67

Slide 67 text

@codeJENNerator

Slide 68

Slide 68 text

@codeJENNerator • Clean up the code and find a way to integrate the optimization and fixes into the existing groovy compiler

Slide 69

Slide 69 text

@codeJENNerator Conclusion

Slide 70

Slide 70 text

@codeJENNerator Next Steps • Join the Groovy Community on Slack groovycommunity.com • Join the Codenarc Mailing List • Submit a PR!

Slide 71

Slide 71 text

@codeJENNerator Questions? https://flic.kr/p/5DeuzB