Slide 1

Slide 1 text

@glaforge #groovydvx Groovy with Style Guillaume Laforge @glaforge Restlet — the Web API platform Groovy project lead

Slide 2

Slide 2 text

11+ years of Groovy experience

Slide 3

Slide 3 text

@YourTwitterHandle @YourTwitterHandle @glaforge #groovydvx What style?

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

<=>

Slide 12

Slide 12 text

@glaforge #groovydvx http://www.groovy-lang.org/style-guide.html

Slide 13

Slide 13 text

@glaforge #groovydvx http://www.groovy-lang.org/style-guide.html

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

@glaforge #groovydvx No semicolons! class HelloParis {
 private String message = 'Hello Paris!'
 String greet(String name) {
 "$message, $name speaking"
 } 
 }
 
 print new HelloParis().greet('Guillaume')

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

@glaforge #groovydvx Public by default public class HelloParis {
 private String message = 'Hello Paris'
 private String name
 
 public HelloParis(String name) {
 this.name = name
 }
 public String greet() {
 return "$message, $name speaking"
 } 
 }

Slide 22

Slide 22 text

@glaforge #groovydvx Public by default class HelloParis {
 private String message = 'Hello Paris'
 private String name
 
 HelloParis(String name) {
 this.name = name
 }
 String greet() {
 return "$message, $name speaking"
 } 
 } Methods and classes are public by default

Slide 23

Slide 23 text

@glaforge #groovydvx class HelloParis {
 String message = 'Hello Paris!’
 String name
 
 HelloParis(String name) {
 this.name = name
 }
 String greet() {
 return "$message, $name speaking"
 } 
 } Fields and static fields require visibility

Slide 24

Slide 24 text

@glaforge #groovydvx class HelloParis {
 String message = 'Hello Paris!’
 String name
 
 HelloParis(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!

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

@glaforge #groovydvx Get rid of the useless ‘def’ class HelloParis {
 private String message = 'Hello Paris!'
 private def String name
 def HelloParis(def String name) {
 this.name = name
 }
 public def String greet() {
 def String result = "$message, $name speaking"
 return result
 } 
 }


Slide 27

Slide 27 text

@glaforge #groovydvx Get rid of the useless ‘def’ class HelloParis {
 private String message = 'Hello Paris!'
 private def String name
 def HelloParis(def String name) {
 this.name = name
 }
 public def String greet() {
 def String result = "$message, $name speaking"
 return result
 } 
 }


Slide 28

Slide 28 text

@glaforge #groovydvx Get rid of the useless ‘def’ class HelloParis {
 private String message = 'Hello Paris!'
 private String name
 HelloParis(String name) {
 this.name = name
 }
 String greet() {
 String result = "$message, $name speaking"
 return result
 } 
 }


Slide 29

Slide 29 text

@glaforge #groovydvx Get rid of the useless ‘def’ class HelloParis {
 private String message = 'Hello Paris!'
 private String name
 HelloParis(String name) {
 this.name = name
 }
 String greet() {
 def result = "$message, $name speaking"
 return result
 } 
 }
 But it’s fine to use ‘def’ for local variables

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

@glaforge #groovydvx Return is optional too String greet() { 
 return "$message, $name speaking"
 }

Slide 32

Slide 32 text

@glaforge #groovydvx Return is optional too String greet() { 
 return "$message, $name speaking"
 }

Slide 33

Slide 33 text

@glaforge #groovydvx Return is optional too String greet() { 
 "$message, $name speaking"
 }

Slide 34

Slide 34 text

@glaforge #groovydvx Return is optional too String greet() { 
 "$message, $name speaking"
 } But return is fine for early returns, or for clarity of intent

Slide 35

Slide 35 text

@glaforge #groovydvx Optional return for if / else int color(String name) {
 if (name == 'red')
 1
 else if (name == 'green')
 2
 else
 -1
 }

Slide 36

Slide 36 text

@glaforge #groovydvx Optional return for switch / case int color(String name) {
 switch (name) {
 case 'red': 1; break
 case 'green': 2; break
 default: -1
 }
 }

Slide 37

Slide 37 text

@glaforge #groovydvx 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…

Slide 38

Slide 38 text

@glaforge #groovydvx 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')

