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
7. hugobook:groovy mjhugo$ groovyc
usage: 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.
12. 1 package com.piragua.groovy
2
3 class SimpleBook {
4 String title
5 String authorName
6 }
13. javap -private SimpleBook
Compiled from quot;SimpleBook.groovyquot;
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);
...
}
14. javap -private SimpleBook
Compiled from quot;SimpleBook.groovyquot;
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);
...
}
116. 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)
117. 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
118. “When you program in Groovy, in many ways
you’re writing a special kind of Java.”
-Dierk König
Groovy 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
119. .groovy
.java
In fact, most of the time you can take .java file and rename
it .groovy and it will compile and run
120. Groovy and Java work seamlessly together
-your java classes can reference groovy classes and groovy
classes can reference java classes
121. hugobook:groovy mjhugo$ groovyc
usage: 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
122. What this means is if you’re already using Java, it works with
everything you already have
- IDEs
- Open Source Frameworks
- Application Servers, etc.
123. 20%
80%
For me, it comes down to the 80/20 rule.
Groovy gives me the ability to write concise code thatquot;s straight to the point of
what Iquot;m trying to do. I donquot;t have to include “ceremony” - code that doesnquot;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...
124. getters and setters
Getters and Setters Example
Standard stuff - create some properties and have your IDE of choice generate the
getters and setters
but WHY generate them? they add so much noise to your code...
125. 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, letquot;s look at the same class in Groovy...
126. 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 - thatquot;s
because Groovy provides sensible defaults for these -
Lets take a look at a snippet of the byte code as shown by javap
127. javap -private SimpleBook
Compiled from quot;SimpleBook.groovyquot;
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?
128. javap -private SimpleBook
Compiled from quot;SimpleBook.groovyquot;
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 - thatquot;s the default
- attributes are private by default
- methods are public by default
129. 1 package com.piragua.java; 1 package com.piragua.groovy
2 2
3 import java.util.Date; 3 class Book {
4 import java.util.List; 4 String title
5 5 String authorName
6 public class Book { 6 Integer numberOfPages
7 private String title; 7 String subTitle
8 private String authorName; 8 List chapters
9 private Integer numberOfPages; 9 Date publishDate
10 private String subTitle; 10 String publisher
11 private List<Chapter> chapters; 11
12 private Date publishDate; 12 String toString() {
13 private String publisher; 13 title?.toUpperCase()
14 14 }
15 public String getPublisher() { 15
16 return publisher; 16 String displayString() {
17 } 17 quot;<u>${title}</u> by ${authorName}, (${numberOfPages} pages)quot;
18 18 }
19 public void setPublisher(String publisher) { 19
20 this.publisher = publisher; 20 Chapter findChapterByTitle(String title) {
21 } 21 // finding the first item that matches criteria
22 22 chapters?.find({it?.title == title})
23 public Date getPublishDate() { 23 }
24 return publishDate; 24 }
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 quot;<u>quot; + title + quot;</u> by quot; + authorName + quot;, (quot; + numberOfPages + quot; pages)quot;;
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 }
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?
131. 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(quot;Mike Hugoquot;);
16 book.setTitle(quot;Groovy Jamquot;);
17 book.setSubTitle(quot;Jamminquot;);
18 book.setPublisher(quot;Piragua Pressquot;);
19 book.setPublishDate(new Date());
20 }
Constructor Shortcut
Happens all the time in unit testing, but also sometimes in real code for
setting defaults
New up an object, then call all the setters to populate some values
132. 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: quot;Groovy Jamquot;, subTitle:quot;Jamminquot;,
9 authorName: quot;Mike Hugoquot;, numberOfPages: 300,
10 publishDate:new Date(), publisher: quot;Piragua Pressquot;)
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
- itquot;s descriptive - you know whatquot;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?
134. 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
135. String toString(){
title?.toUpperCase()
}
In Groovy, you can use the ? operator to safely traverse the tree of an object
graph
136. // 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
138. // Java Example
public String displayString() {
return quot;<u>quot; + title + quot;</u> by quot; +
authorName + quot;, (quot; +
numberOfPages + quot; pages)quot;;
}
Yeck.
String concatenation is evil
So is using string buffer
139. // Java Example
public String displayString() {
return quot;<u>quot; + title + quot;</u> by quot; +
authorName + quot;, (quot; +
numberOfPages + quot; pages)quot;;
}
Yeck.
String concatenation is evil
So is using string buffer
140. String displayString() {
quot;<u>${title}</u> by ${authorName}, (${numberOfPages} pages)quot;
}
Groovy strings allow you to construct strings using ${}
notation
You can also do multi line strings
141. String multiLineDisplayString() {
quot;quot;quot;<u>${title}</u>
by ${authorName}
(${numberOfPages} pages)quot;quot;quot;
}
You can also do multi line strings
143. 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 youquot;re looking for, set it in a
temp variable and break
144. 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
145. 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
- #itquot; is an implicit parameter passed to a closure, can be
named
146. 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
147. 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
148. duck typing
http://flickr.com/photos/davidw/380277419/
http://en.wikipedia.org/wiki/Duck_typing
If 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
149. oh wait. you canquot;t do this in java. no example here.
150. 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(quot;usernamequot;);
15 if (username != null) {
16 HttpSession session = request.getSession(true);
17 session.setAttribute(quot;loggedInUserquot;, username);
18 }
19
20 }
21 }
22
Herequot;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,
151. 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
152. 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 donquot;t
153. 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
154. http://groovy.codehaus.org/ http://groovy.mn/
Two resources:
Groovy website @ codehaus - api, documentation, and lots of examples
Groovy 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 Groovy
http://www.slideshare.net/glaforge/groovy-and-grails-in-action-devoxx-2008-
university-guillaume-laforge-presentation
155. 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/
1932394842
http://www.amazon.com/Groovy-Recipes-Greasing-Pragmatic-
159. convention
http://flickr.com/photos/markpasc/92779595
With it you can do rapid application development by using the
concepts of Convention...
160. configuration
http://flickr.com/photos/clintjcl/169886338
instead of configuration (AKA convention over configuration)
161. 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?
162. 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 -
163. Deployment
Jetty and HSQLDB are just the defaults -
You can deploy a grails application on any application server that
can handle a WAR file
and any database that has a JDBC driver
But I’m getting ahead of myself...let’s get started with some Grails
basics
164. Artifacts
http://flickr.com/photos/ragesoss/118620722/
Artifacts. or, if you’re british
165. Artefacts
http://flickr.com/photos/ragesoss/118620722/
A lot of the core contributors to Grails are in the UK, so you
sometimes run into this (in the Grails code base)
166. grails create-app devjam
Every Grails Application has a common structure
Underneath the ‘grails-app’ directory there are sub-directories for
“special” grails artifacts.
Let’s look at a few
167. The domain subdirectory is for any class that you want to be
persistent.
These classes are automatically mapped to the DB through
Hibernate
168. Grails will automatically create your database tables based on
your domain classes using Hibernate’s hbm2ddl
There are other ways to manage DB migrations, this is just the
default
169. 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
170. 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
171. 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
172. 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
173. Not only are the domain classes automatically mapped to the DB,
Grails adds persistent methods like
.save() - inserts or updates an object
188. 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
189. 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)
190. 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)
191. 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
192. Views are GSP (grails server pages) instead of JSPs
193. you can reference anything that is in the ‘model’ with ${} notation
(like eventInstance)
194. there’s a convention for where the views go - by default views for
the “EventController” go in the “views/event” subdirectory
197. Demo
Demo - build a simple Grails app to
-list events (demo scaquot;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)
198. If we had more time...
• testing
• tag libraries
• services
• plugins
• content negotiation
For reference in the handout:
Testing: http://www.grails.org/Testing+Plugin
Tag Libraries: http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html#6.3%20Tag%20Libraries
Services: http://grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.html
Plugins: http://grails.org/Plugins
Content Negotiation: http://grails.org/doc/1.0.x/guide/6.%20The%20Web%20Layer.html#6.8%20Content%20Negotiation
199. http://grails.org http://grails.org/doc/1.0.x/
Two resources:
Grails.org website - great starting point - and a grails app itself
Grails reference guide - excellent documentation of Grails
200. 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
201. Act III
Act III:
- when should you consider using these tools in an existing
environment?
- greenfield environment?
- Where have they worked and where havenquot;t they?
When should you consider using these tools in an existing
environment?
207. Learning Curve
100
75
50
25
0
* data for this chart is completely fabricated
The learning curve for a new language might look like this
208. Learning Curve
100
75
50
25
0
* 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
210. 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 oquot;er.
(See “Grails In Action” book for using Grails to map the “Legacy
Database from Hell”)
212. + +
-If your team is familiar with Hibernate and Spring
-Your process includes iterative development and a fast feedback
loop
-And testing is important
213. Then you should seriously be considering Grails for your next
project
215. 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)
216. 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)
217. There are tons of success stories for Grails (http://grails.org/
Success+Stories)
Some very large, some smaller.
218. 200,000 1 Million $250/month
users page views/month VPS
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 2008
reference: http://www.nabble.com/Grails-1.0.1-is-out-
td15548113.html
219. Linked in uses Grails for some of its sites for corporate customers
http://blog.linkedin.com/2008/06/11/grails-at-linkedin/
220. Hot oquot; 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
222. 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
223. 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.
224. I hope youquot;ve enjoyed the overview of Groovy/Grails and some thoughts
to consider when choosing them
226. But I’ve also been working with Groovy and Grails for almost 2
years and I’m still a happy camper.
227. 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 equot;ective