$30 off During Our Annual Pro Sale. View Details »

Groovy with Style - SpringOne2GX 2015 - Guillaume Laforge

Groovy with Style - SpringOne2GX 2015 - Guillaume Laforge

Guillaume Laforge

September 15, 2015
Tweet

More Decks by Guillaume Laforge

Other Decks in Technology

Transcript

  1. SPRINGONE2GX
    WASHINGTON, DC
    Groovy with Style
    by Guillaume Laforge
    @glaforge

    View Slide

  2. View Slide

  3. Promo Code: ctwspringo2gx
    http://www.manning.com/koenig2/
    GROOVY
    IN ACTION
    2ND EDITION

    View Slide

  4. We know
    about
    APIs!
    http://restlet.com

    View Slide

  5. We know
    about
    APIs!
    http://restlet.com

    View Slide

  6. SPRINGONE2GX
    WASHINGTON, DC
    12 years of
    Groovy experience

    View Slide

  7. SPRINGONE2GX
    WASHINGTON, DC
    What style?

    View Slide

  8. View Slide

  9. View Slide

  10. View Slide

  11. View Slide

  12. View Slide

  13. View Slide

  14. View Slide

  15. <=>

    View Slide

  16. @glaforge
    http://www.groovy-lang.org/style-guide.html
    11

    View Slide

  17. @glaforge
    http://www.groovy-lang.org/style-guide.html
    11

    View Slide

  18. View Slide

  19. View Slide

  20. View Slide

  21. @glaforge
    No semicolons!
    14
    class Hello {

    private String message = 'Hello!';

    String greet(String name) {

    "$message, $name speaking";

    } 

    }


    print new Hello().greet('Guillaume');

    View Slide

  22. @glaforge
    No semicolons!
    14
    class Hello {

    private String message = 'Hello!';

    String greet(String name) {

    "$message, $name speaking";

    } 

    }


    print new Hello().greet('Guillaume');

    View Slide

  23. @glaforge
    No semicolons!
    15
    class Hello {

    private String message = 'Hello'

    String greet(String name) {

    "$message, $name speaking"

    } 

    }


    print new Hello().greet('Guillaume')

    View Slide

  24. View Slide

  25. @glaforge
    Public by default
    17
    public class Hello {

    private static String message = 'Hello'

    private String name


    public Hello(String name) {

    this.name = name

    }

    public String greet() {

    return "$message, $name speaking"

    } 

    }

    View Slide

  26. @glaforge
    Public by default
    18
    class Hello {

    private static String message = 'Hello'

    private String name


    Hello(String name) {

    this.name = name

    }

    String greet() {

    return "$message, $name speaking"

    } 

    }
    Methods and classes are
    public by default

    View Slide

  27. @glaforge
    Fields and static fields require visibility
    19
    class Hello {

    static String message = 'Hello’

    String name


    Hello(String name) {

    this.name = name

    }

    String greet() {

    return "$message, $name speaking"

    } 

    }

    View Slide

  28. @glaforge
    Fields and static fields require visibility
    19
    class Hello {

    static String message = 'Hello’

    String name


    Hello(String name) {

    this.name = name

    }

    String greet() {

    return "$message, $name speaking"

    } 

    }
    You created both an
    instance property and a
    static property!

    View Slide

  29. View Slide

  30. @glaforge
    Get rid of the useless ‘def’
    21
    class Hello {

    private static String message = 'Hello'

    private def String name

    def Hello(def String name) {

    this.name = name

    }

    public def String greet() {

    def String result = "$message, $name speaking"

    return result

    } 

    }


    View Slide

  31. @glaforge
    Get rid of the useless ‘def’
    21
    class Hello {

    private static String message = 'Hello'

    private def String name

    def Hello(def String name) {

    this.name = name

    }

    public def String greet() {

    def String result = "$message, $name speaking"

    return result

    } 

    }


    View Slide

  32. @glaforge
    Get rid of the useless ‘def’
    22
    class Hello {

    private static String message = 'Hello'

    private String name

    Hello(String name) {

    this.name = name

    }

    String greet() {

    String result = "$message, $name speaking"

    return result

    } 

    }


    View Slide

  33. @glaforge
    Get rid of the useless ‘def’
    23
    class Hello {

    private String message = 'Hello'

    private String name

    Hello(String name) {

    this.name = name

    }

    String greet() {

    def result = "$message, $name speaking"

    return result

    } 

    }

    But it’s fine to use ‘def’
    for local variables

    View Slide

  34. View Slide

  35. @glaforge
    Return is optional too
    25
    String greet() { 

    return "$message, $name speaking"

    }

    View Slide

  36. @glaforge
    Return is optional too
    25
    String greet() { 

    return "$message, $name speaking"

    }

    View Slide

  37. @glaforge
    Return is optional too
    26
    String greet() { 

    "$message, $name speaking"

    }

    View Slide

  38. @glaforge
    Return is optional too
    26
    String greet() { 

    "$message, $name speaking"

    }
    But return is fine for
    early returns, or for
    clarity of intent

    View Slide

  39. @glaforge
    Optional return for if / else
    27
    int color(String name) {

    if (name == 'red')

    1

    else if (name == 'green')

    2

    else

    -1

    }

    View Slide

  40. @glaforge
    Optional return for switch / case
    28
    int color(String name) {

    switch (name) {

    case 'red': 1; break

    case 'green': 2; break

    default: -1

    }

    }

    View Slide

  41. @glaforge
    Optional return for switch / case
    28
    int color(String name) {

    switch (name) {

    case 'red': 1; break

    case 'green': 2; break

    default: -1

    }

    } Yeah, yeah, ugly
    semicolon and break…

    View Slide

  42. @glaforge
    Optional return for try / catch
    29
    boolean isInt(String s) {

    try {

    Integer.parseInt(s)

    true

    } catch (NumberFormatException nfe) {

    false

    } finally {

    println 'done'

    }

    }


    assert isInt('123') && assert !isInt('abc')

    View Slide

  43. @glaforge
    Optional return for try / catch
    29
    boolean isInt(String s) {

    try {

    Integer.parseInt(s)

    true

    } catch (NumberFormatException nfe) {

    false

    } finally {

    println 'done'

    }

    }


    assert isInt('123') && assert !isInt('abc')
    ‘finally’ blocks don’t
    return a value

    View Slide

  44. View Slide

  45. @glaforge
    Omit parentheses
    31
    println('Hello, World')

    View Slide

  46. @glaforge
    Omit parentheses
    32
    println 'Hello, World'

    View Slide

  47. @glaforge
    Command chains
    33
    move forward at 3.km/h

    View Slide

  48. @glaforge
    Command chains
    33
    move forward at 3.km/h
    Parsed as:
    move(forward).at(3.getKm().div(h))

    View Slide

  49. @glaforge
    Command chains & named arguments
    34
    check that: wine tastes good

    View Slide

  50. @glaforge
    Command chains & named arguments
    34
    check that: wine tastes good
    Parsed as:
    check(that: wine).tastes(good)

    View Slide

  51. @glaforge
    Trailing closure argument gets out
    35
    void unless(boolean b, Closure c) {

    if (!b) c()

    }


    def (speed, limit) = [80, 90]


    unless(speed > limit) {

    println "speed up a notch"

    }

    View Slide

  52. @glaforge
    Trailing closure argument gets out
    35
    void unless(boolean b, Closure c) {

    if (!b) c()

    }


    def (speed, limit) = [80, 90]


    unless(speed > limit) {

    println "speed up a notch"

    }
    Parsed as:
    unless(speed > limit, {…})

    View Slide

  53. View Slide

  54. @glaforge
    Class as first-class citizen
    37
    connection.doPost("${BASE_URI}/submit", params,
    ResourcesResponse.class)

    View Slide

  55. @glaforge
    Class as first-class citizen
    38
    connection.doPost("${BASE_URI}/submit", params,
    ResourcesResponse)

    View Slide

  56. View Slide

  57. @glaforge
    No need for dumb getters and setters
    40
    class Person {

    private String name

    private int age


    void setName(String name) {

    this.name = name

    }

    String getName() {

    this.name

    }

    void setAge(int age) {

    this.age = age

    }

    int getAge() {

    this.age

    }

    }

    View Slide

  58. @glaforge
    No need for dumb getters and setters
    41
    class Person {

    String name

    int age

    }

    View Slide

  59. @glaforge
    No need for dumb getters and setters
    41
    class Person {

    String name

    int age

    }
    Icing on the cake:
    add @Immutable
    or @Canonical

    View Slide

  60. @glaforge
    Use the property notation
    42
    class Person {

    String name

    int age

    }


    def p = new Person(name: 'Guillaume', 

    age: 37)

    assert p.name == 'Guillaume'


    p.age = 38

    assert p.age == 38

    View Slide

  61. View Slide

  62. @glaforge
    Use the named-argument constructor
    44
    def p = new Person(name: 'Guillaume', 

    age: 38)

    View Slide

  63. @glaforge
    The @Builder transformation
    45
    import groovy.transform.builder.*


    @Builder

    class Person {

    String name

    int age

    }


    Person.builder()
    .name('Guillaume')
    .age(38)
    .build()

    View Slide

  64. @glaforge
    The @Builder transformation
    45
    import groovy.transform.builder.*


    @Builder

    class Person {

    String name

    int age

    }


    Person.builder()
    .name('Guillaume')
    .age(38)
    .build()
    Different strategies available:
    chained setters, external builder
    class, type-safe initializer

    View Slide

  65. View Slide

  66. @glaforge
    Equals and ==
    47
    status != null &&
    status.equals(Control.STATUS_COMPLETED)

    View Slide

  67. @glaforge
    Equals and ==
    48
    status == Control.STATUS_COMPLETED

    View Slide

  68. View Slide

  69. @glaforge
    Use single quotes for String constants
    50
    def msg = 'Groovy Rocks!'

    View Slide

  70. View Slide

  71. @glaforge
    Native syntax for data structures
    52
    def list = [1, 2, 3]

    def range = 'a'..'b'

    def map = [a: 1, b: 2, c: 3]

    def regex = ~/.*foo.*/

    View Slide

  72. View Slide

  73. @glaforge
    The Groovy Development Kit
    54

    View Slide

  74. @glaforge
    The Groovy Development Kit
    54

    View Slide

  75. @glaforge
    The Groovy Development Kit
    54
    Know your GDK!
    So much groovy-ness in there!

    View Slide

  76. View Slide

  77. @glaforge
    Switch / case on steroids
    56
    switch(obj) {

    case 123: "number 123"; break

    case "abc": "string abc"; break

    case String: "is a string"; break

    case [1, 2, 3]: "in list"; break

    case ~/.*o+.*/: "regex match"; break

    case { it < 3 }: "closure criteria"; break

    default: "unknown"

    }

    View Slide

  78. View Slide

  79. @glaforge
    Import aliasing
    58
    import java.util.List as juList

    import java.awt.List as aList


    import javax.swing.WindowConstants as WC

    View Slide

  80. @glaforge
    Import aliasing with static imports too
    59
    import static java.lang.Integer.parseInt as atoi


    assert atoi('123') == 123

    View Slide

  81. View Slide

  82. @glaforge
    Groovy Truth
    61
    assert !( null )

    assert !( "" )

    assert !( [] )

    assert !( 0 )
    assert new Object()

    assert "string"

    assert [1, 2, 3]

    assert 1234

    View Slide

  83. @glaforge
    Groovy Truth
    61
    assert !( null )

    assert !( "" )

    assert !( [] )

    assert !( 0 )
    assert new Object()

    assert "string"

    assert [1, 2, 3]

    assert 1234
    False

    View Slide

  84. @glaforge
    Groovy Truth
    61
    assert !( null )

    assert !( "" )

    assert !( [] )

    assert !( 0 )
    assert new Object()

    assert "string"

    assert [1, 2, 3]

    assert 1234
    False
    True

    View Slide

  85. @glaforge
    Customize the truth with asBoolean()
    62
    class Account {

    String name

    boolean disabled = false


    boolean asBoolean() { !disabled }

    }


    assert new Account(name: 'current')

    assert !new Account(name: 'old', disabled: true)

    View Slide

  86. View Slide

  87. View Slide

  88. @glaforge
    Safe navigation
    64
    // Java
    if (order != null) {

    if (order.getCustomer() != null) {

    if (order.getCustomer().getAddress() != null) {

    System.out.println(order.getCustomer().getAddress());

    }

    }

    }

    // Groovy
    println order?.customer?.address

    View Slide

  89. @glaforge
    Safe navigation
    64
    // Java
    if (order != null) {

    if (order.getCustomer() != null) {

    if (order.getCustomer().getAddress() != null) {

    System.out.println(order.getCustomer().getAddress());

    }

    }

    }

    // Groovy
    println order?.customer?.address
    Also give more
    meaningful NPEs!

    View Slide

  90. View Slide

  91. @glaforge
    Power Assert
    66
    def (a, b, c, d) = [10, 20, 30, 610]

    assert a + b * c == d - 40

    View Slide

  92. @glaforge
    Power Assert
    66
    def (a, b, c, d) = [10, 20, 30, 610]

    assert a + b * c == d - 40
    Assertion failed:


    assert a + b * c == d - 40

    | | | | | | | |

    10| 20| 30| | 570

    610 600 | 610

    false

    View Slide

  93. View Slide

  94. @glaforge
    Calling Elvis for default values
    68
    def result = name != null &&
    name.length() > 0 ?
    name : "Unknown"


    def result = name ?: "Unknown"

    View Slide

  95. @glaforge
    Calling Elvis for default values
    68
    def result = name != null &&
    name.length() > 0 ?
    name : "Unknown"


    def result = name ?: "Unknown"
    Groovy Truth 

    at play here

    View Slide

  96. View Slide

  97. @glaforge
    Catch ‘any’ exception
    70
    try {

    something()

    } catch (any) {

    // ...

    }

    View Slide

  98. @glaforge
    Catch ‘any’ exception
    70
    try {

    something()

    } catch (any) {

    // ...

    }
    Someone suggested me:
    catch(emAll)

    View Slide

  99. View Slide

  100. @glaforge
    Of the importance of contracts
    • Use explicit typing for
    • method signatures
    • properties & fields
    • Nice for
    • Java interoperability
    • documenting your APIs
    • IDE auto-completion and refactoring
    72

    View Slide

  101. SPRINGONE2GX
    WASHINGTON, DC
    Thanks for your attention!

    View Slide

  102. SPRINGONE2GX
    WASHINGTON, DC
    Q & A

    View Slide

  103. @glaforge 75
    Help us move Groovy forward!
    Next: Groovy REST!
    Groovy with Style
    @glaforge

    View Slide

  104. @glaforge
    Picture credits
    Style: http://1hdwallpapers.com/wallpapers/my_style.jpg
    Eurostar: http://www.whatsupwhatson.com/wp-content/uploads/2014/04/Eurostar_3012_Waterloo.jpg
    Puzzle: http://joyinthecause.org/wp-content/uploads/2014/03/missing-puzzle-piece_00449088.jpg
    Gems: http://www.freewhd.com/blue-gems-wallpaper/
    Wise: http://fc00.deviantart.net/fs70/i/2012/044/f/6/three_wise_men_color_by_csoro-d4pmlv2.jpg
    Ready: http://nameshapers.com/wp-content/uploads/2013/12/Social-Media-Coaching-for-CEOs-Getting-started.jpg
    Semicolon: http://www.freeimageslive.co.uk/image/view/3944/_original
    Till death to us part: https://mypencillines.files.wordpress.com/2013/04/img_0171.jpg
    Public: http://www.levelupliving.com/wp-content/uploads/2012/05/Fear-of-Public-Speaking-image.jpg
    Contract: https://www.icts.uiowa.edu/sites/default/files/contract.jpg
    Exception: http://www.quotescover.com/wp-content/uploads/Its-the-exception-that-proves__quotes-by-French-Proverb-77.png
    Banana: http://texturetaddka.com/wp-content/uploads/2011/10/DSC2008.jpg
    Elvis: http://natedsanders.com/blog/wp-content/uploads/2013/10/Elvis-Presley-Wallpaper-1280-x-960.jpeg
    Assert: http://www.itshouldjustworktm.com/wp-content/uploads/2012/03/assert-sign-photoshopped.jpg
    Compass: https://lh4.ggpht.com/WtY8QL0re9kMssF6q4RopDHC6QEpou7ybQo7qNRjn1X8Iu5uKUZv7huHA_PxPB8iGfs=h900
    Safety vest: http://media.nautisports.com/catalog/product/image/gilet-de-sauvetage-gonflable-hydrostatique-hammar-pilot-275-n-avec-harnais-pro-rouge-nav_17452_web_1_1.jpg
    Class: http://upload.wikimedia.org/wikipedia/en/5/50/A_Class_in_Progress.jpg
    Aliasing: http://i.imgur.com/JrFly.png
    Light switch: http://www.hapihour.org/wp-content/uploads/2014/04/lighting-design-wall-light-winsome-designer-light-switches-australia-designer-light-switchesdesigner-light-switches-and-platesdesigner-light-
    switches-coversdesigner-light-switches-graydesign.jpg
    Steel structure: http://www.jingtabuilding.com/UploadFiles/sl6.jpg
    Quotes: http://g.fastcompany.net/multisite_files/fastcompany/poster/2013/09/3018353-poster-1280-quotess3.jpg
    Setter: http://upload.wikimedia.org/wikipedia/commons/b/b4/Rzesz%C3%B3w_Irish_Red_and_White_Setter_1pl.jpg
    Argument: http://www.familytreecounseling.com/kathysblog/wp-content/uploads/2014/01/arguing_couple.jpg
    Equal cupcake: http://static.communitytable.com/wp-content/uploads/2013/04/marriage-equality-cupcakes-ftr.jpg
    Obama truth: http://upload.wikimedia.org/wikipedia/commons/7/7c/Obama_swearing_in.JPG
    Quiz: http://a622.phobos.apple.com/us/r30/Purple/v4/df/a9/6e/dfa96e6c-ea9b-ee4c-4d6c-f9edf2775e1d/mzl.exfkkuro.png
    return: http://legacyofshadow.com/wp-content/uploads/2012/04/no-return-sign.jpg
    spock: http://trekcore.com/gallery/albums/spock09/spock_pb04.jpg
    London: http://www.100percentoptical.com/images/2014/10/london.jpg
    Tie fighter: http://img3.wikia.nocookie.net/__cb20090419001710/uncyclopedia/images/f/fe/Darthvader_tie_fighter.jpg
    76

    View Slide