Slide 39

Slide 39 text

@glaforge #groovydvx 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

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

@glaforge #groovydvx Omit parentheses println('Hello, World')

Slide 42

Slide 42 text

@glaforge #groovydvx Omit parentheses println 'Hello, World'

Slide 43

Slide 43 text

@glaforge #groovydvx Command chains move forward at 3.km/h

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

@glaforge #groovydvx Command chains & named arguments check that: wine tastes good

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

@glaforge #groovydvx 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"
 }

Slide 48

Slide 48 text

@glaforge #groovydvx 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, {…})

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

@glaforge #groovydvx 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
 }
 }

Slide 54

Slide 54 text

@glaforge #groovydvx No need for dumb getters and setters class Person {
 String name
 int age
 }

Slide 55

Slide 55 text

@glaforge #groovydvx No need for dumb getters and setters class Person {
 String name
 int age
 } Icing on the cake: add @Immutable or @Canonical

Slide 56

Slide 56 text

@glaforge #groovydvx 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

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

@glaforge #groovydvx Use the named-argument constructor def p = new Person(name: 'Guillaume', 
 age: 37)

Slide 59

Slide 59 text

@glaforge #groovydvx The @Builder transformation import groovy.transform.builder.*
 
 @Builder
 class Person {
 String name
 int age
 }
 
 Person.builder() .name('Guillaume') .age(37) .build()

Slide 60

Slide 60 text

@glaforge #groovydvx 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

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

@glaforge #groovydvx Equals and == status != null && status.equals(Control.STATUS_COMPLETED)

Slide 63

Slide 63 text

@glaforge #groovydvx Equals and == status == Control.STATUS_COMPLETED

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

@glaforge #groovydvx Use single quotes for String constants def msg = 'Groovy Rocks!'

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

@glaforge #groovydvx 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.*/

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

@glaforge #groovydvx The Groovy Development Kit

Slide 70

Slide 70 text

@glaforge #groovydvx The Groovy Development Kit

Slide 71

Slide 71 text

@glaforge #groovydvx The Groovy Development Kit Know your GDK! So much groovy-ness in there!

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

@glaforge #groovydvx 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"
 }

Slide 74

Slide 74 text

No content

Slide 75

Slide 75 text

@glaforge #groovydvx Import aliasing import java.util.List as juList
 import java.awt.List as aList
 
 import javax.swing.WindowConstants as WC

Slide 76

Slide 76 text

@glaforge #groovydvx Import aliasing with static imports too import static java.lang.Integer.parseInt as atoi
 
 assert atoi('123') == 123

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

@glaforge #groovydvx Groovy Truth assert !( null )
 assert !( "" )
 assert !( [] )
 assert !( 0 ) assert new Object()
 assert "string"
 assert [1, 2, 3]
 assert 1234 False True

Slide 81

Slide 81 text

@glaforge #groovydvx 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)

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

@glaforge #groovydvx 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

Slide 85

Slide 85 text

@glaforge #groovydvx 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!

Slide 86

Slide 86 text

No content

Slide 87

Slide 87 text

@glaforge #groovydvx Power Assert def (a, b, c, d) = [10, 20, 30, 610]
 assert a + b * c == d - 40

Slide 88

Slide 88 text

@glaforge #groovydvx 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

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

@glaforge #groovydvx Calling Elvis for default values def result = name != null ? name : "Unknown"
 
 def result = name ?: "Unknown"

Slide 91

Slide 91 text

@glaforge #groovydvx Calling Elvis for default values def result = name != null ? name : "Unknown"
 
 def result = name ?: "Unknown" Groovy Truth 
 at play here

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

@glaforge #groovydvx Catch ‘any’ exception try {
 something()
 } catch (any) {
 // ...
 } Someone suggested me: catch(emAll)

Slide 95

Slide 95 text

No content

Slide 96

Slide 96 text

@glaforge #groovydvx 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

Slide 97

Slide 97 text

@YourTwitterHandle @YourTwitterHandle @glaforge #groovydvx Thanks for your attention!

Slide 98

Slide 98 text

@YourTwitterHandle @YourTwitterHandle @glaforge #groovydvx Q & A

Slide 99

Slide 99 text

@glaforge #groovydvx 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