Groovy Grails DevJam Jam Session

228
Groovy/Grails DevJam

description

Groovy is a dynamic programming language that runs on the JVM and seamlessly interacts with Java. Grails melds the concept of "Convention over Configuration" and the dynamic power of Groovy to create a framework that greatly simplifies the development of web based applications. This slideshow explores the two - dive into some Groovy vs. Java code examples and see some examples of Grails. We'll also discuss when to introduce either into an existing (or greenfield) environment and where they have worked and where they have failed

Transcript of Groovy Grails DevJam Jam Session

Page 1: Groovy Grails DevJam Jam Session

Groovy/Grails DevJam

Page 2: Groovy Grails DevJam Jam Session
Page 3: Groovy Grails DevJam Jam Session

Act I

Page 4: Groovy Grails DevJam Jam Session

“When you program in Groovy, in many waysyou’re writing a special kind of Java.”

-Dierk KönigGroovy in Action

Page 5: Groovy Grails DevJam Jam Session

.java .groovy

Page 6: Groovy Grails DevJam Jam Session
Page 7: Groovy Grails DevJam Jam Session

hugobook:groovy mjhugo$ groovycusage: groovyc [options] <source-files>

options:

--encoding <encoding> Specify the encoding of the user class files.

-F <flag>

-J <property=value>

-d Specify where to place generated class files.

-e,--exception Print stack trace on error.

-h,--help Print a synopsis of standard options.

-j,--jointCompilation Attach javac compiler to compile .java files. -v,--version Print the version.

Page 8: Groovy Grails DevJam Jam Session
Page 9: Groovy Grails DevJam Jam Session

20%

80%

Page 10: Groovy Grails DevJam Jam Session

getters and setters

Page 11: Groovy Grails DevJam Jam Session

1 package com.piragua.java;

2

3 public class SimpleBook {

4 private String title;

5 private String authorName;

6

7 public String getTitle() {

8 return title;

9 }

10

11 public void setTitle(String title) {

12 this.title = title;

13 }

14

15 public String getAuthorName() {

16 return authorName;

17 }

18

19 public void setAuthorName(String authorName) {

20 this.authorName = authorName;

21 }

22 }

Page 12: Groovy Grails DevJam Jam Session

1 package com.piragua.groovy

2

3 class SimpleBook {

4 String title

5 String authorName

6 }

Page 13: Groovy Grails DevJam Jam Session

javap -private SimpleBook

Compiled from "SimpleBook.groovy"

public class com.piragua.groovy.SimpleBook ... {

private java.lang.String title;

private java.lang.String author;

public java.lang.String getTitle(); public void setTitle(java.lang.String);

public java.lang.String getAuthor(); public void setAuthor(java.lang.String);

...

}

Page 14: Groovy Grails DevJam Jam Session

javap -private SimpleBook

Compiled from "SimpleBook.groovy"

public class com.piragua.groovy.SimpleBook ... {

private java.lang.String title; private java.lang.String author;

public java.lang.String getTitle(); public void setTitle(java.lang.String);

public java.lang.String getAuthor(); public void setAuthor(java.lang.String);

...

}

Page 15: Groovy Grails DevJam Jam Session

1 package com.piragua.java;

2

3 import java.util.Date;

4 import java.util.List;

5

6 public class Book {

7 private String title;

8 private String authorName;

9 private Integer numberOfPages;

10 private String subTitle;

11 private List<Chapter> chapters;

12 private Date publishDate;

13 private String publisher;

14

15 public String getPublisher() {

16 return publisher;

17 }

18

19 public void setPublisher(String publisher) {

20 this.publisher = publisher;

21 }

22

23 public Date getPublishDate() {

24 return publishDate;

25 }

26

27 public void setPublishDate(Date publishDate) {

28 this.publishDate = publishDate;

29 }

30

31 public List getChapters() {

32 return chapters;

33 }

34

35 public void setChapters(List chapters) {

36 this.chapters = chapters;

37 }

38

39 public String getTitle() {

40 return title;

41 }

42

43 public void setTitle(String title) {

44 this.title = title;

45 }

46

47 public String getAuthorName() {

48 return authorName;

49 }

50

51 public void setAuthorName(String authorName) {

52 this.authorName = authorName;

53 }

54

55 public Integer getNumberOfPages() {

56 return numberOfPages;

57 }

58

59 public void setNumberOfPages(Integer numberOfPages) {

60 this.numberOfPages = numberOfPages;

61 }

62

63 public String getSubTitle() {

64 return subTitle;

65 }

66

67 public void setSubTitle(String subTitle) {

68 this.subTitle = subTitle;

69 }

70

71 public String toString() {

72 String upperCaseTitle = null;

73 if (title != null) {

74 upperCaseTitle = title.toUpperCase();

75 }

76 return upperCaseTitle;

77 }

78

79 public String displayString() {

80 return "<u>" + title + "</u> by " + authorName + ", (" + numberOfPages + " pages)";

81 }

82

83 public Chapter findChapterByTitle(String chapterTitle) {

84 Chapter foundChapter = null;

85

86 if (chapterTitle != null && chapters != null) {

87 for (int i = 0; i < chapters.size(); i++) {

88 if (chapters.get(i) != null &&

89 chapterTitle.equals(chapters.get(i).getTitle())) {

90 foundChapter = chapters.get(i);

91 break;

92 }

93 }

94 }

95 return foundChapter;

96 }

97 }

1 package com.piragua.groovy

2

3 class Book {

4 String title

5 String authorName

6 Integer numberOfPages

7 String subTitle

8 List chapters

9 Date publishDate

10 String publisher

11

12 String toString() {

13 title?.toUpperCase()

14 }

15

16 String displayString() {

17 "<u>${title}</u> by ${authorName}, (${numberOfPages} pages)"

18 }

19

20 Chapter findChapterByTitle(String title) {

21 // finding the first item that matches criteria

22 chapters?.find({it?.title == title})

23 }

24 }

Page 16: Groovy Grails DevJam Jam Session

constructor convenience

http://flickr.com/photos/9229859@N02/1052409181/

Page 17: Groovy Grails DevJam Jam Session

1 package com.piragua.java;

2

3 import junit.framework.TestCase;

4

5 import java.util.ArrayList;

6 import java.util.Date;

7

