Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Groovy with Style — GR8Conf Europe 2015

Groovy with Style — GR8Conf Europe 2015

Groovy with Style: tips, tricks, nuggets, style advice for the Groovy developers!

Guillaume Laforge

June 03, 2015
Tweet

More Decks by Guillaume Laforge

Other Decks in Technology

Transcript

  1. Groovy
    with Style
    Guillaume Laforge
    @glaforge
    Restlet — the Web API platform
    Groovy project team

    View Slide

  2. We know
    about
    APIs!

    View Slide

  3. View Slide

  4. GR8Conf Promo Code: cfgr8eu39
    http://www.manning.com/koenig2/
    GROOVY
    IN ACTION
    2ND EDITION

    View Slide

  5. 11+ years of
    Groovy experience

    View Slide

  6. Quick intro to REST

    View Slide

  7. 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. 12
    http://www.groovy-lang.org/style-guide.html

    View Slide

  17. 12
    http://www.groovy-lang.org/style-guide.html

    View Slide

  18. View Slide

  19. View Slide

  20. View Slide

  21. 15
    No semicolons!
    class Hello {

    private String message = 'Hello!';

    String greet(String name) {

    "$message, $name speaking";

    } 

    }


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

    View Slide

  22. 15
    No semicolons!
    class Hello {

    private String message = 'Hello!';

    String greet(String name) {

    "$message, $name speaking";

    } 

    }


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

    View Slide

  23. 16
    No semicolons!
    class Hello {

    private String message = 'Hello'

    String greet(String name) {

    "$message, $name speaking"

    } 

    }


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

    View Slide

  24. View Slide

  25. 18
    Public by default
    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. 19
    Public by default
    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. 20
    class Hello {

    static String message = 'Hello’

    String name


    Hello(String name) {

    this.name = name

    }

    String greet() {

    return "$message, $name speaking"

    } 

    }
    Fields and static fields require visibility

    View Slide

  28. 20
    class Hello {

    static String message = 'Hello’

    String name


    Hello(String name) {

    this.name = name

    }

    String greet() {

    return "$message, $name speaking"

    } 

    }
    Fields and static fields require visibility
    You created both an
    instance property and a
    static property!

    View Slide

  29. View Slide

  30. 22
    Get rid of the useless ‘def’
    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. 22
    Get rid of the useless ‘def’
    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. 23
    Get rid of the useless ‘def’
    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. 24
    Get rid of the useless ‘def’
    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. 26
    Return is optional too
    String greet() { 

    return "$message, $name speaking"

    }

    View Slide

  36. 26
    Return is optional too
    String greet() { 

    return "$message, $name speaking"

    }

    View Slide

  37. 27
    Return is optional too
    String greet() { 

    "$message, $name speaking"

    }

    View Slide

  38. 27
    Return is optional too
    String greet() { 

    "$message, $name speaking"

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

    View Slide

  39. 28
    Optional return for if / else
    int color(String name) {

    if (name == 'red')

    1

    else if (name == 'green')

    2

    else

    -1

    }

    View Slide

  40. 29
    Optional return for switch / case
    int color(String name) {

    switch (name) {

    case 'red': 1; break

    case 'green': 2; break

    default: -1

    }

    }

    View Slide

  41. 29
    Optional return for switch / case
    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. 30
    Optional return for try / catch
    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. 30
    Optional return for try / catch
    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. 32
    Omit parentheses
    println('Hello, World')

    View Slide

  46. 33
    Omit parentheses
    println 'Hello, World'

    View Slide

  47. 34
    Command chains
    move forward at 3.km/h

    View Slide

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

    View Slide

  49. 35
    Command chains & named arguments
    check that: wine tastes good

    View Slide

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

    View Slide

  51. 36
    Trailing closure argument gets out
    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. 36
    Trailing closure argument gets out
    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. 38
    Class as first-class citizen
    connection.doPost("${BASE_URI}/submit", params,
    ResourcesResponse.class)

    View Slide

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

    View Slide

  56. View Slide

  57. 41
    No need for dumb getters and setters
    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. 42
    No need for dumb getters and setters
    class Person {

    String name

    int age

    }

    View Slide

  59. 42
    No need for dumb getters and setters
    class Person {

    String name

    int age

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

    View Slide

  60. 43
    Use the property notation
    class Person {

    String name

    int age

    }


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

    age: 36)

    assert p.name == 'Guillaume'


    p.age = 37

    assert p.age == 37

    View Slide

  61. View Slide

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

    age: 37)

    View Slide

  63. 46
    The @Builder transformation
    import groovy.transform.builder.*


    @Builder

    class Person {

    String name

    int age

    }


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

    View Slide

  64. 46
    The @Builder transformation
    import groovy.transform.builder.*


    @Builder

    class Person {

    String name

    int age

    }


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

    View Slide

  65. View Slide

  66. 48
    Equals and ==
    status != null &&
    status.equals(Control.STATUS_COMPLETED)

    View Slide

  67. 49
    Equals and ==
    status == Control.STATUS_COMPLETED

    View Slide

  68. View Slide

  69. 51
    Use single quotes for String constants
    def msg = 'Groovy Rocks!'

    View Slide

  70. View Slide

  71. 53
    Native syntax for data structures
    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. 55
    The Groovy Development Kit

    View Slide

  74. 55
    The Groovy Development Kit

    View Slide

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

    View Slide

  76. View Slide

  77. 57
    Switch / case on steroids
    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. 59
    Import aliasing
    import java.util.List as juList

    import java.awt.List as aList


    import javax.swing.WindowConstants as WC

    View Slide

  80. 60
    Import aliasing with static imports too
    import static java.lang.Integer.parseInt as atoi


    assert atoi('123') == 123

    View Slide

  81. View Slide

  82. 62
    Groovy Truth
    assert !( null )

    assert !( "" )

    assert !( [] )

    assert !( 0 )
    assert new Object()

    assert "string"

    assert [1, 2, 3]

    assert 1234

    View Slide

  83. 62
    Groovy Truth
    assert !( null )

    assert !( "" )

    assert !( [] )

    assert !( 0 )
    assert new Object()

    assert "string"

    assert [1, 2, 3]

    assert 1234
    False

    View Slide

  84. 62
    Groovy Truth
    assert !( null )

    assert !( "" )

    assert !( [] )

    assert !( 0 )
    assert new Object()

    assert "string"

    assert [1, 2, 3]

    assert 1234
    False
    True

    View Slide

  85. 63
    Customize the truth with asBoolean()
    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. 65
    Safe navigation
    // 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. 65
    Safe navigation
    // 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. 67
    Power Assert
    def (a, b, c, d) = [10, 20, 30, 610]

    assert a + b * c == d - 40

    View Slide

  92. 67
    Power Assert
    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. 69
    Calling Elvis for default values
    def result = name != null &&
    name.length() > 0 ?
    name : "Unknown"


    def result = name ?: "Unknown"

    View Slide

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


    def result = name ?: "Unknown"
    Groovy Truth 

    at play here

    View Slide

  96. View Slide

  97. 71
    Catch ‘any’ exception
    try {

    something()

    } catch (any) {

    // ...

    }

    View Slide

  98. 71
    Catch ‘any’ exception
    try {

    something()

    } catch (any) {

    // ...

    }
    Someone suggested me:
    catch(emAll)

    View Slide

  99. View Slide

  100. 73
    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

    View Slide

  101. Thanks for your attention!

    View Slide

  102. Q & A

    View Slide

  103. 76
    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

    View Slide