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 full-size slide

  2. We know
    about
    APIs!

    View full-size slide

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

    View full-size slide

  4. 11+ years of
    Groovy experience

    View full-size slide

  5. Quick intro to REST

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  8. 15
    No semicolons!
    class Hello {

    private String message = 'Hello!';

    String greet(String name) {

    "$message, $name speaking";

    } 

    }


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

    View full-size slide

  9. 15
    No semicolons!
    class Hello {

    private String message = 'Hello!';

    String greet(String name) {

    "$message, $name speaking";

    } 

    }


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

    View full-size slide

  10. 16
    No semicolons!
    class Hello {

    private String message = 'Hello'

    String greet(String name) {

    "$message, $name speaking"

    } 

    }


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

    View full-size slide

  11. 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 full-size slide

  12. 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 full-size slide

  13. 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 full-size slide

  14. 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 full-size slide

  15. 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 full-size slide

  16. 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 full-size slide

  17. 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 full-size slide

  18. 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 full-size slide

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

    return "$message, $name speaking"

    }

    View full-size slide

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

    return "$message, $name speaking"

    }

    View full-size slide

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

    "$message, $name speaking"

    }

    View full-size slide

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

    "$message, $name speaking"

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

    View full-size slide

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

    if (name == 'red')

    1

    else if (name == 'green')

    2

    else

    -1

    }

    View full-size slide

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

    switch (name) {

    case 'red': 1; break

    case 'green': 2; break

    default: -1

    }

    }

    View full-size slide

  25. 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 full-size slide

  26. 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 full-size slide

  27. 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 full-size slide

  28. 32
    Omit parentheses
    println('Hello, World')

    View full-size slide

  29. 33
    Omit parentheses
    println 'Hello, World'

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  34. 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 full-size slide

  35. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  38. 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 full-size slide

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

    String name

    int age

    }

    View full-size slide

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

    String name

    int age

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

    View full-size slide

  41. 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 full-size slide

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

    age: 37)

    View full-size slide

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


    @Builder

    class Person {

    String name

    int age

    }


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

    View full-size slide

  44. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  48. 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 full-size slide

  49. 55
    The Groovy Development Kit

    View full-size slide

  50. 55
    The Groovy Development Kit

    View full-size slide

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

    View full-size slide

  52. 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 full-size slide

  53. 59
    Import aliasing
    import java.util.List as juList

    import java.awt.List as aList


    import javax.swing.WindowConstants as WC

    View full-size slide

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


    assert atoi('123') == 123

    View full-size slide

  55. 62
    Groovy Truth
    assert !( null )

    assert !( "" )

    assert !( [] )

    assert !( 0 )
    assert new Object()

    assert "string"

    assert [1, 2, 3]

    assert 1234

    View full-size slide

  56. 62
    Groovy Truth
    assert !( null )

    assert !( "" )

    assert !( [] )

    assert !( 0 )
    assert new Object()

    assert "string"

    assert [1, 2, 3]

    assert 1234
    False

    View full-size slide

  57. 62
    Groovy Truth
    assert !( null )

    assert !( "" )

    assert !( [] )

    assert !( 0 )
    assert new Object()

    assert "string"

    assert [1, 2, 3]

    assert 1234
    False
    True

    View full-size slide

  58. 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 full-size slide

  59. 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 full-size slide

  60. 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 full-size slide

  61. 67
    Power Assert
    def (a, b, c, d) = [10, 20, 30, 610]

    assert a + b * c == d - 40

    View full-size slide

  62. 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 full-size slide

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


    def result = name ?: "Unknown"

    View full-size slide

  64. 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 full-size slide

  65. 71
    Catch ‘any’ exception
    try {

    something()

    } catch (any) {

    // ...

    }

    View full-size slide

  66. 71
    Catch ‘any’ exception
    try {

    something()

    } catch (any) {

    // ...

    }
    Someone suggested me:
    catch(emAll)

    View full-size slide

  67. 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 full-size slide

  68. Thanks for your attention!

    View full-size slide

  69. 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 full-size slide