8 public class BookTest extends TestCase {

9 Book book;

10 Chapter chapter;

11

12 public void setUp() {

13 book = new Book();

14 book.setNumberOfPages(300);

15 book.setAuthorName("Mike Hugo");

16 book.setTitle("Groovy Jam");

17 book.setSubTitle("Jammin");

18 book.setPublisher("Piragua Press");

19 book.setPublishDate(new Date());

20 }

Page 18: Groovy Grails DevJam Jam Session

1 package com.piragua.groovy

2

3 public class BookTest extends GroovyTestCase {

4 Book book

5 Chapter grails, groovy, why

6

7 void setUp() {

8 book = new Book(title: "Groovy Jam", subTitle:"Jammin",

9 authorName: "Mike Hugo", numberOfPages: 300,

10 publishDate:new Date(), publisher: "Piragua Press")

11 }

Page 19: Groovy Grails DevJam Jam Session

null safe dereferencing

http://flickr.com/photos/synthesisstudios/352834727/

Page 20: Groovy Grails DevJam Jam Session

32 public String toString() {

33 String upperCaseTitle = null;

34 if (title != null){

35 upperCaseTitle = title.toUpperCase();

36 }

37 return upperCaseTitle;

38 }

Page 21: Groovy Grails DevJam Jam Session

String toString(){

title?.toUpperCase()

}

Page 22: Groovy Grails DevJam Jam Session

// more complex

String toString(){

book?.publisher?.address?.city?.toUpperCase()

}

Page 23: Groovy Grails DevJam Jam Session

groovy strings

http://flickr.com/photos/austinevan/416813459/

Page 24: Groovy Grails DevJam Jam Session

// Java Example

public String displayString() {

return "<u>" + title + "</u> by " +

authorName + ", (" +

numberOfPages + " pages)";

}

Page 25: Groovy Grails DevJam Jam Session

// Java Example

public String displayString() {

return "<u>" + title + "</u> by " +

authorName + ", (" +

numberOfPages + " pages)";

}

Page 26: Groovy Grails DevJam Jam Session

String displayString() {

"<u>${title}</u> by ${authorName}, (${numberOfPages} pages)"

}

Page 27: Groovy Grails DevJam Jam Session

String multiLineDisplayString() {

"""<u>${title}</u>

by ${authorName}

(${numberOfPages} pages)"""

}

Page 28: Groovy Grails DevJam Jam Session

collections

http://flickr.com/photos/stibbons/375342559/

Page 29: Groovy Grails DevJam Jam Session

11 private List<Chapter> chapters;

//...

55 public Chapter findChapterByTitle(String chapterTitle) {

56 Chapter foundChapter = null;

57

58 if (chapterTitle != null && chapters != null) {

59 for (int i = 0; i < chapters.size(); i++) {

60 if (chapters.get(i) != null &&

61 chapterTitle.equals(chapters.get(i).getTitle())) {

62 foundChapter = chapters.get(i);

63 break;

64 }

65 }

66 }

67 return foundChapter;

68 }

Page 30: Groovy Grails DevJam Jam Session

11 private List<Chapter> chapters;

//...

55 public Chapter findChapterByTitle(String chapterTitle) {

56 Chapter foundChapter = null;

57

58 if (chapterTitle != null && chapters != null) {

59 for (int i = 0; i < chapters.size(); i++) {

60 if (chapters.get(i) != null &&

61 chapterTitle.equals(chapters.get(i).getTitle())) {

62 foundChapter = chapters.get(i);

63 break;

64 }

65 }

66 }

67 return foundChapter;

68 }

Page 31: Groovy Grails DevJam Jam Session

8 List chapters

//...

17 Chapter findChapterByTitle(String title) {

18 // finding the first item that matches criteria

19 chapters?.find({it?.title == title})

20 }

Page 32: Groovy Grails DevJam Jam Session

8 List chapters

//...

22 List findChaptersByTitleStartingWith(String searchKeyword) {

23 // finding all matching items

24 chapters?.findAll({it?.title?.startsWith(searchKeyword)})

25 }

Page 33: Groovy Grails DevJam Jam Session

8 List chapters

//...

27 void printChapterTitles() {

28 // iterating over a list

29 chapters.each {chapter ->

30 println chapter?.title

31 }

32 }

Page 34: Groovy Grails DevJam Jam Session

duck typing

http://flickr.com/photos/davidw/380277419/

Page 35: Groovy Grails DevJam Jam Session
Page 36: Groovy Grails DevJam Jam Session

1 package com.piragua.java;

2

3 import javax.servlet.ServletException;

4 import javax.servlet.http.*;

5 import java.io.IOException;

6

7 public class MyServlet extends HttpServlet {

8

9 @Override

10 protected void doPost(HttpServletRequest request,

11 HttpServletResponse response)

12 throws ServletException, IOException {

13

14 String username = request.getParameter("username");

15 if (username != null) {

16 HttpSession session = request.getSession(true);

17 session.setAttribute("loggedInUser", username);

18 }

19

20 }

21 }

22

Page 37: Groovy Grails DevJam Jam Session

1 package com.piragua.groovy

2

3 import javax.servlet.http.*

4 import com.piragua.java.MyServlet

5

6 public class MyServletTest extends GroovyTestCase {

7

8 Map params

9 Map session

10

11 def request

12

13 protected void setUp() {

14 params = [:]

15 session = [:]

16 def mockSession = [setAttribute: {k, v -> session[k] = v }]

17

18 request = [

19 getParameter: {param -> return params[param]},

20 getSession: {createNew -> return mockSession as HttpSession}]

21 }

Page 38: Groovy Grails DevJam Jam Session

23 void testDoGetFoundUser() {

24 params.username = 'mike'

25 new MyServlet().doPost(request as HttpServletRequest,

26 [:] as HttpServletResponse)

27 assertEquals(params.username, session.loggedInUser)

28 }

29

30 void testDoGetNoUser() {

31 params.username = null

32 new MyServlet().doPost(request as HttpServletRequest,

33 [:] as HttpServletResponse)

34 assertNull(session.loggedInUser)

35 }

Page 39: Groovy Grails DevJam Jam Session

If we had more time...• file handling

• really easy regular expressions

• groovy truth

• case / switch

• closures

• meta programming

Page 40: Groovy Grails DevJam Jam Session

http://groovy.codehaus.org/ http://groovy.mn/

Page 41: Groovy Grails DevJam Jam Session
Page 42: Groovy Grails DevJam Jam Session

Act II

Page 43: Groovy Grails DevJam Jam Session

Web MVC Framework

Page 44: Groovy Grails DevJam Jam Session
Page 45: Groovy Grails DevJam Jam Session

convention

http://flickr.com/photos/markpasc/92779595

Page 46: Groovy Grails DevJam Jam Session

configuration

http://flickr.com/photos/clintjcl/169886338

Page 47: Groovy Grails DevJam Jam Session

DRY

http://flickr.com/photos/joshsommers/935470210/

Page 48: Groovy Grails DevJam Jam Session

Development

Page 49: Groovy Grails DevJam Jam Session

Deployment

Page 50: Groovy Grails DevJam Jam Session

http://flickr.com/photos/ragesoss/118620722/

Artifacts

Page 51: Groovy Grails DevJam Jam Session

http://flickr.com/photos/ragesoss/118620722/

Artefacts

Page 52: Groovy Grails DevJam Jam Session

grails create-app devjam

Page 53: Groovy Grails DevJam Jam Session
Page 54: Groovy Grails DevJam Jam Session
Page 55: Groovy Grails DevJam Jam Session

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

Page 56: Groovy Grails DevJam Jam Session

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

Page 57: Groovy Grails DevJam Jam Session

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

Page 58: Groovy Grails DevJam Jam Session
Page 59: Groovy Grails DevJam Jam Session
Page 60: Groovy Grails DevJam Jam Session
Page 61: Groovy Grails DevJam Jam Session
Page 62: Groovy Grails DevJam Jam Session
Page 63: Groovy Grails DevJam Jam Session
Page 64: Groovy Grails DevJam Jam Session
Page 65: Groovy Grails DevJam Jam Session
Page 66: Groovy Grails DevJam Jam Session
Page 67: Groovy Grails DevJam Jam Session

Zero

Page 68: Groovy Grails DevJam Jam Session

Customer

Address

class Customer {

! Address address

}

Page 69: Groovy Grails DevJam Jam Session

IncidentCustomer

class Customer {

! static hasMany = [incidents:Incident]

}

Page 70: Groovy Grails DevJam Jam Session

ProductCustomerCustomer

Product

class Customer {

! static hasMany = [products:Product]

}

class Product {

static hasMany = [customers:Customer]

static belongsTo = Customer //Customer owns the relationship

}

Page 71: Groovy Grails DevJam Jam Session
Page 72: Groovy Grails DevJam Jam Session

http://server/devjam/event/list

name of application

Page 73: Groovy Grails DevJam Jam Session

http://server/devjam/event/list

name of controller

Page 74: Groovy Grails DevJam Jam Session

http://server/devjam/event/list

name of action

Page 75: Groovy Grails DevJam Jam Session

http://server/devjam/event/list?max=10

Page 76: Groovy Grails DevJam Jam Session

Data Binding

Page 77: Groovy Grails DevJam Jam Session

Dependency Injection

Page 78: Groovy Grails DevJam Jam Session
Page 79: Groovy Grails DevJam Jam Session
Page 80: Groovy Grails DevJam Jam Session
Page 81: Groovy Grails DevJam Jam Session
Page 82: Groovy Grails DevJam Jam Session
Page 83: Groovy Grails DevJam Jam Session

Demo

Page 84: Groovy Grails DevJam Jam Session

If we had more time...• testing

• tag libraries

• services

• plugins

• content negotiation

Page 85: Groovy Grails DevJam Jam Session

http://grails.org http://grails.org/doc/1.0.x/

Page 86: Groovy Grails DevJam Jam Session
Page 87: Groovy Grails DevJam Jam Session

Act III

Page 88: Groovy Grails DevJam Jam Session
Page 89: Groovy Grails DevJam Jam Session

http://flickr.com/photos/johnniewalker/359440369

Page 90: Groovy Grails DevJam Jam Session

http://flickr.com/photos/philliecasablanca/2473728872

Page 91: Groovy Grails DevJam Jam Session
Page 92: Groovy Grails DevJam Jam Session
Page 93: Groovy Grails DevJam Jam Session

0

25

50

75

100

Learning Curve

* data for this chart is completely fabricated

Page 94: Groovy Grails DevJam Jam Session

0

25

50

75

100

Learning Curve

* data for this chart is completely fabricated

Page 95: Groovy Grails DevJam Jam Session
Page 96: Groovy Grails DevJam Jam Session
Page 97: Groovy Grails DevJam Jam Session

http://flickr.com/photos/13010608@N02/2441101135/

Page 98: Groovy Grails DevJam Jam Session

+ +

Page 99: Groovy Grails DevJam Jam Session
Page 100: Groovy Grails DevJam Jam Session

http://flickr.com/photos/kevint/85911467

Page 101: Groovy Grails DevJam Jam Session

1 package com.piragua.groovy

2

3 import javax.servlet.http.*

4 import com.piragua.java.MyServlet

5

6 class MyServletTest extends GroovyTestCase {

7

8 Map params

9 Map session

10

11 def request

12

13 protected void setUp() {

14 params = [:]

15 session = [:]

16 def mockSession = [setAttribute: {k, v -> session[k] = v }]

Page 102: Groovy Grails DevJam Jam Session

http://flickr.com/photos/nengard/82039595

Page 103: Groovy Grails DevJam Jam Session
Page 104: Groovy Grails DevJam Jam Session

200,000 users

1 Million page views/month

$250/monthVPS

Page 105: Groovy Grails DevJam Jam Session
Page 106: Groovy Grails DevJam Jam Session
Page 107: Groovy Grails DevJam Jam Session

http://flickr.com/photos/oxygenws/39895404

Page 108: Groovy Grails DevJam Jam Session
Page 109: Groovy Grails DevJam Jam Session

XYZ Thing

Page 110: Groovy Grails DevJam Jam Session
Page 111: Groovy Grails DevJam Jam Session

http://flickr.com/photos/thatblondegirl/467513888

Page 112: Groovy Grails DevJam Jam Session
Page 113: Groovy Grails DevJam Jam Session
Page 114: Groovy Grails DevJam Jam Session

Thank You

Page 115: Groovy Grails DevJam Jam Session

Groovy/Grails DevJam

https://duke.dev.java.net/images/guitar/DukeAsKeith-daylight.pnghttp://svn.codehaus.org/groovy/trunk/groovy/groovy-core/cruise/reporting-app/images/DukeGroovyChair.jpg

Page 116: Groovy Grails DevJam Jam Session

3 things to talk about tonight:-Brief overview of Groovy-High level Grails (and Live Coding!)-Thumbs up and Thumbs Down:! -When should you choose to use Groovy/Grails in existing or greenfield project! -Where it has worked (and why) and where it has failed (and why)

Page 117: Groovy Grails DevJam Jam Session

Act I

What is Groovy? - ask the audience...possible answers:- answers.com: “Very pleasing; wonderful.”- agile language- scripting language for the JVM- dynamically typed language- build tool- runtime tool for the JVM- high level language for the JVM that compiles to byte code- open source java language- language to make unit testing easier for Java applications

Page 118: Groovy Grails DevJam Jam Session

“When you program in Groovy, in many waysyou’re writing a special kind of Java.”

-Dierk KönigGroovy in Action

Groovy is all of those things, but most of all I like this definition. What is Groovy? - answer by Dierk König, Groovy committer and author of “Groovy in Action”- dynamic language for the JVM

Page 119: Groovy Grails DevJam Jam Session

.java .groovy

In fact, most of the time you can take .java file and rename it .groovy and it will compile and run

Page 120: Groovy Grails DevJam Jam Session

Groovy and Java work seamlessly together

-your java classes can reference groovy classes and groovy classes can reference java classes

Page 121: Groovy Grails DevJam Jam Session

hugobook:groovy mjhugo$ groovycusage: groovyc [options] <source-files>

options:

--encoding <encoding> Specify the encoding of the user class files.

-F <flag>

-J <property=value>

-d Specify where to place generated class files.

-e,--exception Print stack trace on error.

-h,--help Print a synopsis of standard options.

-j,--jointCompilation Attach javac compiler to compile .java files. -v,--version Print the version.

This is because of something unique to groovy - the Groovy Joint Compiler - you can compile .groovy and .java files at the same time allowing that seamless interaction

Page 122: Groovy Grails DevJam Jam Session

What this means is if you’re already using Java, it works with everything you already have - IDEs- Open Source Frameworks- Application Servers, etc.

Page 123: Groovy Grails DevJam Jam Session

20%

80%

For me, it comes down to the 80/20 rule. Groovy gives me the ability to write concise code that"s straight to the point of what I"m trying to do. I don"t have to include “ceremony” - code that doesn"t relate to the task at hand (Stuart Halloway, http://blog.thinkrelevance.com/2008/4/1/ending-legacy-code-in-our-lifetime) and can focus directly on the goal my code is trying to achieve.

Examples...

Page 124: Groovy Grails DevJam Jam Session

getters and setters

Getters and Setters ExampleStandard stuff - create some properties and have your IDE of choice generate the getters and settersbut WHY generate them? they add so much noise to your code...

Page 125: Groovy Grails DevJam Jam Session

1 package com.piragua.java;

2

3 public class SimpleBook {

4 private String title;

5 private String authorName;

6

7 public String getTitle() {

8 return title;

9 }

10

11 public void setTitle(String title) {

12 this.title = title;

13 }

14

15 public String getAuthorName() {

16 return authorName;

17 }

18

19 public void setAuthorName(String authorName) {

20 this.authorName = authorName;

21 }

22 }

Java example: two properties, 15 lines of code for getters/setters

Now, let"s look at the same class in Groovy...

Page 126: Groovy Grails DevJam Jam Session

1 package com.piragua.groovy

2

3 class SimpleBook {

4 String title

5 String authorName

6 }

Same class, 0 lines of code for getters/setters

Also notice that the attributes and the class are not scoped - that"s because Groovy provides sensible defaults for these -

Lets take a look at a snippet of the byte code as shown by javap

Page 127: Groovy Grails DevJam Jam Session

javap -private SimpleBook

Compiled from "SimpleBook.groovy"

public class com.piragua.groovy.SimpleBook ... {

private java.lang.String title;

private java.lang.String author;

public java.lang.String getTitle(); public void setTitle(java.lang.String);

public java.lang.String getAuthor(); public void setAuthor(java.lang.String);

...

}

- getters and setters are provided automatically! - You can add your own getters and setters to define custom behavior - but how often do you really do this?

Page 128: Groovy Grails DevJam Jam Session

javap -private SimpleBook

Compiled from "SimpleBook.groovy"

public class com.piragua.groovy.SimpleBook ... {

private java.lang.String title; private java.lang.String author;

public java.lang.String getTitle(); public void setTitle(java.lang.String);

public java.lang.String getAuthor(); public void setAuthor(java.lang.String);

...

}

- no need to define class as public - that"s the default- attributes are private by default- methods are public by default

Page 129: Groovy Grails DevJam Jam Session

1 package com.piragua.java;

2

3 import java.util.Date;

4 import java.util.List;

5

6 public class Book {

7 private String title;

8 private String authorName;

9 private Integer numberOfPages;

10 private String subTitle;

11 private List<Chapter> chapters;

12 private Date publishDate;

13 private String publisher;

14

15 public String getPublisher() {

16 return publisher;

17 }

18

19 public void setPublisher(String publisher) {

20 this.publisher = publisher;

21 }

22

23 public Date getPublishDate() {

24 return publishDate;

25 }

26

27 public void setPublishDate(Date publishDate) {

28 this.publishDate = publishDate;

29 }

30

31 public List getChapters() {

32 return chapters;

33 }

34

35 public void setChapters(List chapters) {

36 this.chapters = chapters;

37 }

38

39 public String getTitle() {

40 return title;

41 }

42

43 public void setTitle(String title) {

44 this.title = title;

45 }

46

47 public String getAuthorName() {

48 return authorName;

49 }

50

51 public void setAuthorName(String authorName) {

52 this.authorName = authorName;

53 }

54

55 public Integer getNumberOfPages() {

56 return numberOfPages;

57 }

58

59 public void setNumberOfPages(Integer numberOfPages) {

60 this.numberOfPages = numberOfPages;

61 }

62

63 public String getSubTitle() {

64 return subTitle;

65 }

66

67 public void setSubTitle(String subTitle) {

68 this.subTitle = subTitle;

69 }

70

71 public String toString() {

72 String upperCaseTitle = null;

73 if (title != null) {

74 upperCaseTitle = title.toUpperCase();

75 }

76 return upperCaseTitle;

77 }

78

79 public String displayString() {

80 return "<u>" + title + "</u> by " + authorName + ", (" + numberOfPages + " pages)";

81 }

82

83 public Chapter findChapterByTitle(String chapterTitle) {

84 Chapter foundChapter = null;

85

86 if (chapterTitle != null && chapters != null) {

87 for (int i = 0; i < chapters.size(); i++) {

88 if (chapters.get(i) != null &&

89 chapterTitle.equals(chapters.get(i).getTitle())) {

90 foundChapter = chapters.get(i);

91 break;

92 }

93 }

94 }

95 return foundChapter;

96 }

97 }

1 package com.piragua.groovy

2

3 class Book {

4 String title

5 String authorName

6 Integer numberOfPages

7 String subTitle

8 List chapters

9 Date publishDate

10 String publisher

11

12 String toString() {

13 title?.toUpperCase()

14 }

15

16 String displayString() {

17 "<u>${title}</u> by ${authorName}, (${numberOfPages} pages)"

18 }

19

20 Chapter findChapterByTitle(String title) {

21 // finding the first item that matches criteria

22 chapters?.find({it?.title == title})

23 }

24 }

This is the same class - on the left is Java (97 lines of code), on the right is Groovy (24 lines of code).6 pt font Each class has 7 attributes and three methods.

When you go to maintain the Book class, which file would you rather work with?

Page 130: Groovy Grails DevJam Jam Session

constructor convenience

http://flickr.com/photos/9229859@N02/1052409181/

Page 131: Groovy Grails DevJam Jam Session

1 package com.piragua.java;

2

3 import junit.framework.TestCase;

4

5 import java.util.ArrayList;

6 import java.util.Date;

7

8 public class BookTest extends TestCase {

9 Book book;

10 Chapter chapter;

11

12 public void setUp() {

13 book = new Book();

14 book.setNumberOfPages(300);

15 book.setAuthorName("Mike Hugo");

16 book.setTitle("Groovy Jam");

17 book.setSubTitle("Jammin");

18 book.setPublisher("Piragua Press");

19 book.setPublishDate(new Date());

20 }

Constructor ShortcutHappens all the time in unit testing, but also sometimes in real code for setting defaultsNew up an object, then call all the setters to populate some values

Page 132: Groovy Grails DevJam Jam Session

1 package com.piragua.groovy

2

3 public class BookTest extends GroovyTestCase {

4 Book book

5 Chapter grails, groovy, why

6

7 void setUp() {

8 book = new Book(title: "Groovy Jam", subTitle:"Jammin",

9 authorName: "Mike Hugo", numberOfPages: 300,

10 publishDate:new Date(), publisher: "Piragua Press")

11 }

In groovy, you can use named parameters in the constructor to build objects- can happen in any order- can pass all, some, or none of the attributes to the constructor- it"s descriptive - you know what"s being set because it says it right here (e.g. title: “groovy jam”)...if you created a java constructor how would you remember which order to pass the parameters?

Page 133: Groovy Grails DevJam Jam Session

null safe dereferencing

http://flickr.com/photos/synthesisstudios/352834727/

Page 134: Groovy Grails DevJam Jam Session

32 public String toString() {

33 String upperCaseTitle = null;

34 if (title != null){

35 upperCaseTitle = title.toUpperCase();

36 }

37 return upperCaseTitle;

38 }

In Java, you often have times where you check to see if something is null before performing an action on it

Page 135: Groovy Grails DevJam Jam Session

String toString(){

title?.toUpperCase()

}

In Groovy, you can use the ? operator to safely traverse the tree of an object graph

Page 136: Groovy Grails DevJam Jam Session

// more complex

String toString(){

book?.publisher?.address?.city?.toUpperCase()

}

If any of the attributes in this example are null, groovy will stop at that point and return null

Page 137: Groovy Grails DevJam Jam Session

groovy strings

http://flickr.com/photos/austinevan/416813459/

Page 138: Groovy Grails DevJam Jam Session

// Java Example

public String displayString() {

return "<u>" + title + "</u> by " +

authorName + ", (" +

numberOfPages + " pages)";

}

Yeck.

String concatenation is evilSo is using string buffer

Page 139: Groovy Grails DevJam Jam Session

// Java Example

public String displayString() {

return "<u>" + title + "</u> by " +

authorName + ", (" +

numberOfPages + " pages)";

}

Yeck.

String concatenation is evilSo is using string buffer

Page 140: Groovy Grails DevJam Jam Session

String displayString() {

"<u>${title}</u> by ${authorName}, (${numberOfPages} pages)"

}

Groovy strings allow you to construct strings using ${} notation

You can also do multi line strings

Page 141: Groovy Grails DevJam Jam Session

String multiLineDisplayString() {

"""<u>${title}</u>

by ${authorName}

(${numberOfPages} pages)"""

}

You can also do multi line strings

Page 142: Groovy Grails DevJam Jam Session

collections

http://flickr.com/photos/stibbons/375342559/

Page 143: Groovy Grails DevJam Jam Session

11 private List<Chapter> chapters;

//...

55 public Chapter findChapterByTitle(String chapterTitle) {

56 Chapter foundChapter = null;

57

58 if (chapterTitle != null && chapters != null) {

59 for (int i = 0; i < chapters.size(); i++) {

60 if (chapters.get(i) != null &&

61 chapterTitle.equals(chapters.get(i).getTitle())) {

62 foundChapter = chapters.get(i);

63 break;

64 }

65 }

66 }

67 return foundChapter;

68 }

Java example of finding a chapter by title

- iterate over the the list until you find the one you"re looking for, set it in a temp variable and break

Page 144: Groovy Grails DevJam Jam Session

11 private List<Chapter> chapters;

//...

55 public Chapter findChapterByTitle(String chapterTitle) {

56 Chapter foundChapter = null;

57

58 if (chapterTitle != null && chapters != null) {

59 for (int i = 0; i < chapters.size(); i++) {

60 if (chapters.get(i) != null &&

61 chapterTitle.equals(chapters.get(i).getTitle())) {

62 foundChapter = chapters.get(i);

63 break;

64 }

65 }

66 }

67 return foundChapter;

68 }

Java example of finding a chapter by title

- by the way, did you notice all the null checking going on that distracts from the essence of the code: finding a chapter by title

Page 145: Groovy Grails DevJam Jam Session

8 List chapters

//...

17 Chapter findChapterByTitle(String title) {

18 // finding the first item that matches criteria

19 chapters?.find({it?.title == title})

20 }

Groovy example

- use .find and pass a closure- closure is executed against every item in the list until a match is found

- #it" is an implicit parameter passed to a closure, can be named- == in groovy is the same as .equals()

Page 146: Groovy Grails DevJam Jam Session

8 List chapters

//...

22 List findChaptersByTitleStartingWith(String searchKeyword) {

23 // finding all matching items

24 chapters?.findAll({it?.title?.startsWith(searchKeyword)})

25 }

- can also use .findAll

Page 147: Groovy Grails DevJam Jam Session

8 List chapters

//...

27 void printChapterTitles() {

28 // iterating over a list

29 chapters.each {chapter ->

30 println chapter?.title

31 }

32 }

or .each to iterate over a collection

Page 148: Groovy Grails DevJam Jam Session

duck typing

http://flickr.com/photos/davidw/380277419/

http://en.wikipedia.org/wiki/Duck_typingIf it walks like a duck and quacks like a duck, I would call it a duck.

Rather than create an interface to define the contract, use behavior at runtime to determine the functionality

So now, a Java example

Page 149: Groovy Grails DevJam Jam Session

oh wait. you can"t do this in java. no example here.

Page 150: Groovy Grails DevJam Jam Session

1 package com.piragua.java;

2

3 import javax.servlet.ServletException;

4 import javax.servlet.http.*;

5 import java.io.IOException;

6

7 public class MyServlet extends HttpServlet {

8

9 @Override

10 protected void doPost(HttpServletRequest request,

11 HttpServletResponse response)

12 throws ServletException, IOException {

13

14 String username = request.getParameter("username");

15 if (username != null) {

16 HttpSession session = request.getSession(true);

17 session.setAttribute("loggedInUser", username);

18 }

19

20 }

21 }

22

Here"s an example of a Java Servlet. It takes a parameter from the request, and if it is not null, sets it in to the session.

If I wanted to test this, I would have to provide a full implementation of HttpServletRequest and HttpServletResponse just in order to call the method.

Note: Spring (and other frameworks) provide Mock implementations of HttpServletRequest and HttpServletResponse, but pretend those don"t exist for the purpose of this example

Page 151: Groovy Grails DevJam Jam Session

1 package com.piragua.groovy

2

3 import javax.servlet.http.*

4 import com.piragua.java.MyServlet

5

6 public class MyServletTest extends GroovyTestCase {

7

8 Map params

9 Map session

10

11 def request

12

13 protected void setUp() {

14 params = [:]

15 session = [:]

16 def mockSession = [setAttribute: {k, v -> session[k] = v }]

17

18 request = [

19 getParameter: {param -> return params[param]},

20 getSession: {createNew -> return mockSession as HttpSession}]

21 }

But using Groovy, I can utilize Duck Typing to mock out the implementation.

Line 20 has an example: “mockSession as HttpSession”

more in the tests

Page 152: Groovy Grails DevJam Jam Session

23 void testDoGetFoundUser() {

24 params.username = 'mike'

25 new MyServlet().doPost(request as HttpServletRequest,

26 [:] as HttpServletResponse)

27 assertEquals(params.username, session.loggedInUser)

28 }

29

30 void testDoGetNoUser() {

31 params.username = null

32 new MyServlet().doPost(request as HttpServletRequest,

33 [:] as HttpServletResponse)

34 assertNull(session.loggedInUser)

35 }

Line 25: “request as HttpServletRequest” - my map (defined in the setup method) now looks like a HttpServletRequest to the Servlet under test

Line 33: “[:] as HttpServletResponse” just acts as a non-null HttpServletResponse. How would you do this in Java? Create a class, implement the HttpServletResponse interface with a bunch of empty methods, then new it up and pass it into the doPost method. That sucks.

Now, I know duck typing is controversial. Interfaces can be a good thing, and they enforce the contract at compile time. With duck typing, you don"t have compile time checking of the contract - so testing is really important here. Regardless of your opinion, remember:

Page 153: Groovy Grails DevJam Jam Session

If we had more time...• file handling

• really easy regular expressions

• groovy truth

• case / switch

• closures

• meta programming

For reference in the handout:- File: Convenience methods for writing and reading files: http://docs.codehaus.org/display/GROOVY/JN2015-Files- Truth: .equals is the same as ==; 1 is true, 0 is false; null is false; empty string is false; etc. : http://docs.codehaus.org/display/GROOVY/Groovy+Truth- Regular expressions are so easy! http://naleid.com/blog/2008/05/19/dont-fear-the-regexp/- Case / Switch: can switch on any type: http://groovy.codehaus.org/Logical+Branching- Closures: named block of code. pass it around, reuse it, do all sorts of fun things: http://groovy.codehaus.org/Closures- Meta Programming: http://groovy.dzone.com/articles/metaprogramming-groovy-ii-expa , also http://naleid.com/blog/2008/05/07/what-methods-does-my-groovygrails-class-have/- See more differences from Java: http://groovy.codehaus.org/Differences+from+Java

Page 154: Groovy Grails DevJam Jam Session

http://groovy.codehaus.org/ http://groovy.mn/

Two resources:Groovy website @ codehaus - api, documentation, and lots of examplesGroovy Users Group of MN - meets the second Tuesday of the month in NE minneapolis

Also see this presentation by Guillaume LaForge (groovy project manager) on Groovyhttp://www.slideshare.net/glaforge/groovy-and-grails-in-action-devoxx-2008-university-guillaume-laforge-presentation

Page 155: Groovy Grails DevJam Jam Session

Three books:-Groovy in Action (Dierk König)-Groovy Recipies (Scott Davis)-Programming Groovy (Venkat Subramaniam)

http://www.amazon.com/Groovy-Action-Dierk-Koenig/dp/1932394842http://www.amazon.com/Groovy-Recipes-Greasing-Pragmatic-Programmers/dp/0978739299/

Page 156: Groovy Grails DevJam Jam Session

Act II

So now, on to Grails...What is Grails?

Page 157: Groovy Grails DevJam Jam Session

Web MVC Framework

Grails is a Web Model/View/Controller framework

Page 158: Groovy Grails DevJam Jam Session

that leverages the power of Groovy, Hibernate, Spring and Java

Page 159: Groovy Grails DevJam Jam Session

convention

http://flickr.com/photos/markpasc/92779595

With it you can do rapid application development by using the concepts of Convention...

Page 160: Groovy Grails DevJam Jam Session

configuration

http://flickr.com/photos/clintjcl/169886338

instead of configuration (AKA convention over configuration)

Page 161: Groovy Grails DevJam Jam Session

DRY

http://flickr.com/photos/joshsommers/935470210/

And “Don’t Repeat Yourself” Why add all sorts of ceremony to your code in configuration when it could be implied?

Page 162: Groovy Grails DevJam Jam Session

Development

Grails provides a full *development* environment out of the box including an:- in-memory HSQL DB- Jetty application server- Automatic reloading of most artifacts

But you’re not limited to that in Development or even in Production -

Page 163: Groovy Grails DevJam Jam Session

Deployment

Jetty and HSQLDB are just the defaults -You can deploy a grails application on any application server that can handle a WAR fileand any database that has a JDBC driver

But I’m getting ahead of myself...let’s get started with some Grails basics

Page 164: Groovy Grails DevJam Jam Session

http://flickr.com/photos/ragesoss/118620722/

Artifacts

Artifacts. or, if you’re british

Page 165: Groovy Grails DevJam Jam Session

http://flickr.com/photos/ragesoss/118620722/

Artefacts

A lot of the core contributors to Grails are in the UK, so you sometimes run into this (in the Grails code base)

Page 166: Groovy Grails DevJam Jam Session

grails create-app devjam

Every Grails Application has a common structureUnderneath the ‘grails-app’ directory there are sub-directories for “special” grails artifacts.Let’s look at a few

Page 167: Groovy Grails DevJam Jam Session

The domain subdirectory is for any class that you want to be persistent. These classes are automatically mapped to the DB through Hibernate

Page 168: Groovy Grails DevJam Jam Session

Grails will automatically create your database tables based on your domain classes using Hibernate’s hbm2ddlThere are other ways to manage DB migrations, this is just the default

Page 169: Groovy Grails DevJam Jam Session

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

! - the domain class name becomes the table name

Page 170: Groovy Grails DevJam Jam Session

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

! - attribute names are converted into column names

Page 171: Groovy Grails DevJam Jam Session

mysql> describe event;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | bigint(20) | NO | PRI | NULL | auto_increment | | version | bigint(20) | NO | | NULL | | | event_date | datetime | NO | | NULL | | | title | varchar(255) | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+4 rows in set (0.00 sec)

- id (PK) and version (optimistic locking) columns are added to DB, but don’t need to be explicitly specified in code

all of these defaults can be overridden through a mapping DSL or through explicit Hibernate configuration

Page 172: Groovy Grails DevJam Jam Session

The next couple examples are screen shots of the “Grails Console” - an interactive Swing console that is wired up with hibernate and all your spring beans and everything

Page 173: Groovy Grails DevJam Jam Session

Not only are the domain classes automatically mapped to the DB, Grails adds persistent methods like

.save() - inserts or updates an object

Page 174: Groovy Grails DevJam Jam Session

.get(id)

pass in the ID of a persistent object and hibernate will retrieve it

Page 175: Groovy Grails DevJam Jam Session

.list()

select * from table

Page 176: Groovy Grails DevJam Jam Session

and last but not least, dynamic finders like “findByTitle”

Page 177: Groovy Grails DevJam Jam Session

and you can even add criteria like ‘EventDateLessThan’

Page 178: Groovy Grails DevJam Jam Session

how about a query using case insensitive ‘like’?

Page 179: Groovy Grails DevJam Jam Session

or a query using HQL?

Page 180: Groovy Grails DevJam Jam Session

or a query using criteria?

Page 181: Groovy Grails DevJam Jam Session

Zero

All of this with: Zero - the amount of configuration and DAO lines of code you have to do to perform crud on a domain class.

Page 182: Groovy Grails DevJam Jam Session

Customer

Address

class Customer {

! Address address

}

Associations are also supported - you can have - one to one

Page 183: Groovy Grails DevJam Jam Session

IncidentCustomer

class Customer {

! static hasMany = [incidents:Incident]

}

- one to many

Page 184: Groovy Grails DevJam Jam Session

ProductCustomerCustomer

Product

class Customer {

! static hasMany = [products:Product]

}

class Product {

static hasMany = [customers:Customer]

static belongsTo = Customer //Customer owns the relationship

}

- many to many

Page 185: Groovy Grails DevJam Jam Session

Controllers are servlets in the Grails world. Any groovy class in this directory will have a url mapping by convention - no xml config required:

Page 186: Groovy Grails DevJam Jam Session

http://server/devjam/event/list

name of application

The context root of your app is the name of the application, in this case “devjam”

Page 187: Groovy Grails DevJam Jam Session

http://server/devjam/event/list

name of controller

The next part of a URL is the name of the controller

Page 188: Groovy Grails DevJam Jam Session

http://server/devjam/event/list

name of action

and the final part is the name of the action (which is a closure defined in the controller)

These are the defaults - you can change URL mappings to your liking

Page 189: Groovy Grails DevJam Jam Session

http://server/devjam/event/list?max=10

Grails puts all the parameters coming in to a controller in to a map called ‘params’ - you can access them using ‘dot’ notation (like ‘params dot max’ to get the ‘max’ parameter)

Page 190: Groovy Grails DevJam Jam Session

Data Binding

This is also fantastic for data binding - on a new object you can pass the ‘params’ map straight to a object constructor (thank you Groovy constructor convenience)

Page 191: Groovy Grails DevJam Jam Session

Dependency Injection

Grails artifacts like controllers and services are created as spring beans - and grails autowires beans together by name.

In the case, AuthenticateService will automatically be injected into the EventController - no config needed

Page 192: Groovy Grails DevJam Jam Session

Views are GSP (grails server pages) instead of JSPs

Page 193: Groovy Grails DevJam Jam Session

you can reference anything that is in the ‘model’ with ${} notation (like eventInstance)

Page 194: Groovy Grails DevJam Jam Session

there’s a convention for where the views go - by default views for the “EventController” go in the “views/event” subdirectory

Page 195: Groovy Grails DevJam Jam Session

Grails uses SiteMesh to decorate pages - so your GSPs are simple HTML

Page 196: Groovy Grails DevJam Jam Session

that have a layout applied to them

Page 197: Groovy Grails DevJam Jam Session

Demo

Demo - build a simple Grails app to -list events (demo sca"olding)-create a new event (demo domain constraints)-allow users to RSVP to them (demo reloading of controller and dependency injection)-create RSS feed of events list (install and use feeds plugin)

Page 198: Groovy Grails DevJam Jam Session

If we had more time...• testing

• tag libraries

• services

• plugins

• content negotiation

For reference in the handout:Testing: http://www.grails.org/Testing+PluginTag Libraries: http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html#6.3%20Tag%20LibrariesServices: http://grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.htmlPlugins: http://grails.org/PluginsContent Negotiation: http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html#6.8%20Content%20Negotiation

Page 199: Groovy Grails DevJam Jam Session

http://grails.org http://grails.org/doc/1.0.x/

Two resources:Grails.org website - great starting point - and a grails app itselfGrails reference guide - excellent documentation of Grails

Page 200: Groovy Grails DevJam Jam Session

Two excellent books coming out very soon (early editions available from publisher now)

GIA (May?): http://www.amazon.com/Grails-Action-Glen-Smith/dp/1933988932/DGG (Jan): http://www.amazon.com/Definitive-Guide-Grails-Second/dp/1590599950

Page 201: Groovy Grails DevJam Jam Session

Act III

Act III: - when should you consider using these tools in an existing environment? - greenfield environment?- Where have they worked and where haven"t they?

When should you consider using these tools in an existing environment?

Page 202: Groovy Grails DevJam Jam Session

The first question I ask is “Are you already a Java shop?”

Page 203: Groovy Grails DevJam Jam Session

http://flickr.com/photos/johnniewalker/359440369

If you are - then you already have the infrastructure you need to build and deploy applications with Groovy/Grails...

Page 204: Groovy Grails DevJam Jam Session

http://flickr.com/photos/philliecasablanca/2473728872

And you also have resources that understand Java

Page 205: Groovy Grails DevJam Jam Session

If your company/client is open source friendly

Page 206: Groovy Grails DevJam Jam Session

Then bringing Groovy into your existing environment is a piece of cake.

Page 207: Groovy Grails DevJam Jam Session

0

25

50

75

100

Learning Curve

* data for this chart is completely fabricated

The learning curve for a new language might look like this

Page 208: Groovy Grails DevJam Jam Session

0

25

50

75

100

Learning Curve

* data for this chart is completely fabricated

With Groovy, your Java developers will have a jump start on learning the language -the syntax is basically the same-all the Java APIs are available to you-can immediately be productive with the language and conveniences it provides

Page 209: Groovy Grails DevJam Jam Session

Integrating Grails into an existing environment may not be quite as easy

Page 210: Groovy Grails DevJam Jam Session

If you’re already using Hibernate for the ORM layer, then it’s possible. You can take your existing database, existing hibernate mapping files and Java domain classes and take advantage of all the features Grails has to o"er.

(See “Grails In Action” book for using Grails to map the “Legacy Database from Hell”)

Page 211: Groovy Grails DevJam Jam Session

http://flickr.com/photos/13010608@N02/2441101135/

But where Grails really excels is in a green field

Page 212: Groovy Grails DevJam Jam Session

+ +

-If your team is familiar with Hibernate and Spring-Your process includes iterative development and a fast feedback loop -And testing is important

Page 213: Groovy Grails DevJam Jam Session

Then you should seriously be considering Grails for your next project

Page 214: Groovy Grails DevJam Jam Session

http://flickr.com/photos/kevint/85911467

Where has it worked?

Page 215: Groovy Grails DevJam Jam Session

1 package com.piragua.groovy

2

3 import javax.servlet.http.*

4 import com.piragua.java.MyServlet

5

6 class MyServletTest extends GroovyTestCase {

7

8 Map params

9 Map session

10

11 def request

12

13 protected void setUp() {

14 params = [:]

15 session = [:]

16 def mockSession = [setAttribute: {k, v -> session[k] = v }]

Unit Testing is a great way to start integrating Groovy into your code base- collections / xml / file convenience features reduce the amount of ceremony in your tests- can make mocking is easier (as shown in earlier groovy slides)

Page 216: Groovy Grails DevJam Jam Session

http://flickr.com/photos/nengard/82039595

“internal” apps are a great place for Grails - it’s very easy to develop a fully functional web app very quickly

I built one at my last client in 12 hours (full user login, search, audit history and workflow task management)

Page 217: Groovy Grails DevJam Jam Session

There are tons of success stories for Grails (http://grails.org/Success+Stories)Some very large, some smaller.

Page 218: Groovy Grails DevJam Jam Session

200,000 users

1 Million page views/month

$250/monthVPS

Like this example - this Brazilian Entertainment website has 200k users, 1 million page views per month and runs on a $250/month VPS - no load balancing or major performance tuning

Feb 2008reference: http://www.nabble.com/Grails-1.0.1-is-out-td15548113.html

Page 219: Groovy Grails DevJam Jam Session

Linked in uses Grails for some of its sites for corporate customers

http://blog.linkedin.com/2008/06/11/grails-at-linkedin/

Page 220: Groovy Grails DevJam Jam Session

Hot o" the press - a full case study is coming soon!wired.com/reviews is Grails powered and more of Wired.com is moving to Grails soon

Page 221: Groovy Grails DevJam Jam Session

http://flickr.com/photos/oxygenws/39895404

Where has it failed?

Page 222: Groovy Grails DevJam Jam Session

I have seen projects run into trouble when they don’t test enough. The dynamic nature of Groovy/Grails means that the compiler won’t find certain errors - you need good testing to mitigate this

Page 223: Groovy Grails DevJam Jam Session

XYZ Thing

Too far outside the box

For instance - one project that didn’t use the conventions that GORM provides and tried to roll their own persistence mechanism didn’t go so well.

Page 224: Groovy Grails DevJam Jam Session

I hope you"ve enjoyed the overview of Groovy/Grails and some thoughts to consider when choosing them

Page 225: Groovy Grails DevJam Jam Session

http://flickr.com/photos/thatblondegirl/467513888

Obviously, I’m drinking the Koolaid

Page 226: Groovy Grails DevJam Jam Session

But I’ve also been working with Groovy and Grails for almost 2 years and I’m still a happy camper.

Page 227: Groovy Grails DevJam Jam Session

I encourage you to go download Groovy or download Grails and walk through the “Getting Started” tutorials - and see how these new tools can help you be more e"ective

Page 228: Groovy Grails DevJam Jam Session

Thank You