SlideShare une entreprise Scribd logo
1  sur  210
Télécharger pour lire hors ligne
What makes
Groovy groovy?
Guillaume Laforge
@glaforge
© 2013 Guillaume Laforge. All rights reserved. Do not distribute without permission.
Guillaume
Laforge
Groovy project lead
at
.
@glaforge
http://glaforge.appspot.com
Les Cast
Codeurs
1
t
r
a
P

The Groovy
vision
Simplify the life of
(Java) developers
Great for
scripting
Great for
scripting

Fit for DomainSpecific Languages
Great for
scripting

Fit for DomainSpecific Languages

Most seamless integration &
interoperability wih java!
It’s so easy
to learn!
Groovy as a
Java superset

It’s so easy
to learn!
class!MathSpec!extends!Specification!{
!!!!def!"maximum!of!two!numbers"()!{
******expect:
!!!!!!!!Math.max(a,!b)!==!c
******where:
!!!!!!!!a!|!b!||!c
!!!!!!!!1!|!3!||!3
!!!!!!!!7!|!4!||!4
!!!!!!!!0!|!0!||!0
!!!!}
}
As safe and fast as Java with
static type checking & compilation
As safe and fast as Java with
static type checking & compilation
new!MarkupBuilder().html!{
!!!!head!{
!!!!!!!!title!"The!Script!Bowl"
!!!!}
!!!!body!{
!!!!!!!!div(class:!"banner")!{
!!!!!!!!!!!!p!"Groovy!rocks!"
!!!!!!!!}
!!!!}
}
move!forward!at!3.km/h
Expressive,
Concise,
Readable
Speaking of conciseness...
A full Spring app in the span of a tweet!
@RestController
class!App!{
!!!!@RequestMapping("/")
!!!!String!home()!{!"Hello!World!"!}
}
• SmartThings
• Carriots

Services

• European Patent
Office
• Amadeus
IoT

Financial

• Crédit Suisse
• JPMorgan
• Fanny Mae
• Mutual of Omaha
• Hypoport
20

• Energy Transfer
• National Cancer Inst.
• IRSN

Internet

• Netflix
• LinkedIn
• Google

Technology

Who’s using Groovy?
2
t
r
a
P

Cool Groovy
gems
Most Java code is also
valid Groovy code!
Most Java code is also
valid Groovy code!

Any Java developer is a
Groovy developer!
Flat learning
curve
Flat learning
curve

Easy to learn
Scripts versus Classes
public!class!Main!{
!!!!public!static!void!main(String[]!args)!{
!!!!!!!!System.out.println("Hello");
!!!!}
}

vs
24
Scripts versus Classes
public!class!Main!{
!!!!public!static!void!main(String[]!args)!{
!!!!!!!!System.out.println("Hello");
!!!!}
}

vs
println!"Hello"
24
Optional
Semicolons

Optional
Semicolons
Parentheses

Optional
Semicolons
Parentheses

Optional
return keyword
Semicolons
Parentheses

Optional
return keyword

public keyword
Semicolons
Parentheses

Optional
Typing!
return keyword

public keyword
Optional...
public!class!Greeter!{
!!!!private!String!owner;
!!!!public!String!getOwner()!{
!!!!!!!!return!owner;
!!!!}
!!!!public!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner;
!!!!}
!!!!public*String!greet(String!name)!{
!!!!!!!!return!"Hello!"!+!name!+!",!I!am!"!+!owner;
!!!!}
}
Greeter!greeter!=!new!Greeter();
greeter.setOwner("Guillaume");
System.out.println(greeter.greet("Marion"));
26
Optional...

Semicolons

