A Groovy journey in Open Source land

A Groovy journey in Open Source land

In dog years... err... Open Source years, the Groovy programming language project is a very mature and successful one, as its 12+ million downloads a year can attest. The Groovy language is certainly the most widely deployed alternative language of the JVM today. But how do we go from a hobby night & week-end project to professionally company sponsored? And back again to hobby mode but joining the wider Apache Software Foundation community?

Guillaume will guide you through the history of the project, its latest developments, and its recent news, outlining the importance of a community around an Open Source project.

Also, we'll discuss what it means to contribute, when it's your hobby or as a paid committer -- what does it change? What it means to join the Apache community, what the impact of professional Open Source is, and more.

137d3908243acfc30e126615d59d4e6d?s=128

Guillaume Laforge

June 02, 2016
Tweet

Transcript

  1. A Groovy Journey in Open Source Land Guillaume Laforge /

    @glaforge Chair of the Apache Groovy PMC
  2. A Groovy Journey in Open Source Land Guillaume Laforge /

    @glaforge Chair of the Apache Groovy PMC
  3. None
  4. GR8Conf Promo Code: ctwgr8conftw http://www.manning.com/koenig2/ GROOVY IN ACTION 2ND EDITION

  5. From 2003 onward…

  6. 2003

  7. Bob McWhirter James Strachan

  8. Bob McWhirter James Strachan James Strachan and Bob McWhirter gave

    birth to Groovy: a dynamic and agile scripting language for the JVM. […] James always used to say that it was all Bob's fault, but indeed, James had so many groovy ideas that it's hard to believe it's not his own fault. He kept saying: "Wouldn't it be groovy if we could do this and that...". Hence the name "Groovy". That's roughly how it all started.
  9. None
  10. 7 Groovy pre-1.0 • Closures available since 2003 on Java

    1.4+ • All the nice shortcuts already, inspired by Python & Ruby • native syntax for lists, maps, etc… • Tons of useful methods to simplify 
 common Java boiler-plate code • Initially dynamically-typed only
  11. None
  12. I join the project in 2003, patches after patches, become

    committer, then lead when founders left
  13. 2004

  14. 5

  15. 11 Groovy in 2004 • A brand new parser based

    on Antlr • after two hand-rolled versions • by John Rose and Jeremy Rainer • Jochen « blackdrag » Theodorou joins the project
  16. None
  17. None
  18. 2005

  19. None
  20. 2006

  21. 6

  22. 17 First paid committer • Jochen becomes the first full-time

    paid committer • sponsored by BigSky Technologies / No Fluff Just Stuff
  23. 2007

  24. None
  25. 1.0

  26. None
  27. None
  28. None
  29. None
  30. None
  31. Spock the Enterprise testing framework

  32. 24 Groovy in 2007 — Groovy 1.5 • The long

    awaited Java 5 update • annotations, enums, generics… • Joint compiler! • Varargs support • Static imports (including import aliasing) • Named parameters without parentheses
  33. None
  34. Paul King, #1 committer from 2007 to 2010, and overall

    #1 committer too!
  35. 2008

  36. None
  37. None
  38. 29 Griffon and Easyb

  39. 30 Groovy++ fork! • Not the first fork, but 3rd

    • by Alex Tkachman (former G2One co-founder) • Big focus on static compilation • interesting playground for our forthcoming static type checking and static compilation support
  40. 2009

  41. I can honestly say if someone had shown me the

    Programming Scala book back in 2003, I’d probably have never created Groovy
  42. Have I had JPA back then, I would certainly not

    have created Hibernate!
  43. None
  44. None
  45. None
  46. None
  47. None
  48. None
  49. None
  50. None
  51. None
  52. None
  53. None
  54. 39 The Groovy Ecosystem grows…

  55. 40 Groovy 1.6 • Performance improvements with call-site caching •

    Multiple assignments • Optional return in if/else, try/catch, switch/case • More AST transformations • @Singleton, @Lazy, @Immutable, @Delegate • The Grape module system with @Grab • OSGi support
  56. 41 Groovy 1.7 • Nested and inner classes, and nested

    static classes • Missing annotation definition support • Power Asserts from Spock • Customize the Groovy Truth! • AST viewer and AST builder • SQL support improvements
  57. 2010

  58. 43 Groovy ecosystem marching on… GContracts

  59. 2011

  60. None
  61. 7

  62. 47 More Groovy ecosystem…

  63. 48 Groovy 1.8 • Command chain expressions • GPars bundled

    with the Groovy distribution • Primitive calculation optimizations • Closures • as annotation parameters • currying, memoization and tail recursion • Built-in JSON support
  64. I’m joining the Groovy team!

  65. None
  66. 2012

  67. 52 Groovy ecosystem continued… • Netflix • Asgard, • Zuul

    • LinkedIn Glu • GroovyStream
  68. 53 Groovy 2.0 • Static type checking and static compilation

    • type inference, flow typing… • « Project Coin » enhancements • binary literals, underscore in numbers, multicatch block • Initial « invoke dynamic » support • Modularity of the Groovy code base with modules
  69. 2013

  70. None
  71. 56 Richer Groovy ecosystem…

  72. 57 Groovy 2.1 • Full « invoke dynamic » support

    • Type-checking extensions • Meta-annotations • @DelegatesTo annotation • Compiler customization scripts • Distribution bundling GPars 1.0
  73. 58 Groovy 2.2 • Implicit closure coercion to SAM types

    • Java lambda friendly! • Pre-compiled type checking extensions • @Memoized transformations for methods
  74. 2014

  75. 8

  76. 61 Groovy ecosystem

  77. 62 Groovy 2.3 • Traits! • Improved JDK 8 support

    • Drastic performance improvement for JSON • New AST transformations & improvements • @Builder,@Sortable,@SourceURI, @BaseScript • New markup template engine • More NIO support
  78. 2015

  79. You’re fired! 2015

  80. None
  81. Oh by the way, Codehaus closes!

  82. ANY IMPACT?

  83. 2012 2013 2014 2015 Downloads

  84. 2012 2013 2014 2015 1.7M 3M 4.5M Downloads 12.7M

  85. 3.4 MILLIONS FROM MAVEN CENTRAL IN 4 MONTHS

  86. MAVEN CENTRAL ONLY

  87. MAVEN CENTRAL ONLY +BINTRAY

  88. 3 MILLIONS FROM BINTRAY

  89. 6.4 MILLIONS ALREADY IN 2016 SO FAR

  90. GROOVY 2.4

  91. 72 Groovy 2.4 — Android support • Write your Android

    applications fully in Groovy! • Dedicated Gradle plugin
  92. 73 Groovy 2.4 — Android support SwissKnife
 a dedicated 


    Groovy / Android 
 library
  93. 74 Groovy 2.4 — Performance & bytecode • Improved bytecode

    • cheaper comparison operations • optimization of primitive type coercions with ‘as’ • Reduced bytecode size • no MOP generated methods in static context • uneeded inner class distributor methods when no inner • timestamp removal • Reduced memory consumption
  94. 75 Groovy 2.4 — Traits @SelfType class Component {
 void

    doSomething() {
 println "Done!"
 }
 }
  95. 75 Groovy 2.4 — Traits @SelfType class Component {
 void

    doSomething() {
 println "Done!"
 }
 } import groovy.transform.* 
 @SelfType(Component)
 @TypeChecked
 trait ComponentDecorator {
 void logAndDoSomething() {
 println "Going to do something"
 doSomething()
 }
 }
  96. 75 Groovy 2.4 — Traits @SelfType class Component {
 void

    doSomething() {
 println "Done!"
 }
 } import groovy.transform.* 
 @SelfType(Component)
 @TypeChecked
 trait ComponentDecorator {
 void logAndDoSomething() {
 println "Going to do something"
 doSomething()
 }
 } class ConcreteComponent
 extends Component
 implements ComponentDecorator {}
 
 def c = new ConcreteComponent()
 c.logAndDoSomething()
  97. 76 Groovy 2.4 — GDK improvements • New methods •

    System.currentTimeSeconds() • List: removeAt(index), getIndices() • Collection: removeElement(Object) • Iterable: disjoin(), size(), dropRight(), takeRight() • More collection methods moved to iterator-based • Favor stream-like traversal methods leveraging iterables • Consistency for mutation in place vs new collection creation
  98. 77 Groovy 2.4 — AST transformations • @ToString added includeSuperProperties

    parameter • Can define compilation phase for @ASTTest • @Synchronized supports explicit static locks used by instance methods if needed • Cleaned-up code for @AutoExternalizable and @EqualsAndHashCode when used with @CompileStatic • Improved Java integration for @Builder • @PackageScope allowed on constructors
  99. 78 Groovy 2.4 — Groovysh improvements • Custom .rc and

    .profile scripts • instanceof completion • Static members completion only in a static context • Completion candidates in color • :set interpreterMode to remember locally-defined variables • :load command supports file names with spaces • Align arguments & flags with the groovy command • Script launch on startup & continue execution of Groovysh • Easier to subclass Groovysh for embedded reuse
  100. Here come the Indians!

  101. None
  102. MESSAGE TO THE COMMUNITY

  103. HERE TO STAY

  104. HERE TO STAY INDEPENDENCE

  105. HERE TO STAY COMMUNITY ABOVE ALL INDEPENDENCE

  106. 83 Top Level Project at Apache! • PMC & Incubator

    PMC voted for graduation • Apache Board agreed to the graduation! • (last November) • Call us Apache Groovy :-) • 2.4.6 was released on February 2016
  107. 84 Entering the TIOBE index • 3 months in a

    row in the top-20 TIOBE index • 17th for January • 20th for February • 17th for March • 17th for April • 17th for May
  108. None
  109. Little nuggets…

  110. 87 Groovy 2.4.4/5/6 / 2.5 • Improved compiler performance •

    with an ASM class reader • @Canonical becomes a meta-annotation • More control on the meta-annotation collector • New @MapConstructor transformation • Pre/post conditions for @TupleConstructor • Property validation in transformation parameters • @Delegate on getters • Further AST transformation improvements • JAXB marshal/unmarshal shortcuts
  111. 88 @Canonical becomes a meta-annotation import groovy.transform.*
 
 @Canonical(includeNames =

    true)
 class Person {
 String name
 int age
 }
 
 assert new Person('Guillaume', 38).toString() ==
 'Person(name:Guillaume, age:38)'
  112. 88 @Canonical becomes a meta-annotation import groovy.transform.*
 
 @Canonical(includeNames =

    true)
 class Person {
 String name
 int age
 }
 
 assert new Person('Guillaume', 38).toString() ==
 'Person(name:Guillaume, age:38)' includeNames from @ToString
  113. 89 More control on annotation collector DUPLICATE Annotations from the

    annotation collection will always be inserted. PREFER_COLLECTOR Annotations from the collector will be added and any existing annotations with the same name will be removed. PREFER_EXPLICIT Annotations from the collector will be ignored if any existing annotations with the same name are found. PREFER_EXPLICIT_MERGED Annotations from the collector will be ignored if any existing annotations with the same name are found but any new parameters on the collector annotation will be added to existing annotations. PREFER_COLLECTOR_MERGED Annotations from the collector will be added and any existing annotations with the same name will be removed but any new parameters found within existing annotations will be merged into the added annotation.
  114. 90 New @MapConstructor transformation import groovy.transform.*
 
 @TupleConstructor
 class Person

    {
 String first, last
 }
 
 @CompileStatic // optional
 @ToString(includeSuperProperties = true)
 @MapConstructor(pre = { super(args?.first, args?.last);
 args = args ?: [:] },
 post = { first = first?.toUpperCase() })
 class Author extends Person {
 String bookName
 } assert new Author(first: 'Dierk', last: 'Koenig', bookName: 'ReGinA').toString() == 'Author(ReGinA, DIERK, Koenig)'
 
 assert new Author().toString() == 'Author(null, null, null)'
  115. 90 New @MapConstructor transformation import groovy.transform.*
 
 @TupleConstructor
 class Person

    {
 String first, last
 }
 
 @CompileStatic // optional
 @ToString(includeSuperProperties = true)
 @MapConstructor(pre = { super(args?.first, args?.last);
 args = args ?: [:] },
 post = { first = first?.toUpperCase() })
 class Author extends Person {
 String bookName
 } assert new Author(first: 'Dierk', last: 'Koenig', bookName: 'ReGinA').toString() == 'Author(ReGinA, DIERK, Koenig)'
 
 assert new Author().toString() == 'Author(null, null, null)' Can decorate map ctor with pre / post- instructions
  116. 91 Pre/post events for @TupleConstructor import groovy.transform.TupleConstructor @TupleConstructor(pre = {

    first = first?.toLowerCase() }) class Person { String first } def p = new Person('Jack') assert p.first == 'jack'
  117. 91 Pre/post events for @TupleConstructor import groovy.transform.TupleConstructor @TupleConstructor(pre = {

    first = first?.toLowerCase() }) class Person { String first } def p = new Person('Jack') assert p.first == 'jack' import groovy.transform.TupleConstructor import static groovy.test.GroovyAssert.shouldFail @TupleConstructor(pre = { assert first }) class Person { String first } def p = new Person('Jack') shouldFail { def unknown = new Person() }
  118. 92 Properties validated in AST xforms import groovy.transform.AutoClone
 
 @AutoClone(excludes

    = 'sirName')
 class Person {
 String firstName
 String surName
 }
 
 new Person(firstName: "John", surName: "Doe").clone()
  119. 92 Properties validated in AST xforms import groovy.transform.AutoClone
 
 @AutoClone(excludes

    = 'sirName')
 class Person {
 String firstName
 String surName
 }
 
 new Person(firstName: "John", surName: "Doe").clone() Error during @AutoClone processing: 'excludes' property 'sirName' does not exist.
  120. 93 Prevent @TupleConstructor default ctors @TupleConstructor
 class Person {
 String

    first, last
 int age
 }
  121. 93 Prevent @TupleConstructor default ctors @TupleConstructor
 class Person {
 String

    first, last
 int age
 } Generates: Person(String first, String last, int age) { /*...*/ } Person(String first, String last) { this(first, last, 0) } Person(String first) { this(first, null) } Person() { this(null) }
  122. 94 Prevent @TupleConstructor default ctors @TupleConstructor(defaults = true)
 class Person

    { String first, last
 int age
 }
  123. 94 Prevent @TupleConstructor default ctors @TupleConstructor(defaults = true)
 class Person

    { String first, last
 int age
 } Generates only: Person(String first, String last, int age) { /*...*/ }
  124. 95 @Immutable support in class hierarchy import groovy.transform.*
 
 @EqualsAndHashCode


    class Person {
 String name
 }
  125. 95 @Immutable support in class hierarchy import groovy.transform.*
 
 @EqualsAndHashCode


    class Person {
 String name
 } @Immutable
 @TupleConstructor(includeSuperProperties = true)
 @EqualsAndHashCode(callSuper = true)
 @ToString(includeNames = true, includeSuperProperties = true)
 class Athlete extends Person {
 String sport
 }
  126. 95 @Immutable support in class hierarchy import groovy.transform.*
 
 @EqualsAndHashCode


    class Person {
 String name
 } @Immutable
 @TupleConstructor(includeSuperProperties = true)
 @EqualsAndHashCode(callSuper = true)
 @ToString(includeNames = true, includeSuperProperties = true)
 class Athlete extends Person {
 String sport
 } def d1 = new Athlete('Michael Jordan', 'BasketBall')
 def d2 = new Athlete(name: 'Roger Federer', sport: ‘Tennis') assert d1 != d2
 assert d1.toString() == 
 'Athlete(sport:BasketBall, name:Michael Jordan)'
 assert d2.toString() == 
 'Athlete(sport:Tennis, name:Roger Federer)'
  127. 96 :grab command in groovysh groovy:000> :grab 'com.google.guava:guava:19.0' groovy:000> import

    com.google.common.collect.BiMap ===> com.google.common.collect.BiMap
  128. 97 @Delegate on getters too class Person {
 String name

    @Delegate
 String getName() { name.toUpperCase() } } def p = new Person('Bill') assert p.toUpperCase() == 'BILL'
  129. 98 JAXB marshalling shortcuts import groovy.transform.EqualsAndHashCode import javax.xml.bind.JAXBContext import javax.xml.bind.annotation.*

    @EqualsAndHashCode @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement class Person { String name int age }
  130. 98 JAXB marshalling shortcuts import groovy.transform.EqualsAndHashCode import javax.xml.bind.JAXBContext import javax.xml.bind.annotation.*

    @EqualsAndHashCode @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement class Person { String name int age } def jaxbContext = JAXBContext.newInstance(Person) def p = new Person(name: 'Bill', age: 20) def xml = jaxbContext.marshal(p) assert jaxbContext.unmarshal(xml, Person) == p
  131. 99 Miscellaneous • Map#retainAll {} and Map#removeAll {} methods •

    GDK’s createSimilarCollection() and createSimilarMap() methods support all the JDK’s collections and maps • New File#relativePath(file) method
  132. To conclude…

  133. None
  134. It’s been a long road! And it’s not over yet!

  135. None
  136. Thanks for your attention!

  137. Questions & Answers