Save 37% off PRO during our Black Friday Sale! »

Groovy with Style - SpringOne2GX 2015 - Guillaume Laforge

Groovy with Style - SpringOne2GX 2015 - Guillaume Laforge

137d3908243acfc30e126615d59d4e6d?s=128

Guillaume Laforge

September 15, 2015
Tweet

Transcript

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

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

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

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

  6. SPRINGONE2GX WASHINGTON, DC 12 years of Groovy experience

  7. SPRINGONE2GX WASHINGTON, DC What style?

  8. None
  9. None
  10. None
  11. None
  12. None
  13. None
  14. None
  15. <=>

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

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

  18. None
  19. None
  20. None
  21. @glaforge No semicolons! 14 class Hello {
 private String message

    = 'Hello!';
 String greet(String name) {
 "$message, $name speaking";
 } 
 }
 
 print new Hello().greet('Guillaume');
  22. @glaforge No semicolons! 14 class Hello {
 private String message

    = 'Hello!';
 String greet(String name) {
 "$message, $name speaking";
 } 
 }
 
 print new Hello().greet('Guillaume');
  23. @glaforge No semicolons! 15 class Hello {
 private String message

    = 'Hello'
 String greet(String name) {
 "$message, $name speaking"
 } 
 }
 
 print new Hello().greet('Guillaume')
  24. None
  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"
 } 
 }
  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
  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"
 } 
 }
  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!
  29. None
  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
 } 
 }

  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
 } 
 }

  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
 } 
 }

  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
  34. None
  35. @glaforge Return is optional too 25 String greet() { 


    return "$message, $name speaking"
 }
  36. @glaforge Return is optional too 25 String greet() { 


    return "$message, $name speaking"
 }
  37. @glaforge Return is optional too 26 String greet() { 


    "$message, $name speaking"
 }
  38. @glaforge Return is optional too 26 String greet() { 


    "$message, $name speaking"
 } But return is fine for early returns, or for clarity of intent
  39. @glaforge Optional return for if / else 27 int color(String

    name) {
 if (name == 'red')
 1
 else if (name == 'green')
 2
 else
 -1
 }
  40. @glaforge Optional return for switch / case 28 int color(String

    name) {
 switch (name) {
 case 'red': 1; break
 case 'green': 2; break
 default: -1
 }
 }
  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…
  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')
  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
  44. None
  45. @glaforge Omit parentheses 31 println('Hello, World')

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

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

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

    move(forward).at(3.getKm().div(h))
  49. @glaforge Command chains & named arguments 34 check that: wine

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

    tastes good Parsed as: check(that: wine).tastes(good)
  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"
 }
  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, {…})
  53. None
  54. @glaforge Class as first-class citizen 37 connection.doPost("${BASE_URI}/submit", params, ResourcesResponse.class)

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

  56. None
  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
 }
 }
  58. @glaforge No need for dumb getters and setters 41 class

    Person {
 String name
 int age
 }
  59. @glaforge No need for dumb getters and setters 41 class

    Person {
 String name
 int age
 } Icing on the cake: add @Immutable or @Canonical
  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
  61. None
  62. @glaforge Use the named-argument constructor 44 def p = new

    Person(name: 'Guillaume', 
 age: 38)
  63. @glaforge The @Builder transformation 45 import groovy.transform.builder.*
 
 @Builder
 class

    Person {
 String name
 int age
 }
 
 Person.builder() .name('Guillaume') .age(38) .build()
  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
  65. None
  66. @glaforge Equals and == 47 status != null && status.equals(Control.STATUS_COMPLETED)

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

  68. None
  69. @glaforge Use single quotes for String constants 50 def msg

    = 'Groovy Rocks!'
  70. None
  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.*/
  72. None
  73. @glaforge The Groovy Development Kit 54

  74. @glaforge The Groovy Development Kit 54

  75. @glaforge The Groovy Development Kit 54 Know your GDK! So

    much groovy-ness in there!
  76. None
  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"
 }
  78. None
  79. @glaforge Import aliasing 58 import java.util.List as juList
 import java.awt.List

    as aList
 
 import javax.swing.WindowConstants as WC
  80. @glaforge Import aliasing with static imports too 59 import static

    java.lang.Integer.parseInt as atoi
 
 assert atoi('123') == 123
  81. None
  82. @glaforge Groovy Truth 61 assert !( null )
 assert !(

    "" )
 assert !( [] )
 assert !( 0 ) assert new Object()
 assert "string"
 assert [1, 2, 3]
 assert 1234
  83. @glaforge Groovy Truth 61 assert !( null )
 assert !(

    "" )
 assert !( [] )
 assert !( 0 ) assert new Object()
 assert "string"
 assert [1, 2, 3]
 assert 1234 False
  84. @glaforge Groovy Truth 61 assert !( null )
 assert !(

    "" )
 assert !( [] )
 assert !( 0 ) assert new Object()
 assert "string"
 assert [1, 2, 3]
 assert 1234 False True
  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)
  86. None
  87. None
  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
  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!
  90. None
  91. @glaforge Power Assert 66 def (a, b, c, d) =

    [10, 20, 30, 610]
 assert a + b * c == d - 40
  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
  93. None
  94. @glaforge Calling Elvis for default values 68 def result =

    name != null && name.length() > 0 ? name : "Unknown"
 
 def result = name ?: "Unknown"
  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
  96. None
  97. @glaforge Catch ‘any’ exception 70 try {
 something()
 } catch

    (any) {
 // ...
 }
  98. @glaforge Catch ‘any’ exception 70 try {
 something()
 } catch

    (any) {
 // ...
 } Someone suggested me: catch(emAll)
  99. None
  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
  101. SPRINGONE2GX WASHINGTON, DC Thanks for your attention!

  102. SPRINGONE2GX WASHINGTON, DC Q & A

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

    Groovy with Style @glaforge
  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