public!class!Greeter!{
!!!!private!String!owner;
!!!!public!String!getOwner()!{
!!!!!!!!return!owner;
!!!!}
!!!!public!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner;
!!!!}
!!!!public*String!greet(String!name)!{
!!!!!!!!return!"Hello!"!+!name!+!",!I!am!"!+!owner;
!!!!}
}
Greeter!greeter!=!new!Greeter();
greeter.setOwner("Guillaume");
System.out.println(greeter.greet("Marion"));
26
Optional...
public!class!Greeter!{
!!!!private!String!owner
!!!!public!String!getOwner()!{
!!!!!!!!return!owner
!!!!}
!!!!public!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!public*String!greet(String!name)!{
!!!!!!!!return!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
Greeter!greeter!=!new!Greeter()
greeter.setOwner("Guillaume")
System.out.println(greeter.greet("Marion"))
27
Optional...
public!class!Greeter!{
!!!!private!String!owner
!!!!public!String!getOwner()!{
!!!!!!!!return!owner
!!!!}
!!!!public!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!public*String!greet(String!name)!{
!!!!!!!!return!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
Greeter!greeter!=!new!Greeter()
greeter.setOwner("Guillaume")
System.out.println(greeter.greet("Marion"))
28
Optional...
public!class!Greeter!{
!!!!private!String!owner
!!!!public!String!getOwner()!{
!!!!!!!!return!owner
!!!!}
!!!!public!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!public*String!greet(String!name)!{
!!!!!!!!return!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}

Parentheses

Greeter!greeter!=!new!Greeter()
greeter.setOwner("Guillaume")
System.out.println(greeter.greet("Marion"))
28
Optional...
public!class!Greeter!{
!!!!private!String!owner
!!!!public!String!getOwner()!{
!!!!!!!!return!owner
!!!!}
!!!!public!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!public*String!greet(String!name)!{
!!!!!!!!return!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
Greeter!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
System.out.println!greeter.greet("Marion")
29
Optional...
public!class!Greeter!{
!!!!private!String!owner
!!!!public!String!getOwner()!{
!!!!!!!!return!owner
!!!!}
!!!!public!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}

return keyword

!!!!public*String!greet(String!name)!{
!!!!!!!!return!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
Greeter!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
System.out.println!greeter.greet("Marion")
29
Optional...
public!class!Greeter!{
!!!!private!String!owner
!!!!public!String!getOwner()!{
!!!!!!!!******!owner
!!!!}
!!!!public!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!public*String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
Greeter!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
System.out.println!greeter.greet("Marion")
30
Optional...
public!class!Greeter!{
!!!!private!String!owner
!!!!public!String!getOwner()!{
!!!!!!!!******!owner
!!!!}

public keyword

!!!!public!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!public*String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
Greeter!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
System.out.println!greeter.greet("Marion")
30
Optional...
******!class!Greeter!{
!!!!private!String!owner
!!!!******!String!getOwner()!{
!!!!!!!!******!owner
!!!!}
!!!!******!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
Greeter!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
System.out.println!greeter.greet("Marion")
31
Optional...
******!class!Greeter!{
!!!!private!String!owner
!!!!******!String!getOwner()!{
!!!!!!!!******!owner
!!!!}
!!!!******!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}

optional typing

Greeter!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
System.out.println!greeter.greet("Marion")
31
Optional...
******!class!Greeter!{
!!!!private!String!owner
!!!!******!String!getOwner()!{
!!!!!!!!******!owner
!!!!}
!!!!******!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
def!!!!!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
System.out.println!greeter.greet("Marion")
32
Optional...
******!class!Greeter!{
!!!!private!String!owner
!!!!******!String!getOwner()!{
!!!!!!!!******!owner
!!!!}
!!!!******!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}

handy println shortcut

def!!!!!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
System.out.println!greeter.greet("Marion")
32
Optional...
******!class!Greeter!{
!!!!private!String!owner
!!!!******!String!getOwner()!{
!!!!!!!!******!owner
!!!!}
!!!!******!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
def!!!!!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
!!!!!!!!!!!println!greeter.greet("Marion")
33
Optional...

verbose Java properties!

******!class!Greeter!{
!!!!private!String!owner
!!!!******!String!getOwner()!{
!!!!!!!!******!owner
!!!!}
!!!!******!void!setOwner(String!owner)!{
!!!!!!!!this.owner!=!owner
!!!!}
!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
def!!!!!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
!!!!!!!!!!!println!greeter.greet("Marion")
33
Optional...
******!class!Greeter!{
!!!!*******!String!owner

!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
def!!!!!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
!!!!!!!!!!!println!greeter.greet("Marion")
34
Optional...
******!class!Greeter!{
!!!!*******!String!owner

!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}

Property notation

def!!!!!greeter!=!new!Greeter()
greeter.setOwner!"Guillaume"
!!!!!!!!!!!println!greeter.greet("Marion")
34
Optional...
******!class!Greeter!{
!!!!*******!String!owner

!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
def!!!!!greeter!=!new!Greeter()
greeter.owner!!!!"Guillaume"
!!!!!!!!!!!println!greeter.greet("Marion")
35
Optional...
******!class!Greeter!{
!!!!*******!String!owner

Named argument
!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
constructor
!!!!}
}
def!!!!!greeter!=!new!Greeter()
greeter.owner!!!!"Guillaume"
!!!!!!!!!!!println!greeter.greet("Marion")
35
Optional...
******!class!Greeter!{
!!!!*******!String!owner

!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
def!!!!!greeter!=!new!Greeter(owner:!"Guillaume")
!!!!!!!!!!!println!greeter.greet("Marion")
36
Optional...
******!class!Greeter!{
!!!!*******!String!owner

Interpolated strings!
(aka GStrings)
!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!"!+!name!+!",!I!am!"!+!owner
!!!!}
}
def!!!!!greeter!=!new!Greeter(owner:!"Guillaume")
!!!!!!!!!!!println!greeter.greet("Marion")
36
Optional...
******!class!Greeter!{
!!!!*******!String!owner

!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!${name},!I!am!${owner}"
!!!!}
}
def!!!!!greeter!=!new!Greeter(owner:!"Guillaume")
!!!!!!!!!!!println!greeter.greet("Marion")
37
Optional...
******!class!Greeter!{
!!!!*******!String!owner

Let’s reformat that
mess of whitespace!

!!!!*******String!greet(String!name)!{
!!!!!!!!******!"Hello!${name},!I!am!${owner}"
!!!!}
}
def!!!!!greeter!=!new!Greeter(owner:!"Guillaume")
!!!!!!!!!!!println!greeter.greet("Marion")
37
Optional...
class!Greeter!{
***!String!owner
****String!greet(String!name)!{
******!"Hello!${name},!I!am!${owner}"
!!!!}
}
def!greeter!=!new!Greeter(owner:!"Guillaume")
println!greeter.greet("Marion")

38
Optional...
public!class!Greeter!{
!!!!private!String!owner;
!!!!public!String!getOwner()!{
class!Greeter!{
!!!!!!!!return!owner;
***!String!owner
!!!!}
****String!greet(String!name)!{
!!!!public!void!setOwner(String!owner)!{
******!"Hello!${name},!I!am!${owner}"
!!!!!!!!this.owner!=!owner;
!!!!}
!!!!}}
!!!!public*String!greet(String!name)!{
def!greeter!=!new!Greeter(owner:!"Guillaume")
!!!!!!!!return!"Hello!"!+!name!+!",!I!am!"!+!owner;
!!!!}println!greeter.greet("Marion")
}
Greeter!greeter!=!new!Greeter();
greeter.setOwner("Guillaume");
System.out.println(greeter.greet("Marion"));
38
Optional...
class!Greeter!{
***!String!owner
****String!greet(String!name)!{
******!"Hello!${name},!I!am!${owner}"
!!!!}
}
def!greeter!=!new!Greeter(owner:!"Guillaume")
println!greeter.greet("Marion")

38
Native syntax constructs
• Closures
• Lists
• Maps
• Regular expressions
• Ranges
39
Closures
• Functions as first-class citizen of the language

40
Lists
def!list!=!['a',!'b',!'c']
list!<<!'d'
assert!list.contains('d')
assert!list.findAll!{!it.startsWith!'a'!}.size()!==!1
assert!list.collect!{!it.toUpperCase()!}!==!['A',!'B',!'C',!'D']
assert!list.inject('')!{!a,!b!c>!a!+!b!}!==!'abcd'

41
Lists

List definition

def!list!=!['a',!'b',!'c']
list!<<!'d'
assert!list.contains('d')
assert!list.findAll!{!it.startsWith!'a'!}.size()!==!1
assert!list.collect!{!it.toUpperCase()!}!==!['A',!'B',!'C',!'D']
assert!list.inject('')!{!a,!b!c>!a!+!b!}!==!'abcd'

41
Lists

List definition

def!list!=!['a',!'b',!'c']

Append an element
(operator overloading)

list!<<!'d'
assert!list.contains('d')
assert!list.findAll!{!it.startsWith!'a'!}.size()!==!1
assert!list.collect!{!it.toUpperCase()!}!==!['A',!'B',!'C',!'D']
assert!list.inject('')!{!a,!b!c>!a!+!b!}!==!'abcd'

41
Lists

List definition

def!list!=!['a',!'b',!'c']

Append an element
(operator overloading)

list!<<!'d'
assert!list.contains('d')
assert!list.findAll!{!it.startsWith!'a'!}.size()!==!1
assert!list.collect!{!it.toUpperCase()!}!==!['A',!'B',!'C',!'D']
assert!list.inject('')!{!a,!b!c>!a!+!b!}!==!'abcd'

Functional-style
map / filter / reduce
with closures
41
Maps
def!map!=![name:!'Guillaume',!age:!36]
map.daughters!=!['Marion',!'Erine']
assert!map['daughters'].contains('Marion')

42
Maps

Map definition

def!map!=![name:!'Guillaume',!age:!36]
map.daughters!=!['Marion',!'Erine']
assert!map['daughters'].contains('Marion')

42
Maps

Map definition

def!map!=![name:!'Guillaume',!age:!36]
map.daughters!=!['Marion',!'Erine']
assert!map['daughters'].contains('Marion')

Indexed access

42
Maps

Map definition

def!map!=![name:!'Guillaume',!age:!36]
map.daughters!=!['Marion',!'Erine']
assert!map['daughters'].contains('Marion')

Property
notation access

42

Indexed access
Regular expressions
def!pattern!=!~/.*foo.*/
assert!"Alibaba"!==~!/.*(ba){2}/
def!matcher!=!"Superman"!=~!/([AcZ][acz]+)man/
assert!matcher[0][0]!==!'Superman'
assert!matcher[0][1]!==!'Super'
'75001!Paris'.find(/(d{5})s(w)+/)!{!match,!cp,!town!c>
!!!!println!"The!Zip!code!of!${town}!is!${cp}"
}

43
Regular expressions
Pattern
def!pattern!=!~/.*foo.*/
assert!"Alibaba"!==~!/.*(ba){2}/
def!matcher!=!"Superman"!=~!/([AcZ][acz]+)man/
assert!matcher[0][0]!==!'Superman'
assert!matcher[0][1]!==!'Super'
'75001!Paris'.find(/(d{5})s(w)+/)!{!match,!cp,!town!c>
!!!!println!"The!Zip!code!of!${town}!is!${cp}"
}

43
Regular expressions
Pattern

Match

def!pattern!=!~/.*foo.*/
assert!"Alibaba"!==~!/.*(ba){2}/
def!matcher!=!"Superman"!=~!/([AcZ][acz]+)man/
assert!matcher[0][0]!==!'Superman'
assert!matcher[0][1]!==!'Super'
'75001!Paris'.find(/(d{5})s(w)+/)!{!match,!cp,!town!c>
!!!!println!"The!Zip!code!of!${town}!is!${cp}"
}

43
Regular expressions
Pattern

Match

def!pattern!=!~/.*foo.*/
assert!"Alibaba"!==~!/.*(ba){2}/

Find

def!matcher!=!"Superman"!=~!/([AcZ][acz]+)man/
assert!matcher[0][0]!==!'Superman'
assert!matcher[0][1]!==!'Super'
'75001!Paris'.find(/(d{5})s(w)+/)!{!match,!cp,!town!c>
!!!!println!"The!Zip!code!of!${town}!is!${cp}"
}

43
Regular expressions
Pattern

Match

def!pattern!=!~/.*foo.*/
assert!"Alibaba"!==~!/.*(ba){2}/

Find

def!matcher!=!"Superman"!=~!/([AcZ][acz]+)man/
assert!matcher[0][0]!==!'Superman'
assert!matcher[0][1]!==!'Super'
'75001!Paris'.find(/(d{5})s(w)+/)!{!match,!cp,!town!c>
!!!!println!"The!Zip!code!of!${town}!is!${cp}"
}

Nice way to decompose the matched regions
43
Ranges
def!range!=!'a'..'z'
assert!range.contains('m')
assert!range.contains('z')
def!exclusive!=!1..<10
assert!!exclusive.contains(10)
def!reverse!=!10..0
assert!reverse[0]!==!10
assert!reverse[c1]!==!0
44
Ranges

Range

def!range!=!'a'..'z'
assert!range.contains('m')
assert!range.contains('z')
def!exclusive!=!1..<10
assert!!exclusive.contains(10)
def!reverse!=!10..0
assert!reverse[0]!==!10
assert!reverse[c1]!==!0
44
Ranges

Range

def!range!=!'a'..'z'
assert!range.contains('m')
assert!range.contains('z')
def!exclusive!=!1..<10

Excluded upper bound

assert!!exclusive.contains(10)
def!reverse!=!10..0
assert!reverse[0]!==!10
assert!reverse[c1]!==!0
44
Ranges

Range

def!range!=!'a'..'z'
assert!range.contains('m')
assert!range.contains('z')
def!exclusive!=!1..<10

Excluded upper bound

assert!!exclusive.contains(10)
def!reverse!=!10..0
assert!reverse[0]!==!10
assert!reverse[c1]!==!0
44

Reverse range
Ranges

Range

def!range!=!'a'..'z'
assert!range.contains('m')
assert!range.contains('z')
def!exclusive!=!1..<10

Excluded upper bound

assert!!exclusive.contains(10)
def!reverse!=!10..0
assert!reverse[0]!==!10
assert!reverse[c1]!==!0
44

Reverse range
Negative index count
from the end
Strings, GStrings, multiline strings

def!name!=!'Groovy'
def!tmpl!=!"""
!!!!Dear!Mr!${name},
!!!!You're!the!winner!of!the!lottery!
!!!!Yours!sincerly,
!!!!Dave
"""
assert!tmpl.toString().contains('Groovy')

45
Strings, GStrings, multiline strings
Plain java.lang.String
def!name!=!'Groovy'
def!tmpl!=!"""
!!!!Dear!Mr!${name},
!!!!You're!the!winner!of!the!lottery!
!!!!Yours!sincerly,
!!!!Dave
"""
assert!tmpl.toString().contains('Groovy')

45
Strings, GStrings, multiline strings
Plain java.lang.String
def!name!=!'Groovy'
Multiline string with
def!tmpl!=!"""
expression interpolation
!!!!Dear!Mr!${name},
!!!!You're!the!winner!of!the!lottery!
!!!!Yours!sincerly,
!!!!Dave
"""
assert!tmpl.toString().contains('Groovy')

45
Surprising numbers...

System.out.println(!2.0!c!1.1!);

46
Surprising numbers...

System.out.println(!2.0!c!1.1!);
0.8999999999999999

46
Surprising numbers...

System.out.println(!2.0!c!1.1!);
0.8999999999999999

46
Surprising numbers...

System.out.println(!3!/!2!);

47
Surprising numbers...

System.out.println(!3!/!2!);
1

47
Surprising numbers...

System.out.println(!3!/!2!);
1

47
BigDecimal by default!

assert!2.0!c!1.1!==!0.9
assert!3!/!2!==!1.5

48
BigDecimal by default!

assert!2.0!c!1.1!==!0.9
assert!3!/!2!==!1.5
One of the reasons why microbenchmarks sometimes showed
Groovy to be slow...
48
BigDecimal by default!

assert!2.0!c!1.1!==!0.9
assert!3!/!2!==!1.5
One of the reasons why microbenchmarks sometimes showed
Groovy to be slow...
48

But you can use doubles & floats
for performance, with ‘d’ or ‘f ’
suffixes or with explicit type
Powerful
switch / case
on steroids
Powerful
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]:!!!!!!!!!!!!"contained!in!list";!break
!!!!case!~/.*o+.*/:!!!!!!!!!!!!"match!the!regex";!!!break
!!!!case!{!it.isUpperCase()!}:!"closure!criteria";!!break
****default:!"unknown"
}
Named arguments

move!obj,!x:!3,!y:!4

50
Named arguments

move!obj,!x:!3,!y:!4
Normal argument

50
Named arguments

move!obj,!x:!3,!y:!4
Normal argument

50

Named argument
Named arguments

move!obj,!x:!3,!y:!4
Normal argument
Calls:
move(Map m, Object)

50

Named argument
Command chains
• Ability to chain method calls
without parentheses and dots

51
Command chains
• Ability to chain method calls
without parentheses and dots

move!forward!at!3.km/h

51
Command chains
• Ability to chain method calls
without parentheses and dots

move!forward!at!3.km/h
Actually equivalent to:
move(forward).at(3.getKm().div(h))

51
Named arguments and command chains

check!that:!vodka!tastes!good

52
Named arguments and command chains

check!that:!vodka!tastes!good
Will call:
check(that: vodka).tastes(good)

52
Multiple assignment and destructuring
def!(a,!b)!=!['A',!'B']
(a,!b)!=![b,!a]
def!(int!i,!int!j)!=![1,!2]
def!geocode(String!place)!{
!!!!return![45.4,!2.3]
}
def!(la,!lo)!=!geocode("Paris")
assert!la!==!45.4!&&!lo!==!2.3
53
Multiple assignment and destructuring
def!(a,!b)!=!['A',!'B']
(a,!b)!=![b,!a]

Classic « swap »

def!(int!i,!int!j)!=![1,!2]
def!geocode(String!place)!{
!!!!return![45.4,!2.3]
}
def!(la,!lo)!=!geocode("Paris")
assert!la!==!45.4!&&!lo!==!2.3
53
Multiple assignment and destructuring
def!(a,!b)!=!['A',!'B']

With types

(a,!b)!=![b,!a]

Classic « swap »

def!(int!i,!int!j)!=![1,!2]
def!geocode(String!place)!{
!!!!return![45.4,!2.3]
}
def!(la,!lo)!=!geocode("Paris")
assert!la!==!45.4!&&!lo!==!2.3
53
Multiple assignment and destructuring
def!(a,!b)!=!['A',!'B']

With types

(a,!b)!=![b,!a]

Classic « swap »

def!(int!i,!int!j)!=![1,!2]

Method
returning a list

def!geocode(String!place)!{
!!!!return![45.4,!2.3]
}
def!(la,!lo)!=!geocode("Paris")
assert!la!==!45.4!&&!lo!==!2.3

53
Multiple assignment and destructuring
def!(a,!b)!=!['A',!'B']

With types

(a,!b)!=![b,!a]

Classic « swap »

def!(int!i,!int!j)!=![1,!2]

Method
returning a list

def!geocode(String!place)!{
!!!!return![45.4,!2.3]
}
Destructuring
def!(la,!lo)!=!geocode("Paris")
assert!la!==!45.4!&&!lo!==!2.3

53
Multiple assignment and destructuring
class!Point!{
!!!!double!x,!y
!!!!double!getAt(int!idx)!{
!!!!!!!!if!(idx!==!0)!x
!!!!!!!!else!if!(idx!==!1)!y
!!!!!!!!else!throw!new!Exception("Wrong!index")
!!!!}
}
def!(x,!y)!=!new!Point(x:!48.3,!y:!3.5)
assert!x!==!48.3!&&!y!==!3.5
54
Multiple assignment and destructuring
class!Point!{
!!!!double!x,!y

Method signature
convention: getAt(int)

!!!!double!getAt(int!idx)!{
!!!!!!!!if!(idx!==!0)!x
!!!!!!!!else!if!(idx!==!1)!y
!!!!!!!!else!throw!new!Exception("Wrong!index")
!!!!}
}
def!(x,!y)!=!new!Point(x:!48.3,!y:!3.5)
assert!x!==!48.3!&&!y!==!3.5
54
Multiple assignment and destructuring
class!Point!{
!!!!double!x,!y

Method signature
convention: getAt(int)

!!!!double!getAt(int!idx)!{
!!!!!!!!if!(idx!==!0)!x
!!!!!!!!else!if!(idx!==!1)!y
!!!!!!!!else!throw!new!Exception("Wrong!index")
!!!!}
}
Transparent destructuring
def!(x,!y)!=!new!Point(x:!48.3,!y:!3.5)
assert!x!==!48.3!&&!y!==!3.5
54
Builders and GPath expressions
import!groovy.xml.*
new!MarkupBuilder().html!{
!!!!head!{
!!!!!!!!title!"The!Script!Bowl"
!!!!}
!!!!body!{
!!!!!!!!div(class:!"banner")!{
!!!!!!!!!!!!p!"Groovy!won!"
!!!!!!!!}
!!!!}
}
55
Builders and GPath expressions
import!groovy.xml.*

Hierarchical data
representation

new!MarkupBuilder().html!{
!!!!head!{
!!!!!!!!title!"The!Script!Bowl"
!!!!}
!!!!body!{
!!!!!!!!div(class:!"banner")!{
!!!!!!!!!!!!p!"Groovy!won!"
!!!!!!!!}
!!!!}
}
55
Builders and GPath expressions
import!groovy.xml.*

Hierarchical data
representation

new!MarkupBuilder().html!{
!!!!head!{
!!!!!!!!title!"The!Script!Bowl"
!!!!}
!!!!body!{
!!!!!!!!div(class:!"banner")!{
!!!!!!!!!!!!p!"Groovy!won!"
!!!!!!!!}
Closure blocks delimiting
!!!!}
the structure
}
55
Builders and GPath expressions
import!groovy.xml.*

Hierarchical data
representation

new!MarkupBuilder().html!{
!!!!head!{
!!!!!!!!title!"The!Script!Bowl"
!!!!}
Attributes
!!!!body!{
!!!!!!!!div(class:!"banner")!{
!!!!!!!!!!!!p!"Groovy!won!"
!!!!!!!!}
Closure blocks delimiting
!!!!}
the structure
}
55
Power asserts
def!(a,!b,!c)!=![20,!30,!40]
assert!a!*!(b!c!1)!/!10!==!3!*!c!/!2!+!1

56
Power asserts
def!(a,!b,!c)!=![20,!30,!40]
assert!a!*!(b!c!1)!/!10!==!3!*!c!/!2!+!1
Assertion!failed:!
assert!a!*!(b!c!1)!/!10!==!3!*!c!/!2!+!1
!!!!!!!|!|!!|!|!!!!|!!!!|!!!!|!|!|!!!|
!!!!!!!|!580|!29!!!58!!!false|!|!60!!61
!!!!!!!20!!!30!!!!!!!!!!!!!!!|!40
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!120
! at!script1.run(script1t.groovy:4)
56
Null handling
• Groovy provides a more descriptive
NullPointerException than Java
• Safe navigation with ?.

57
The Truth,
the Groovy Truth!
The Truth,
the Groovy Truth!
And what if I could
customize the truth?
?:
?:
The Elvis
operator!
Towards Elvis...

60
Towards Elvis...
def!(x,!y)!=!['MacBook!Pro',!'unknown']

60
Towards Elvis...
def!(x,!y)!=!['MacBook!Pro',!'unknown']
if*(x!!=!null!&&!x.size()!>!0)!x!else!y

60
Towards Elvis...
def!(x,!y)!=!['MacBook!Pro',!'unknown']
if*(x!!=!null!&&!x.size()!>!0)!x!else!y
if*(x!&&!x.size())!x!else!y

60
Towards Elvis...
def!(x,!y)!=!['MacBook!Pro',!'unknown']
if*(x!!=!null!&&!x.size()!>!0)!x!else!y
if*(x!&&!x.size())!x!else!y
if*(x)!x!else!y

60
Towards Elvis...
def!(x,!y)!=!['MacBook!Pro',!'unknown']
if*(x!!=!null!&&!x.size()!>!0)!x!else!y
if*(x!&&!x.size())!x!else!y
if*(x)!x!else!y
x!?!x!:!y

60
Towards Elvis...
def!(x,!y)!=!['MacBook!Pro',!'unknown']
if*(x!!=!null!&&!x.size()!>!0)!x!else!y
if*(x!&&!x.size())!x!else!y
if*(x)!x!else!y
x!?!x!:!y
x!?:!y

60
Towards Elvis...
def!(x,!y)!=!['MacBook!Pro',!'unknown']
if*(x!!=!null!&&!x.size()!>!0)!x!else!y
if*(x!&&!x.size())!x!else!y
if*(x)!x!else!y
x!?!x!:!y
x!?:!y

Null, empty, zerosized... false,
otherwise true!

60
Towards Elvis...
def!(x,!y)!=!['MacBook!Pro',!'unknown']
if*(x!!=!null!&&!x.size()!>!0)!x!else!y
if*(x!&&!x.size())!x!else!y
if*(x)!x!else!y
x!?!x!:!y
x!?:!y

Good old ternary
operator

60

Null, empty, zerosized... false,
otherwise true!
Towards Elvis...
def!(x,!y)!=!['MacBook!Pro',!'unknown']
if*(x!!=!null!&&!x.size()!>!0)!x!else!y
if*(x!&&!x.size())!x!else!y
if*(x)!x!else!y
x!?!x!:!y
x!?:!y

Elvis!

60

Good old ternary
operator

Null, empty, zerosized... false,
otherwise true!
AST transformations
• Abstract Syntax Tree
– in memory representation of your program
before being compiled into bytecode

• AST transformation == process of transforming
the AST of a program before it’s compiled
• Macro-like compiler hook!

61
Lots of AST transformations...
• Code generation
– @ToString, @EqualsAndHashCode, @Canonical,
@TupleConstructor, @InheritConstructors,
@Category, @IndexedProperty, @Lazy, @Newify

• Class design
– @Delegate, @Immutable, @Memoized,
@Singleton, @Mixin

• Logging
– @Log, @Log4j, @Log4j2, @Slf4j
62
Lots of AST transformations...
• Safer scripting
– @ConditionalInterrupt, @ThreadInterrupt,
@TimedInterupt

• Compiler directives
– @Field, @PackageScope, @AnnotationCollector,
@DelegatesTo, @TypeChecked,
@CompileStatic, @CompileDynamic

• Swing patterns
– @Bindable, @ListenerList, @Vetoable
63
Lots of AST transformations...
• Dependencies handling
– @Grab, @GrabConfig, @GrabExclude,
@GrabResolver

• Test assistance
– @NotYetImplemented, @ASTTest

64
Immutability
• Implement immutability
by the book
– final class
– tuple-style constructor
– private final backing fields
– defensive copying of collections
– equals() and hashCode() methods
– toString() method
– ...
65
Immutability
• Implement immutability
by the book
– final class
Can be error-prone to
– tuple-style constructor
write immutable
– private final backing fields
classes oneself!
– defensive copying of collections
– equals() and hashCode() methods
– toString() method
– ...
65
Immutability
• A Person class with

public final class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}

– a String name
– an int age

public String getName() {
return name;
}
public int getAge() {
return age;
}
public int hashCode() {
return age + 31 * name.hashCode();
}
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (this == other) {
return true;
}
if (Person.class != other.getClass()) {
return false;
}
Person otherPerson = (Person)other;
if (!name.equals(otherPerson.getName()) {
return false;
}
if (age != otherPerson.getAge()) {
return false;
}
return true;
}
public String toString() {
return "Person(" + name + ", " + age + ")";
}
}

66
Immutability
• A Person class with

Damn
verbose
Java!

public final class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}

– a String name
– an int age

public String getName() {
return name;
}
public int getAge() {
return age;
}
public int hashCode() {
return age + 31 * name.hashCode();
}
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (this == other) {
return true;
}
if (Person.class != other.getClass()) {
return false;
}
Person otherPerson = (Person)other;
if (!name.equals(otherPerson.getName()) {
return false;
}
if (age != otherPerson.getAge()) {
return false;
}
return true;
}
public String toString() {
return "Person(" + name + ", " + age + ")";
}
}

66
Immutability
• A Person class with

Damn
verbose
Java!

public final class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}

– a String name
– an int age

public String getName() {
return name;
}
public int getAge() {
return age;
}
public int hashCode() {
return age + 31 * name.hashCode();
}
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (this == other) {
return true;
}
if (Person.class != other.getClass()) {
return false;
}
Person otherPerson = (Person)other;
if (!name.equals(otherPerson.getName()) {
return false;
}
if (age != otherPerson.getAge()) {
return false;
}
return true;
}

Although it’s also a valid
Groovy program!

public String toString() {
return "Person(" + name + ", " + age + ")";
}
}

66
@Immutable

import!groovy.transform.*
@Immutable
class!Person!{
!!!!String!name
!!!!int!age
}
67
Memoization
• Cache the result of previous invocations
of closures or methods with the same set
of argument values
import!groovy.transform.*
@Memoized
long!fib(long!n)!{
!!!!if!(n!==!0)!0
!!!!else!if!(n!==!1)!1
!!!!else!fib(n!c!1)!+!fib(n!c!2)
}
println!fib(40)
68
Memoization
• Cache the result of previous invocations
of closures or methods with the same set
of argument values
import!groovy.transform.*

Best applied to
side-effect free
functions

@Memoized
long!fib(long!n)!{
!!!!if!(n!==!0)!0
!!!!else!if!(n!==!1)!1
!!!!else!fib(n!c!1)!+!fib(n!c!2)
}
println!fib(40)

68
Groovy allows you
to be lazy
Groovy allows you
to be lazy

The compiler will do
the job for you
Groovy allows you
to be lazy

More concise, more
readable code

The compiler will do
the job for you
Groovy allows you
to be lazy

More concise, more
readable code

The compiler will do
the job for you

Less stuff to maintain
and worry about
@TypeChecked and @CompileStatic
• Static type checking with @TypeChecked,
throws compilation errors on...
– typos in method and variable names
– incompatible return types
– wrong type assignments

• Supports fine-grained type inference
– « Least Upper Bound »
– « Flow typing »

70
@TypeChecked and @CompileStatic
• Static type checking with @TypeChecked,
throws compilation errors on...
– typos in method and variable names
– incompatible return types
You can even extend the
– wrong type assignments
static type checker!

• Supports fine-grained type inference
– « Least Upper Bound »
– « Flow typing »

70
@TypeChecked and @CompileStatic
• Static type checking with @TypeChecked,
throws compilation errors on...
– typos in method and variable names
– incompatible return types
You can even extend the
– wrong type assignments
static type checker!

• Supports fine-grained type inference
– « Least Upper Bound »
– « Flow typing »

70

Type check DSLs or
dynamic features!
@TypeChecked and @CompileStatic
• What is type checked can also be compiled
statically with @CompileStatic
– generate the same bytecode as javac
– same performance as Java

71
Pi (π)
Fibonacci
quadrature
Java

191 ms

97 ms

3.6 s

2.x

Static
compilation

197 ms

101 ms

4.3 s

1.8
72

Binary
trees

Primitive
optimizations

360 ms

111 ms

23.7 s

1.7

Static compilation performance

No prim.
optimizations

2590 ms 3220 ms

50.0 s
3
t
r
a
P

Superb
community!
A blossoming
Ecosystem
M
V
G
GVM
GVM
GROOVY
ENVIRONMENT

MANAGER
GVM: Groovy enVironment Manager
• The new kid on the block
– http://gvmtool.net/ — @gvmtool

• Manage parallel versions
of the various ecosystem projects
• Supports...
– Groovy, Grails, Griffon, Gradle,Vert.x, Spring Boot

• On Linux, MacOS, Cygwin, Solaris, FreeBSD
81
I’m Spock...
I’m Spock...
...the Spock testing
framework
I’m Spock...
...the Spock testing
framework
Spock example
@Grab('org.spockframework:spockccore:0.7cgroovyc2.0')
import!spock.lang.*
class!MathSpec!extends!Specification!{
!!!!def!"maximum!of!two!numbers"()!{
******expect:
!!!!!!!!Math.max(a,!b)!==!c
******where:
!!!!!!!!a!|!b!||!c
!!!!!!!!1!|!3!||!3
!!!!!!!!7!|!4!||!4
!!!!!!!!0!|!0!||!0
!!!!}
}
83
Spock example

@Grab a dependency

@Grab('org.spockframework:spockccore:0.7cgroovyc2.0')
import!spock.lang.*
class!MathSpec!extends!Specification!{
!!!!def!"maximum!of!two!numbers"()!{
******expect:
!!!!!!!!Math.max(a,!b)!==!c
******where:
!!!!!!!!a!|!b!||!c
!!!!!!!!1!|!3!||!3
!!!!!!!!7!|!4!||!4
!!!!!!!!0!|!0!||!0
!!!!}
}
83
Spock example

@Grab a dependency

@Grab('org.spockframework:spockccore:0.7cgroovyc2.0')
import!spock.lang.*
class!MathSpec!extends!Specification!{
!!!!def!"maximum!of!two!numbers"()!{
******expect:
!!!!!!!!Math.max(a,!b)!==!c
******where:
!!!!!!!!a!|!b!||!c
!!!!!!!!1!|!3!||!3
!!!!!!!!7!|!4!||!4
!!!!!!!!0!|!0!||!0
!!!!}
}
83

Meaningful test
method names
Spock example

@Grab a dependency

@Grab('org.spockframework:spockccore:0.7cgroovyc2.0')
import!spock.lang.*

Meaningful test
method names

class!MathSpec!extends!Specification!{
!!!!def!"maximum!of!two!numbers"()!{
******expect:
!!!!!!!!Math.max(a,!b)!==!c
Clever use of labels
******where:
!!!!!!!!a!|!b!||!c
!!!!!!!!1!|!3!||!3
!!!!!!!!7!|!4!||!4
!!!!!!!!0!|!0!||!0
!!!!}
}
83

for BDD style
Spock example

@Grab a dependency

@Grab('org.spockframework:spockccore:0.7cgroovyc2.0')
import!spock.lang.*

Meaningful test
method names

class!MathSpec!extends!Specification!{
!!!!def!"maximum!of!two!numbers"()!{
******expect:
!!!!!!!!Math.max(a,!b)!==!c
Clever use of labels
******where:
!!!!!!!!a!|!b!||!c
!!!!!!!!1!|!3!||!3
!!!!!!!!7!|!4!||!4
!!!!!!!!0!|!0!||!0
!!!!}
}
83

for BDD style
Expression to
be asserted
Spock example

@Grab a dependency

@Grab('org.spockframework:spockccore:0.7cgroovyc2.0')
import!spock.lang.*

Meaningful test
method names

class!MathSpec!extends!Specification!{
!!!!def!"maximum!of!two!numbers"()!{
******expect:
!!!!!!!!Math.max(a,!b)!==!c
Clever use of labels
******where:
!!!!!!!!a!|!b!||!c
!!!!!!!!1!|!3!||!3
!!!!!!!!7!|!4!||!4
!!!!!!!!0!|!0!||!0
!!!!}
}
83

for BDD style
Cute datadriven tests!

Expression to
be asserted
@GrabResolver("https://oss.jfrog.org/artifactory/repo")
@Grab("org.ratpackcframework:ratpackcgroovy:0.9.0cSNAPSHOT")
import!static!org.ratpackframework.groovy.RatpackScript.ratpack
import!static!org.ratpackframework.groovy.Template.groovyTemplate
ratpack!{
!!!!handlers!{
!!!!!!!!get!{
!!!!!!!!!!!!response.send!"Welcome!"
!!!!!!!!}
!!!!!!!!get("date")!{
!!!!!!!!!!!!render!groovyTemplate("date.html")
!!!!!!!!}
!!!!!!!!assets!"public"
!!!!}
}
@GrabResolver("https://oss.jfrog.org/artifactory/repo")
@Grab("org.ratpackcframework:ratpackcgroovy:0.9.0cSNAPSHOT")
import!static!org.ratpackframework.groovy.RatpackScript.ratpack
import!static!org.ratpackframework.groovy.Template.groovyTemplate
ratpack!{
!!!!handlers!{
!!!!!!!!get!{
!!!!!!!!!!!!response.send!"Welcome!"
!!!!!!!!}

Lightweight Netty-based
web app toolkit

!!!!!!!!get("date")!{
!!!!!!!!!!!!render!groovyTemplate("date.html")
!!!!!!!!}
!!!!!!!!assets!"public"
!!!!}
}
Geb
• Browser automation solution
• WebDriver + jQuery selectors + Groovy
• Handy for
– scripting, scraping, automation...
– functional / web / acceptance testing
• when integrated with JUnit, TestNG or Spock

85
Geb — Example
import!geb.Browser
Browser.drive!{
!!!!go!"http://myapp.com/login"
!!!!assert!$("h1").text()!==!"Please!Login"
!!!!$("form.login").with!{
!!!!!!!!username!=!"admin"
!!!!!!!!password!=!"password"
!!!!!!!!login().click()
!!!!}
!!!!assert!$("h1").text()!==!
!!!!!!!!"Admin!Section"
}

86
Geb — Example

Drive the browser
to this site

import!geb.Browser
Browser.drive!{
!!!!go!"http://myapp.com/login"
!!!!assert!$("h1").text()!==!"Please!Login"
!!!!$("form.login").with!{
!!!!!!!!username!=!"admin"
!!!!!!!!password!=!"password"
!!!!!!!!login().click()
!!!!}
!!!!assert!$("h1").text()!==!
!!!!!!!!"Admin!Section"
}

86
Geb — Example

Drive the browser
to this site

import!geb.Browser
Browser.drive!{
!!!!go!"http://myapp.com/login"

Check the content
of the title

!!!!assert!$("h1").text()!==!"Please!Login"
!!!!$("form.login").with!{
!!!!!!!!username!=!"admin"
!!!!!!!!password!=!"password"
!!!!!!!!login().click()
!!!!}
!!!!assert!$("h1").text()!==!
!!!!!!!!"Admin!Section"
}

86
Geb — Example

Drive the browser
to this site

import!geb.Browser
Browser.drive!{
!!!!go!"http://myapp.com/login"

Check the content
of the title

!!!!assert!$("h1").text()!==!"Please!Login"
!!!!$("form.login").with!{
!!!!!!!!username!=!"admin"
!!!!!!!!password!=!"password"
!!!!!!!!login().click()
!!!!}
!!!!assert!$("h1").text()!==!
!!!!!!!!"Admin!Section"
}

86

Find & fill in
the form
Geb — Example

Drive the browser
to this site

import!geb.Browser
Browser.drive!{
!!!!go!"http://myapp.com/login"

Check the content
of the title

!!!!assert!$("h1").text()!==!"Please!Login"
!!!!$("form.login").with!{
!!!!!!!!username!=!"admin"
!!!!!!!!password!=!"password"
!!!!!!!!login().click()
!!!!}
!!!!assert!$("h1").text()!==!
!!!!!!!!"Admin!Section"
}

86

Find & fill in
the form
Submit the
form
Geb — Example

Drive the browser
to this site

import!geb.Browser
Browser.drive!{
!!!!go!"http://myapp.com/login"

Check the content
of the title

!!!!assert!$("h1").text()!==!"Please!Login"
!!!!$("form.login").with!{
!!!!!!!!username!=!"admin"
!!!!!!!!password!=!"password"
!!!!!!!!login().click()
!!!!}
!!!!assert!$("h1").text()!==!
!!!!!!!!"Admin!Section"
}

Find & fill in
the form
Submit the
form

In the admin section, yeah!
86
Geb — With page objects and Spock
import!geb.spock.GebSpec
class!GoogleWikipediaSpec!extends!GebSpec!{
!!!!def!"first!result!for!wikipedia!search!should!be!wikipedia"()!{
********given:
!!!!!!!!to!GoogleHomePage
********expect:
!!!!!!!!at!GoogleHomePage
********when:
!!!!!!!!search.field.value("wikipedia")
********then:
!!!!!!!!waitFor!{!at!GoogleResultsPage!}
********and:
!!!!!!!!firstResultLink.text()!==!"Wikipedia"
********when:
!!!!!!!!firstResultLink.click()
********then:
!!!!!!!!waitFor!{!at!WikipediaPage!}
!!!!}
}

87
Geb — With page objects and Spock
import!geb.spock.GebSpec
class!GoogleWikipediaSpec!extends!GebSpec!{

With page objects
!!!!def!"first!result!for!wikipedia!search!should!be!wikipedia"()!{
********given:
!!!!!!!!to!GoogleHomePage
********expect:
!!!!!!!!at!GoogleHomePage
********when:
!!!!!!!!search.field.value("wikipedia")
********then:
!!!!!!!!waitFor!{!at!GoogleResultsPage!}
********and:
!!!!!!!!firstResultLink.text()!==!"Wikipedia"
********when:
!!!!!!!!firstResultLink.click()
********then:
!!!!!!!!waitFor!{!at!WikipediaPage!}
!!!!}
}

87
Geb — With page objects and Spock
import!geb.spock.GebSpec
class!GoogleWikipediaSpec!extends!GebSpec!{

With page objects
!!!!def!"first!result!for!wikipedia!search!should!be!wikipedia"()!{
********given:
!!!!!!!!to!GoogleHomePage
********expect:
!!!!!!!!at!GoogleHomePage

BDD style: given/when/then

********when:
!!!!!!!!search.field.value("wikipedia")
********then:
!!!!!!!!waitFor!{!at!GoogleResultsPage!}
********and:
!!!!!!!!firstResultLink.text()!==!"Wikipedia"
********when:
!!!!!!!!firstResultLink.click()
********then:
!!!!!!!!waitFor!{!at!WikipediaPage!}
!!!!}
}

87
Geb — With page objects and Spock
import!geb.spock.GebSpec
class!GoogleWikipediaSpec!extends!GebSpec!{

With page objects
!!!!def!"first!result!for!wikipedia!search!should!be!wikipedia"()!{
********given:
!!!!!!!!to!GoogleHomePage
********expect:
!!!!!!!!at!GoogleHomePage
********when:
!!!!!!!!search.field.value("wikipedia")

BDD style: given/when/then
Wait for slow loading pages

********then:
!!!!!!!!waitFor!{!at!GoogleResultsPage!}
********and:
!!!!!!!!firstResultLink.text()!==!"Wikipedia"
********when:
!!!!!!!!firstResultLink.click()
********then:
!!!!!!!!waitFor!{!at!WikipediaPage!}
!!!!}
}

87
4
t
r
a
P

Summary
Java’s best friend
• Java derived syntax
– Flat learning curve
– Easy to learn

• But goes beyond Java
– Concise, expressive, readable
– Fit for Domain-Specific Languages

• Seamless & transparent Java integration
– Mix and match Groovy and Java classes (joint compil.)
– No language barrier to cross
89
Groovy’s nature
• Object oriented dynamic language...
• But...
– as type safe as you want it — static type checking
– as fast as you need it — static compilation
– as functional as you make it — closures...

90
Groovy use cases
• Scripting tasks, build automation
• Extension points for customizing/configuring apps
• Business languages & Domain-Specific Languages
• Full blown apps
– for desktop with Griffon
– for the web with Grails, Ratpack, Gaelyk
– for web reactive programming with reactor
91

Contenu connexe

En vedette

Soirée Ceylon avec Stéphane Epardaud
Soirée Ceylon avec Stéphane EpardaudSoirée Ceylon avec Stéphane Epardaud
Soirée Ceylon avec Stéphane EpardaudNormandy JUG
 
Gatling : Faites tomber la foudre sur votre serveur ! (Stéphane Landelle)
Gatling : Faites tomber la foudre sur votre serveur ! (Stéphane Landelle)Gatling : Faites tomber la foudre sur votre serveur ! (Stéphane Landelle)
Gatling : Faites tomber la foudre sur votre serveur ! (Stéphane Landelle)Normandy JUG
 
[Codeurs en seine] management & monitoring cloud
[Codeurs en seine] management & monitoring cloud[Codeurs en seine] management & monitoring cloud
[Codeurs en seine] management & monitoring cloudNormandy JUG
 
Découvrez les bases de l’ergonomie web : donnez à vos utilisateurs le meilleu...
Découvrez les bases de l’ergonomie web : donnez à vos utilisateurs le meilleu...Découvrez les bases de l’ergonomie web : donnez à vos utilisateurs le meilleu...
Découvrez les bases de l’ergonomie web : donnez à vos utilisateurs le meilleu...Normandy JUG
 
Codeurs En Seine - Lean startup - Matthieu Garde-Lebreton
Codeurs En Seine - Lean startup - Matthieu Garde-LebretonCodeurs En Seine - Lean startup - Matthieu Garde-Lebreton
Codeurs En Seine - Lean startup - Matthieu Garde-LebretonNormandy JUG
 
Capacity Planning : Pratiques et outils pour regarder la foudre tomber sans p...
Capacity Planning : Pratiques et outils pour regarder la foudre tomber sans p...Capacity Planning : Pratiques et outils pour regarder la foudre tomber sans p...
Capacity Planning : Pratiques et outils pour regarder la foudre tomber sans p...Normandy JUG
 
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...Normandy JUG
 

En vedette (8)

Soirée Ceylon avec Stéphane Epardaud
Soirée Ceylon avec Stéphane EpardaudSoirée Ceylon avec Stéphane Epardaud
Soirée Ceylon avec Stéphane Epardaud
 
Gatling : Faites tomber la foudre sur votre serveur ! (Stéphane Landelle)
Gatling : Faites tomber la foudre sur votre serveur ! (Stéphane Landelle)Gatling : Faites tomber la foudre sur votre serveur ! (Stéphane Landelle)
Gatling : Faites tomber la foudre sur votre serveur ! (Stéphane Landelle)
 
HTML5 en projet
HTML5 en projetHTML5 en projet
HTML5 en projet
 
[Codeurs en seine] management & monitoring cloud
[Codeurs en seine] management & monitoring cloud[Codeurs en seine] management & monitoring cloud
[Codeurs en seine] management & monitoring cloud
 
Découvrez les bases de l’ergonomie web : donnez à vos utilisateurs le meilleu...
Découvrez les bases de l’ergonomie web : donnez à vos utilisateurs le meilleu...Découvrez les bases de l’ergonomie web : donnez à vos utilisateurs le meilleu...
Découvrez les bases de l’ergonomie web : donnez à vos utilisateurs le meilleu...
 
Codeurs En Seine - Lean startup - Matthieu Garde-Lebreton
Codeurs En Seine - Lean startup - Matthieu Garde-LebretonCodeurs En Seine - Lean startup - Matthieu Garde-Lebreton
Codeurs En Seine - Lean startup - Matthieu Garde-Lebreton
 
Capacity Planning : Pratiques et outils pour regarder la foudre tomber sans p...
Capacity Planning : Pratiques et outils pour regarder la foudre tomber sans p...Capacity Planning : Pratiques et outils pour regarder la foudre tomber sans p...
Capacity Planning : Pratiques et outils pour regarder la foudre tomber sans p...
 
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
Fork / Join, Parallel Arrays, Lambdas : la programmation parallèle (trop ?) f...
 

Similaire à What makes Groovy groovy? Key features of the Groovy programming language

Desert Code Camp 2014: C#, the best programming language
Desert Code Camp 2014: C#, the best programming languageDesert Code Camp 2014: C#, the best programming language
Desert Code Camp 2014: C#, the best programming languageJames Montemagno
 
JavaCro 2016 - From Java to Groovy: Adventure Time!
JavaCro 2016 - From Java to Groovy: Adventure Time!JavaCro 2016 - From Java to Groovy: Adventure Time!
JavaCro 2016 - From Java to Groovy: Adventure Time!Iván López Martín
 
Gr8Conf US 2017 - From Java to Groovy: Adventure Time!
Gr8Conf US 2017 - From Java to Groovy: Adventure Time!Gr8Conf US 2017 - From Java to Groovy: Adventure Time!
Gr8Conf US 2017 - From Java to Groovy: Adventure Time!Iván López Martín
 
Spring, CDI, Jakarta EE good parts
Spring, CDI, Jakarta EE good partsSpring, CDI, Jakarta EE good parts
Spring, CDI, Jakarta EE good partsJarek Ratajski
 
Go language presentation
Go language presentationGo language presentation
Go language presentationparamisoft
 
Why don't you Groovy?
Why don't you Groovy?Why don't you Groovy?
Why don't you Groovy?Orest Ivasiv
 
Groovy best pratices at EWAY
Groovy best pratices at EWAYGroovy best pratices at EWAY
Groovy best pratices at EWAYĐào Hiệp
 
An Introduction to Groovy for Java Developers
An Introduction to Groovy for Java DevelopersAn Introduction to Groovy for Java Developers
An Introduction to Groovy for Java DevelopersKostas Saidis
 
Groovy And Grails Introduction
Groovy And Grails IntroductionGroovy And Grails Introduction
Groovy And Grails IntroductionEric Weimer
 
Groovy AST Demyistified - 33degree
Groovy AST Demyistified - 33degreeGroovy AST Demyistified - 33degree
Groovy AST Demyistified - 33degreeAndres Almiray
 
Machine vision and device integration with the Ruby programming language (2008)
Machine vision and device integration with the Ruby programming language (2008)Machine vision and device integration with the Ruby programming language (2008)
Machine vision and device integration with the Ruby programming language (2008)Jan Wedekind
 
New adventures in 3D
New adventures in 3DNew adventures in 3D
New adventures in 3DRob Bateman
 
Groovy Up Your Code
Groovy Up Your CodeGroovy Up Your Code
Groovy Up Your CodePaulo Traça
 
Дмитрий Щадей "Что помогает нам писать качественный JavaScript-код?"
Дмитрий Щадей "Что помогает нам писать качественный JavaScript-код?"Дмитрий Щадей "Что помогает нам писать качественный JavaScript-код?"
Дмитрий Щадей "Что помогает нам писать качественный JavaScript-код?"Yandex
 
Fast Web Applications with Go
Fast Web Applications with Go Fast Web Applications with Go
Fast Web Applications with Go Eylem Ozekin
 
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume LaforgeGroovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume LaforgeGuillaume Laforge
 
Imola informatica - cloud computing and software development
Imola informatica - cloud computing and software developmentImola informatica - cloud computing and software development
Imola informatica - cloud computing and software developmentFilippo Bosi
 

Similaire à What makes Groovy groovy? Key features of the Groovy programming language (20)

Desert Code Camp 2014: C#, the best programming language
Desert Code Camp 2014: C#, the best programming languageDesert Code Camp 2014: C#, the best programming language
Desert Code Camp 2014: C#, the best programming language
 
JavaCro 2016 - From Java to Groovy: Adventure Time!
JavaCro 2016 - From Java to Groovy: Adventure Time!JavaCro 2016 - From Java to Groovy: Adventure Time!
JavaCro 2016 - From Java to Groovy: Adventure Time!
 
Gr8Conf US 2017 - From Java to Groovy: Adventure Time!
Gr8Conf US 2017 - From Java to Groovy: Adventure Time!Gr8Conf US 2017 - From Java to Groovy: Adventure Time!
Gr8Conf US 2017 - From Java to Groovy: Adventure Time!
 
Spring, CDI, Jakarta EE good parts
Spring, CDI, Jakarta EE good partsSpring, CDI, Jakarta EE good parts
Spring, CDI, Jakarta EE good parts
 
Go language presentation
Go language presentationGo language presentation
Go language presentation
 
Why don't you Groovy?
Why don't you Groovy?Why don't you Groovy?
Why don't you Groovy?
 
Groovy And Grails
Groovy And GrailsGroovy And Grails
Groovy And Grails
 
Groovy best pratices at EWAY
Groovy best pratices at EWAYGroovy best pratices at EWAY
Groovy best pratices at EWAY
 
An Introduction to Groovy for Java Developers
An Introduction to Groovy for Java DevelopersAn Introduction to Groovy for Java Developers
An Introduction to Groovy for Java Developers
 
Groovy And Grails Introduction
Groovy And Grails IntroductionGroovy And Grails Introduction
Groovy And Grails Introduction
 
Groovy AST Demyistified - 33degree
Groovy AST Demyistified - 33degreeGroovy AST Demyistified - 33degree
Groovy AST Demyistified - 33degree
 
Plataforma java
Plataforma javaPlataforma java
Plataforma java
 
Machine vision and device integration with the Ruby programming language (2008)
Machine vision and device integration with the Ruby programming language (2008)Machine vision and device integration with the Ruby programming language (2008)
Machine vision and device integration with the Ruby programming language (2008)
 
New adventures in 3D
New adventures in 3DNew adventures in 3D
New adventures in 3D
 
Groovy Up Your Code
Groovy Up Your CodeGroovy Up Your Code
Groovy Up Your Code
 
Дмитрий Щадей "Что помогает нам писать качественный JavaScript-код?"
Дмитрий Щадей "Что помогает нам писать качественный JavaScript-код?"Дмитрий Щадей "Что помогает нам писать качественный JavaScript-код?"
Дмитрий Щадей "Что помогает нам писать качественный JavaScript-код?"
 
Clojure at ardoq
Clojure at ardoqClojure at ardoq
Clojure at ardoq
 
Fast Web Applications with Go
Fast Web Applications with Go Fast Web Applications with Go
Fast Web Applications with Go
 
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume LaforgeGroovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
 
Imola informatica - cloud computing and software development
Imola informatica - cloud computing and software developmentImola informatica - cloud computing and software development
Imola informatica - cloud computing and software development
 

Plus de Normandy JUG

Soirée Guava et Lombok avec Thierry Leriche
Soirée Guava et Lombok avec Thierry LericheSoirée Guava et Lombok avec Thierry Leriche
Soirée Guava et Lombok avec Thierry LericheNormandy JUG
 
Couche Base par Tugdual Grall
Couche Base par Tugdual GrallCouche Base par Tugdual Grall
Couche Base par Tugdual GrallNormandy JUG
 
Apache, osgi and karaf par Guillaume Nodet
Apache, osgi and karaf par Guillaume NodetApache, osgi and karaf par Guillaume Nodet
Apache, osgi and karaf par Guillaume NodetNormandy JUG
 
Mockito - Design + tests par Brice Duteil
Mockito - Design + tests par Brice DuteilMockito - Design + tests par Brice Duteil
Mockito - Design + tests par Brice DuteilNormandy JUG
 
Annotations Java par Olivier Croisier
Annotations Java par Olivier CroisierAnnotations Java par Olivier Croisier
Annotations Java par Olivier CroisierNormandy JUG
 
Spring Batch 17-05-2011
Spring Batch 17-05-2011Spring Batch 17-05-2011
Spring Batch 17-05-2011Normandy JUG
 
ATR2011 - Planning poker
ATR2011 - Planning pokerATR2011 - Planning poker
ATR2011 - Planning pokerNormandy JUG
 
ATR2011 - Scrum dans les tranchées Normandes
ATR2011 - Scrum dans les tranchées NormandesATR2011 - Scrum dans les tranchées Normandes
ATR2011 - Scrum dans les tranchées NormandesNormandy JUG
 
Hibernate vs le_cloud_computing
Hibernate vs le_cloud_computingHibernate vs le_cloud_computing
Hibernate vs le_cloud_computingNormandy JUG
 
Soirée BPM - Introduction Logica
Soirée BPM - Introduction LogicaSoirée BPM - Introduction Logica
Soirée BPM - Introduction LogicaNormandy JUG
 
Soirée BPM - Bonita Soft
Soirée BPM - Bonita SoftSoirée BPM - Bonita Soft
Soirée BPM - Bonita SoftNormandy JUG
 
AT2010 Keynote de cloture
AT2010 Keynote de clotureAT2010 Keynote de cloture
AT2010 Keynote de clotureNormandy JUG
 
AT2010 Kanban au secours des équipes sysadmin et support
AT2010 Kanban au secours des équipes sysadmin et supportAT2010 Kanban au secours des équipes sysadmin et support
AT2010 Kanban au secours des équipes sysadmin et supportNormandy JUG
 
AT2010 Introduction à scrum
AT2010 Introduction à scrumAT2010 Introduction à scrum
AT2010 Introduction à scrumNormandy JUG
 
AT2010 Principes Integration Continue
AT2010 Principes Integration ContinueAT2010 Principes Integration Continue
AT2010 Principes Integration ContinueNormandy JUG
 
AT2010 Optimisez le retour sur investissement de votre produit avec une bonne...
AT2010 Optimisez le retour sur investissement de votre produit avec une bonne...AT2010 Optimisez le retour sur investissement de votre produit avec une bonne...
AT2010 Optimisez le retour sur investissement de votre produit avec une bonne...Normandy JUG
 

Plus de Normandy JUG (20)

Soirée Guava et Lombok avec Thierry Leriche
Soirée Guava et Lombok avec Thierry LericheSoirée Guava et Lombok avec Thierry Leriche
Soirée Guava et Lombok avec Thierry Leriche
 
Couche Base par Tugdual Grall
Couche Base par Tugdual GrallCouche Base par Tugdual Grall
Couche Base par Tugdual Grall
 
Java7 normandyjug
Java7 normandyjugJava7 normandyjug
Java7 normandyjug
 
Apache, osgi and karaf par Guillaume Nodet
Apache, osgi and karaf par Guillaume NodetApache, osgi and karaf par Guillaume Nodet
Apache, osgi and karaf par Guillaume Nodet
 
Mockito - Design + tests par Brice Duteil
Mockito - Design + tests par Brice DuteilMockito - Design + tests par Brice Duteil
Mockito - Design + tests par Brice Duteil
 
Annotations Java par Olivier Croisier
Annotations Java par Olivier CroisierAnnotations Java par Olivier Croisier
Annotations Java par Olivier Croisier
 
Spring Batch 17-05-2011
Spring Batch 17-05-2011Spring Batch 17-05-2011
Spring Batch 17-05-2011
 
ATR2011 - Planning poker
ATR2011 - Planning pokerATR2011 - Planning poker
ATR2011 - Planning poker
 
ATR2011 - Scrum dans les tranchées Normandes
ATR2011 - Scrum dans les tranchées NormandesATR2011 - Scrum dans les tranchées Normandes
ATR2011 - Scrum dans les tranchées Normandes
 
Hibernate vs le_cloud_computing
Hibernate vs le_cloud_computingHibernate vs le_cloud_computing
Hibernate vs le_cloud_computing
 
Git
GitGit
Git
 
Soirée BPM - Introduction Logica
Soirée BPM - Introduction LogicaSoirée BPM - Introduction Logica
Soirée BPM - Introduction Logica
 
Soirée BPM - Bonita Soft
Soirée BPM - Bonita SoftSoirée BPM - Bonita Soft
Soirée BPM - Bonita Soft
 
AT2010 Keynote de cloture
AT2010 Keynote de clotureAT2010 Keynote de cloture
AT2010 Keynote de cloture
 
AT2010 Kanban au secours des équipes sysadmin et support
AT2010 Kanban au secours des équipes sysadmin et supportAT2010 Kanban au secours des équipes sysadmin et support
AT2010 Kanban au secours des équipes sysadmin et support
 
AT2010 Introduction à scrum
AT2010 Introduction à scrumAT2010 Introduction à scrum
AT2010 Introduction à scrum
 
AT2010 Dojo TDD
AT2010 Dojo TDDAT2010 Dojo TDD
AT2010 Dojo TDD
 
AT2010 Keynote
AT2010 KeynoteAT2010 Keynote
AT2010 Keynote
 
AT2010 Principes Integration Continue
AT2010 Principes Integration ContinueAT2010 Principes Integration Continue
AT2010 Principes Integration Continue
 
AT2010 Optimisez le retour sur investissement de votre produit avec une bonne...
AT2010 Optimisez le retour sur investissement de votre produit avec une bonne...AT2010 Optimisez le retour sur investissement de votre produit avec une bonne...
AT2010 Optimisez le retour sur investissement de votre produit avec une bonne...
 

Dernier

Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Nikki Chapple
 
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical InfrastructureVarsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructureitnewsafrica
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...itnewsafrica
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...itnewsafrica
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Kaya Weers
 
QCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesQCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesBernd Ruecker
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observabilityitnewsafrica
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integrationmarketing932765
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 

Dernier (20)

Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
 
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical InfrastructureVarsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
 
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...Zeshan Sattar- Assessing the skill requirements and industry expectations for...
Zeshan Sattar- Assessing the skill requirements and industry expectations for...
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)
 
QCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesQCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architectures
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 

What makes Groovy groovy? Key features of the Groovy programming language