<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7290642316743338665</id><updated>2012-01-31T04:01:28.906-06:00</updated><category term='ruby'/><category term='mocks'/><category term='math'/><category term='IDEA'/><category term='tools'/><category term='OSGi'/><category term='java'/><category term='books'/><category term='patterns'/><category term='security'/><category term='AutoHotKey'/><category term='typing'/><category term='OCaml'/><category term='lisp'/><category term='event'/><category term='language'/><category term='F#'/><category term='philosophy'/><category term='concurrency'/><category term='flex'/><category term='grails'/><category term='griffon'/><category term='gradle'/><category term='android'/><category term='craft'/><category term='groovy'/><category term='TeamCity'/><category term='devoxx'/><category term='functional'/><category term='unit testing'/><category term='Spring'/><category term='architecture'/><category term='conferences'/><category term='usability'/><category term='Guice'/><category term='recursion'/><title type='text'>behind the times</title><subtitle type='html'>grab the unicorn by the horn and ride to a realm of higher knowledge</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default?start-index=101&amp;max-results=100'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>200</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6796504595336033612</id><published>2012-01-18T07:51:00.002-06:00</published><updated>2012-01-18T07:51:51.674-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>The Best Groovy Inspections You’re Not Using</title><content type='html'>Many, many tools perform static analysis on code. There are all sorts of automated ways to look through your code and tell you if there are likely errors or not. &lt;a href="http://findbugs.sourceforge.net/"&gt;FindBugs&lt;/a&gt;, &lt;a href="http://pmd.sourceforge.net/"&gt;PMD&lt;/a&gt;, and &lt;a href="http://checkstyle.sourceforge.net/"&gt;CheckStyle&lt;/a&gt; are some of the big names from the Java world. On the Groovy side we have two real options: &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt; and &lt;a href="http://codenarc.sourceforge.net/"&gt;CodeNarc&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This post (over on the &lt;a href="http://www.canoo.com/blog/2012/01/18/the-best-groovy-inspections-youre-not-using/"&gt;Canoo Blog&lt;/a&gt;) highlights my favorite static analysis rules for Groovy in IDEA that are not enabled by default. Groovy in IDEA 11 has well over 100 rules, but less than half of them are activated when you install the product. To turn these rules on you’ll need to go into Settings (Ctrl+Alt+S) and enable them under Inspections.&lt;br /&gt;&lt;br /&gt;So surf over to the main post and &lt;a href="http://www.canoo.com/blog/2012/01/18/the-best-groovy-inspections-youre-not-using/"&gt;check it out&lt;/a&gt;. If you want to leave a comment, then do it on the &lt;a href="http://www.dzone.com/links/the_best_groovy_inspections_youre_not_using.html"&gt;DZone page&lt;/a&gt;. I've been turning comments off on the main posts.&lt;br /&gt;&lt;br /&gt;If you like this then you might check out some of my other IDEA related posts: &lt;a href="http://hamletdarcy.blogspot.com/2008/04/10-best-idea-inspections-youre-not.html"&gt;The 10 Best Inspections You’re Not Using (in Java)&lt;/a&gt;, or the IDEA archive on &lt;a href="http://hamletdarcy.blogspot.com/search/label/IDEA"&gt;my blog&lt;/a&gt; and the &lt;a href="http://www.canoo.com/blog/tag/idea/"&gt;Canoo blog&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;And remember if you need Groovy and Grails help, then give me a call or drop me an email at hamlet.darcy@canoo.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6796504595336033612?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6796504595336033612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6796504595336033612' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6796504595336033612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6796504595336033612'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2012/01/best-groovy-inspections-youre-not-using.html' title='The Best Groovy Inspections You’re Not Using'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8693754175716260222</id><published>2012-01-12T07:35:00.001-06:00</published><updated>2012-01-12T07:36:00.035-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android Testing in IntelliJ IDEA</title><content type='html'>Google’s Android site has some fairly detailed instructions for testing Android applications… from Eclipse. They were nice enough to supply a “&lt;a href="http://developer.android.com/guide/developing/testing/testing_otheride.html"&gt;Testing from Other IDEs&lt;/a&gt;” page, but that is nothing more than instructions on using Ant and the command line. Well, if you are using IntelliJ IDEA then you already believe the IDE is going to be a better tool than Ant for this. It’s easy to set up a test project in IDEA and get your tests running. Here are some simple instructions.&lt;br /&gt;&lt;br /&gt;As usual, the &lt;a href="http://www.canoo.com/blog/2012/01/12/android-testing-in-intellij-idea/"&gt;full post&lt;/a&gt; is over on the &lt;a href="http://www.canoo.com/blog/2012/01/12/android-testing-in-intellij-idea/"&gt;Canoo website&lt;/a&gt;. Wanna be cool about it? Upvote it at &lt;a href="http://www.dzone.com/links/android_testing_in_intellij_idea.html"&gt;DZone&lt;/a&gt; or &lt;a href="http://www.reddit.com/r/programming/comments/odvi9/android_testing_in_intellij_idea/"&gt;Reddit&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Thanks for paying attention.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8693754175716260222?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8693754175716260222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8693754175716260222'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2012/01/android-testing-in-intellij-idea.html' title='Android Testing in IntelliJ IDEA'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6676560478149981397</id><published>2011-12-20T03:57:00.002-06:00</published><updated>2011-12-20T03:57:20.250-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>IntelliJ IDEA 11 for the Groovy Developer</title><content type='html'>&lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA 11&lt;/a&gt; was released a few weeks ago, and it contains quite a few new features for the Groovy developer. Everything listed in my blog post is in the free and open source &lt;a href="http://www.jetbrains.com/idea/free_java_ide.html"&gt;Community Edition&lt;/a&gt; of IntelliJ IDEA. There are plenty of new Grails features as well, but I wanted to separate out the Ultimate Edition features into a different post.&lt;br /&gt;&lt;br /&gt;To read the full post, surf on over to the Canoo Blog:&amp;nbsp;&lt;a href="http://www.canoo.com/blog/2011/12/20/intellij-idea-11-for-the-groovy-developer/"&gt;http://www.canoo.com/blog/2011/12/20/intellij-idea-11-for-the-groovy-developer/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And, as usual, you can &lt;a href="http://www.dzone.com/links/intellij_idea_11_for_the_groovy_developer.html"&gt;vote for this thing&lt;/a&gt; over at DZone.&lt;br /&gt;&lt;br /&gt;Thanks everyone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6676560478149981397?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6676560478149981397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6676560478149981397' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6676560478149981397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6676560478149981397'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/12/intellij-idea-11-for-groovy-developer.html' title='IntelliJ IDEA 11 for the Groovy Developer'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1668529993083114530</id><published>2011-12-08T03:09:00.001-06:00</published><updated>2011-12-08T03:11:39.208-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='language'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>The Art of Groovy Command Expressions in DSLs</title><content type='html'>&lt;i&gt;Domain Specific Languages (DSLs) are often littered with the accidental complexity of the host language. Have you ever seen a supposedly “friendly” language expression like “ride(minutes(10)).on(bus).towards(Basel)”. The newest version of Groovy contains a language feature that aims to eliminate the noise of all those extra periods and parenthesis, so that your DSL looks more like “ride 10.minutes on bus towards Basel”. This article shows you step-by-step how to use Groovy Command Expressions and plain old metaprogramming to write just this DSL, and also offers advice on when, and when not, to use this new language feature.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.canoo.com/blog/2011/12/08/the-art-of-groovy-command-expressions-in-dsls/"&gt;full article&lt;/a&gt; is available over on the Canoo Blog:&lt;a href="http://www.canoo.com/blog/2011/12/08/the-art-of-groovy-command-expressions-in-dsls/"&gt; http://www.canoo.com/blog/2011/12/08/the-art-of-groovy-command-expressions-in-dsls/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And of course you can &lt;a href="http://www.dzone.com/links/the_art_of_groovy_command_expressions_in_dsls.html"&gt;upvote in&lt;/a&gt; all the &lt;a href="http://www.reddit.com/r/programming/comments/n4nd3/the_art_of_groovy_command_expressions_in_dsls/"&gt;usual places&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Until next time...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1668529993083114530?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1668529993083114530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1668529993083114530' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1668529993083114530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1668529993083114530'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/12/art-of-groovy-command-expressions-in.html' title='The Art of Groovy Command Expressions in DSLs'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-2442125304275279210</id><published>2011-11-24T13:51:00.001-06:00</published><updated>2011-11-24T13:52:39.066-06:00</updated><title type='text'>Global Day of Code Retreat Comes to Switzerland</title><content type='html'>Next Saturday, 3rd December, Canoo is sponsoring the Swiss installment of the &lt;a href="http://coderetreat.com/global_day.html"&gt;Global Day of Code Retreat&lt;/a&gt;. It's being held in &lt;a href="http://www.juglugano.ch/events/meeting_gdc.html"&gt;Lugano&lt;/a&gt;, which is easily reachable from Switzerland or Northern Italy. The event is free, lunch is provided, and you'll get a chance to practice your programming skills while taking part in a world-wide event that criss-crosses the globe. Sound fun? It will be. Here's what you need to know:&lt;a href="http://www.canoo.com/blog/wp-content/uploads/2011/11/gdcr.png"&gt;&lt;img class="aligncenter size-medium wp-image-2355" title="gdcr" src="http://www.canoo.com/blog/wp-content/uploads/2011/11/gdcr-300x176.png" alt="" width="300" height="176" /&gt;&lt;/a&gt;A code retreat is a day long event where programmers get to practice and hone their craft. The format was created three years ago and has been used and improved regularly since then. During the day we'll use &lt;a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life"&gt;Conway's Game of Life&lt;/a&gt; to practice our design, testing, and pair programming skills. The event has a predefined format and will be facilitated by Canooie &lt;a href="http://twitter.com/hamletdrc"&gt;Hamlet D'Arcy&lt;/a&gt;. This is quite different from our &lt;a href="http://hackergarten.net/"&gt;Hackergartens&lt;/a&gt;, so you may want to read up on the format so you know what to expect. Michael Hunger has an excellent synopsis of &lt;a href="http://www.infoq.com/news/2011/11/global_day_of_code_retreat"&gt;Code Retreat up on the InfoQ&lt;/a&gt; website.The originator of the idea is &lt;a href="http://coderetreat.com/"&gt;Corey Haines&lt;/a&gt; and he will be facilitating the first code retreat of the day in Australia and then flying to Hawaii to also facilitate the last retreat of the day. There is most likely a code retreat in your area, just in case you can't make it to Lugano. Check out the map to see where you can go.&lt;iframe width="640" height="480" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="http://maps.google.com/maps/ms?msid=211858429594081017615.0004b0b076e7ed3148f35&amp;amp;msa=0&amp;amp;ie=UTF8&amp;amp;t=m&amp;amp;vpsrc=6&amp;amp;ll=27.683528,-22.5&amp;amp;spn=166.415629,90&amp;amp;z=1&amp;amp;output=embed"&gt;&lt;/iframe&gt;There are several sponsors for the Code Retreat in Lugano: &lt;a href="http://www.canoo.com/"&gt;Canoo&lt;/a&gt;, &lt;a href="http://www.exmachina.ch/"&gt;Ex Machina&lt;/a&gt;, and &lt;a href="http://www.jetbrains.com/"&gt;JetBrains&lt;/a&gt; to name a few. If you show up then expect to leave with some goodies as well as the free lunch. And please, if you plan on coming then be sure to &lt;a href="http://coderetreat.ning.com/events/global-day-of-code-retreat-in-lugano"&gt;register on the website&lt;/a&gt; so we can provide enough food and coffee.See you Saturday!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-2442125304275279210?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/2442125304275279210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=2442125304275279210' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/2442125304275279210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/2442125304275279210'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/11/global-day-of-code-retreat-comes-to.html' title='Global Day of Code Retreat Comes to Switzerland'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8937947815567893872</id><published>2011-10-21T06:41:00.000-05:00</published><updated>2011-10-21T06:41:30.743-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android and IDEA for the Eclipse Refugee</title><content type='html'>&lt;p&gt;For the full article jump to: &lt;a href="http://www.canoo.com/blog/2011/10/18/android-and-idea-for-the-eclipse-refugee/"&gt;http://www.canoo.com/blog&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;p&gt;Earlier this month I switched from writing my Android projects in &lt;a href="http://developer.android.com/sdk/eclipse-adt.html"&gt;Eclipse&lt;/a&gt; to writing them in &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt;. Overall the experience has been great, and I much prefer using IDEA to Eclipse for Android development. And now that &lt;a href="http://confluence.jetbrains.net/display/IDEADEV/IDEA+11+EAP"&gt;IntelliJ IDEA 11 EAP (Early Access)&lt;/a&gt; has a visual layout window, there is almost no reason for me to write my Android apps in anything else. I wrote this post to help other users along their way when converting between the IDEs. &lt;/p&gt;&lt;br/&gt;&lt;p&gt;The full article with all the screenshot glory is over on the &lt;a href="http://www.canoo.com/blog/2011/10/18/android-and-idea-for-the-eclipse-refugee/"&gt;Canoo Blog&lt;/a&gt;&lt;/p&gt;&lt;br/&gt;&lt;p&gt;If you want to be a bro and slip me an upvote, then please do: &lt;a href="http://news.ycombinator.com/item?id=3125747"&gt;Hackernews&lt;/a&gt;, &lt;a href="http://www.reddit.com/r/programming/comments/lgebd/android_and_idea_for_the_eclipse_refugee/"&gt;Reddit&lt;/a&gt;, or &lt;a href="http://www.dzone.com/links/android_and_idea_for_the_eclipse_refugee.html"&gt;DZone&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8937947815567893872?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8937947815567893872/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8937947815567893872' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8937947815567893872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8937947815567893872'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/10/android-and-idea-for-eclipse-refugee.html' title='Android and IDEA for the Eclipse Refugee'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-5890892655425467237</id><published>2011-08-01T23:21:00.009-05:00</published><updated>2011-08-02T11:08:37.467-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='typing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Should Static Type-Checked Compilation Come to Groovy?</title><content type='html'>Please note: As always, I speak for myself alone and not as a representative for any project or company. These are my opinions and reading of an ever-changing situation.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Update: This was a pretty stupid thing to post, because everything is in flux and these are just some thoughts.&lt;br /&gt;  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Why Should Groovy have a Static Mode? &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;There were some internal discussions about "Grumpy mode" among some of the Groovy committers. I had a lot of reservations about introducing static-typing or static-mode into Groovy. When I thought about the idea I come up with many unanswerable questions. Is it a good idea or not? Only time will tell. Here are some of the questions that I wish I had answers to.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What exactly do users want?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Do people want a static language with a dynamic backdoor, such as the way &lt;a href="http://msdn.microsoft.com/en-us/library/dd264736.aspx"&gt;C#/.NET has a dynamic keyword&lt;/a&gt; or the way you can use Groovy++ by default with the .gpp file extension and then sprinkle in @Dynamic annotations? This is one approach, where the core of your language is statically typed but you have an option to escape into dynamic-land. Or do people want a dynamic language with a static backdoor, which Groovy will be (as far as I know) one of the few examples of. This use case is the same as adding an @Typed keyword to your Groovy code to enable static compilation, or adding an @Grumpy keyword. Or do people just want better performance from Groovy, end of story?&lt;br /&gt;&lt;br /&gt;If you want a statically typed language without the verbosity of Java then use &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt;. Yes, Scala is complex. But Groovy is just as complex. Does anyone really know Groovy without reading a few books? Yes you can get things done, but understanding metaprogramming, understanding method dispatch, and understanding all the closure options (delegates, delegate-first, trampoline) is just as complex. I am excited about &lt;a href="http://confluence.jetbrains.net/display/Kotlin/Welcome"&gt;Kotlin&lt;/a&gt; and think it looks like a great statically-typed language, but at this point it is nothing more than a slidedeck and a wiki for anyone that isn't on the IntelliJ IDEA development team. It's not available to anyone.&lt;br /&gt;&lt;br /&gt;I honestly don't think a Grumpy mode will boost my productivity much. Will it aide in language adoption? I say probably not. In my opinion there are three large barriers to Groovy adoption in the mainstream: performance, tooling, and bugs. Not being statically typed is a connoisseurs criticism, and connoisseurs generally chase after things that are interesting rather than good (it's been said about me as well). Groovy is a language that appeals to people that just want to get something done; it's about productivity not about programming language theory. Adding static typing might please some high-end connoisseurs if it is done in a good way, but I have trouble believing it will please many real users. Search the web for "Groovy sucks". You won't find pages about dynamic type systems, you'll find performance benchmarks. In my personal experience, people I talk to about Groovy++ are asking about performance. Sure, traits are clever. Sure, the type-checking is an interesting idea. But the interest is in performance. &lt;a href="http://groovy.dzone.com/users/alext"&gt;Alex's blog posts&lt;/a&gt; are mostly about x-thousand transactions per second, or beating Scala performance. I think the number 1 priority of Groovy++ is performance, and type checking is a 2nd nice to have benefit.&lt;br /&gt;&lt;br /&gt;And what about people that want a static language with a dynamic backdoor (for builder objects perhaps)? Other languages have this. C# has a "dynamic" variable, right? Boo has a dynamic variable as well, and even lowly Flex has dynamic XML support. This is useful and valuable. I would love to see an @Groovy annotation in Java, where you escape from Java into Groovy, rather than an @Grumpy annotation for Groovy. The benefit of @Groovy for Java is that tool support is the best in the world (without a doubt) and the language has a specification, is well known, and is well tested. Of course, an @Groovy annotation would only ever work with core Java language grammar changes or very ugly hacks.&lt;br /&gt;&lt;br /&gt;Lastly, do users just want static compile-time typing for tooling support to catch silly errors as early as possible? Well yes they want that. Who wouldn't? But who is writing Groovy code without testing it? And we already do a great job of recommending suggestions when methods fail ("hashode not found. Did you mean hashcode()"). And the tools exist to do this. &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt; is very reliable in this regard and &lt;a href="http://www.groovylint.com/"&gt;GroovyLint&lt;/a&gt; does the same thing on a limited scale. These features exist today but since they aren't in Eclipse by default then I suspect they are underused. Catching silly errors is entirely possible without the burden of static typing. In fact, some might say that the majority of &lt;a href="http://codenarc.sourceforge.net/"&gt;CodeNarc&lt;/a&gt; errors fall into the silly category!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Can Groovy Afford the Complexity?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The Java world talks about a "complexity budget" where a language can only absorb so much complexity before developers leave for something simpler. The term "complexity budget" is poorly defined and often used as a scare tactic in hyperbolic arguments, but I often fear that Groovy could become the next C++ and overrun this arbitrary "complexity budget". C is a good and simple language. Java is a good and simple language. Neither C nor Java are good for all tasks, but they are both successful and capable of having system written in them. C++ started building on C and had every feature known to man added. Nowadays the criticism of C++ is that only 20% is safe to use, but no two C++ programmers can agree on which 20%. Groovy is a multi-paradigm language. You can script, you can OO, and you can FP. Already I am advising teams to find their standard. If you like FP then embrace curry, trampoline, and functions. If you don't then steer clear of those features. Adding a static mode is going to make Groovy more complex. The same code will most likely behave differently between Grumpy mode and not Gumpy. This is one more thing to think about when programming, even if we work to minimize the differences.&lt;br /&gt;&lt;br /&gt;Looking at Groovy++, they have done some very cool things. But sometimes the basic features of Groovy++ and Groovy differ, and this cannot be allowed to happen because it is too complex. Already Groovy developers need to know Java and the JVM. I don't know how you could us Groovy outside of Grails without knowing Java. Introducing a new mode that is subtly different could be too much complexity.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Time and Budget Trade-offs &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Adding static-mode seems to me like a big undertaking in terms of developer hours. Groovy++ is a good proof of concept for the idea, but the implementation won't be merged into core-groovy. The approach used by Groovy++ is to subclass ASTNodes with AST Transformations and then write out different bytecode for the node, fighting with groovyc to make sure the correct node is invoked. It is better to implement this feature as a part of the core compiler than as an AST transformation, and that is the route the team are currently taking.&lt;br /&gt;&lt;br /&gt;It is wonderful that VMWare supports Groovy financially by giving several people jobs. But remember there are finite resources for the project. Any time spent on static-mode means there is less time spent on other features. There aren't enough hours in the day to do everything. So developing a high-performing and well-behaving @Grumpy mode means there are less resources to solve the performance problems of plain old Groovy. I already asserted that performance was a big barrier to wider adoption. Optimized ints are good for benchmarks and came out in Groovy 1.8, but I reckon most method calls are on user defined objects. How many ints are used in a Grails app? Maybe there is a way to do everything at once, but I'm a little sad to see performance improvements not come faster to the language.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;My Wishlist&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Here is my wishlist of what @Grumpy would do for me and how the feature should roll out.&lt;br /&gt;&lt;br /&gt;Some social wishes...&lt;br /&gt;&lt;br /&gt;&lt;div&gt;* GEP - The GEP process for Groovy enhancements is supposed to help us formalize features and provide feedback, but it's underused. Please, let's start a GEP as soon as possible and move this big change into the public debate.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;* Dev-List Discussion - The dev-list exists to give developers a forum to communicate with each other. There will always be internal conference calls and IM Chats as well, but please lets move more discussion back into the public domain.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Research - Are there any other dynamic languages with Static backdoor that we learn from them? I don't know of one, but would love to see more examples of what works and what doesn't&lt;br /&gt;&lt;br /&gt;Some type inference and static typing wishes...&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Closure Return Type Type-Inference - Closures should have their return type inferred. This is non trivial, and you can have closures that return the values of closure.apply(). At some point type inference breaks. Where will Groovy's fail? How far will the type inferrer go? And how will you specify a return type on a closure when it does fail?&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Closure Arity - The type checker should check the number of parameters a closure has. You should not be able to pass a one method closure to something like Collection.inject() that requires two parameters. All closures need to specify at their type declaration how many parameters it takes.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Closure Parameter Types - The parameter types of a closure should be type checked. You shouldn't be able to pass a closure that takes a String argument to something that requires a closure that takes an Event argument. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;* Closure casting to interfaces - When you cast a Closure into a Single-Method-Interface then the arity, return type, and parameter types should all be checked and verified.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Interfaces Implemented as a Map - When you implement an interface using the Map notation [ methodName: { /* body */ } ] then the closure arity, parameter types, and return type should be checked, and the compiler should make sure all interface methods are implemented.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* curry/ncurry type issues- Functions like curry, lCurry, rCurry, and nCurry should work in a correct, statically-typed way. For example, if you curry of a 2-arg closure then you're returned a 1-arg closure. Curry a 4-arg closure and you're returned a 3-arg closure. This is a fun edge case that can't be implemented with just overloaded methods!&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Calling groovy from Java - The semantics for calling Grumpy Groovy from Java must remain sane. I'm interested to see some examples of what the APIs look like once all the new types are added. For instance, what is the Closure class hierarchy? Will there be Closure0, Closure1, Closure2 types to model the arity of closures?&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* A Grumpy GDK - All of the libraries that ship with Groovy should be as Grumpy as possible. That way a Grumpy developer never has a problem just because a Groovy GDK method was not Grumpy as well. For instance, you should be able to easily make a Grumpy subclass of GroovyTestCase, so any dynamic method on GroovyTestCase should be updated to be as static as possible. Only really use dynamic features when they are necessary.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Generic by Default - The type inference mechanism should create the correct generics for methods, similar to how F#/Ocaml creates generic methods by default. For instance, the closure: def wrap = { println "logging..."; it() }  should have a generic type signature that returns the same type that the 'it' parameter returns.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* AST Transforms Can Read Types - Transforms should be easily able to read the type information out of the AST, and it should be there as early as possible in the compilation process. So the type inference should happen early. The types don't need to be checked early, but they need to be inferred early. Also, when the type of an object is unknown then an AST transformation should be able to read this. Currently, an unknown type is Object to Groovy, but there should be a difference between Object and Unknown.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* AST Transforms Can Write Types - Transforms should be able to write type information. Transforms should be able to participate fully in this process if they are to remain powerful and flexible.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;* Type Verification Happens at the End - Type checking and verification should occur at the end of all the compiler phases. This enables AST transforms to actively participate in the type inferring and type specifying process. If type verification runs and fails too early then transforms that could fix the problem won't have a chance to run&lt;/div&gt;&lt;div&gt;&lt;br /&gt;So that is my wishlist, perhaps it is a connoisseur's wishlist. What is it that you want to see in Grumpy mode? What do you not want to see?&lt;br /&gt;&lt;br /&gt;You can leave feedback here are on the Groovy dev mailing list. We'll see where this goes! &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-5890892655425467237?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/5890892655425467237/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=5890892655425467237' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5890892655425467237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5890892655425467237'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/08/static-type-checked-compilation-is.html' title='Should Static Type-Checked Compilation Come to Groovy?'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6343854739905176530</id><published>2011-07-14T14:46:00.003-05:00</published><updated>2011-07-14T14:56:45.853-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Java 7 Small Language Changes Screencast</title><content type='html'>&lt;p&gt;This screencast demonstrates the &lt;a href="http://openjdk.java.net/projects/coin/"&gt;small language changes&lt;/a&gt; that are part of &lt;a href="http://openjdk.java.net/"&gt;Open JDK 7&lt;/a&gt;, which is available from the Open JDK website. It demonstrates multi-catch, try with resources, strings in switch statements, underscores in literals, and the diamond operator.&lt;/p&gt;&lt;p&gt;If you have any issues watching the video below, then you may have better luck viewing it on the &lt;a href="http://tv.jetbrains.net/videocontent/java-7-small-language-changes"&gt;JetBrains.tv&lt;/a&gt; site. &lt;/p&gt;&lt;object width="400" height="300" id="_ipad" data="http://tv.jetbrains.net/flowplayer/flowplayer-3.2.7.swf" type="application/x-shockwave-flash"&gt;&lt;param name="movie" value="http://tv.jetbrains.net/flowplayer/flowplayer-3.2.7.swf" /&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="flashvars" value='config={"clip":{"scaling":"orig","autoPlay":false,"autoBuffering":true,"url":"/sites/default/files/videos/converted/projectcoin.mp4"},"plugins":{"controls":{"stop":true}},"playlist":[{"scaling":"orig","autoPlay":false,"autoBuffering":true,"url":"http://tv.jetbrains.net/sites/default/files/videos/converted/projectcoin.mp4"}]}' /&gt;&lt;/object&gt;&lt;p&gt;I've made a lot of screencasts and blog posts over the years. If you like this, then there are many ways to see the other stuff I've done:&amp;nbsp;&lt;/p&gt;&lt;ul&gt;    &lt;li&gt;My main blog:&amp;nbsp;&lt;a href="http://hamletdarcy.blogspot.com"&gt;http://hamletdarcy.blogspot.com&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;My other JetBrains.tv posts:&amp;nbsp;&lt;a href="http://tv.jetbrains.net/tags/hamlet"&gt;http://tv.jetbrains.net/tags/hamlet&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;IDEA&amp;nbsp;related posts on my blog:&amp;nbsp;&lt;a href="http://hamletdarcy.blogspot.com/search/label/IDEA"&gt;http://hamletdarcy.blogspot.com/search/label/IDEA&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;My screencasts on YouTube:&amp;nbsp;&lt;a href="http://www.youtube.com/user/HamletDRC"&gt;http://www.youtube.com/user/HamletDRC&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;IDEA related Posts on my work blog:&amp;nbsp;&lt;a href="http://www.canoo.com/blog/tag/idea/"&gt;http://www.canoo.com/blog/tag/idea/&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Or follow me on Twitter:&amp;nbsp;&lt;a href="http://twitter.com/hamletdrc"&gt;@HamletDRC&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The screencast was created with Ubuntu 10.04, PiTiVi, Audicity, gtk-RecordMyDesktop, IntelliJ IDEA, and LibreOffice. OS from top to bottom.&lt;/p&gt;&lt;p&gt;Thanks for watching, leave a comment, or upvote it at your &lt;a href="http://www.dzone.com/links/java_7_language_changes_screencast.html"&gt;favorite link site&lt;/a&gt;! &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6343854739905176530?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6343854739905176530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6343854739905176530' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6343854739905176530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6343854739905176530'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/07/java-7-small-language-changes.html' title='Java 7 Small Language Changes Screencast'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1131743317466123876</id><published>2011-07-12T18:50:00.002-05:00</published><updated>2011-07-12T18:54:41.141-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Mock Objects with Spock Screencast</title><content type='html'>&lt;p&gt;This screencast demonstrates how to use &lt;a href="http://code.google.com/p/spock/"&gt;Spock testing&lt;/a&gt; specifications and Groovy for mocking and stubbing behavior in unit tests. It covers creating the mock object syntax, setting expectations, verifying and spying on results, and argument matchers.&lt;/p&gt;&lt;p&gt;If you have any issues with video playback, then trying viewing it from the &lt;a href="http://tv.jetbrains.net/videocontent/spock-and-mock-object-basics"&gt;JBrains.tv website&lt;/a&gt;&lt;/p&gt;&lt;object width="400" height="300" id="_ipad" data="http://tv.jetbrains.net/flowplayer/flowplayer-3.2.7.swf" type="application/x-shockwave-flash"&gt;&lt;param name="movie" value="http://tv.jetbrains.net/flowplayer/flowplayer-3.2.7.swf" /&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="flashvars" value='config={"clip":{"scaling":"orig","autoPlay":false,"autoBuffering":true,"url":"/sites/default/files/videos/converted/spockmocking.mp4"},"plugins":{"controls":{"stop":true}},"playlist":[{"scaling":"orig","autoPlay":false,"autoBuffering":true,"url":"http://tv.jetbrains.net/sites/default/files/videos/converted/spockmocking.mp4"}]}' /&gt;&lt;/object&gt;&lt;p&gt;Here are some useful links to read for this webcast:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Spock Framework - &lt;a href="http://code.google.com/p/spock/"&gt;http://code.google.com/p/spock/ &lt;/a&gt;&lt;/li&gt;&lt;li&gt;Spock Basics Screencast: &lt;a href="http://tv.jetbrains.net/videocontent/ffff"&gt;http://tv.jetbrains.net/videocontent/ffff &lt;/a&gt;&lt;/li&gt;&lt;li&gt;Mocks and Stubs aren't Spies: &lt;a href="http://hamletdarcy.blogspot.com/2007/10/mocks-and-stubs-arent-spies.html"&gt;http://hamletdarcy.blogspot.com/2007/10/mocks-and-stubs-arent-spies.html &lt;/a&gt;&lt;/li&gt;&lt;li&gt;Mocking with Spocks: &lt;a href="http://www.canoo.com/blog/2010/04/20/spock-and-test-spies-a-logical-choice/"&gt;http://www.canoo.com/blog/2010/04/20/spock-and-test-spies-a-logical-choice/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I've made a lot of screencasts and blog posts over the years. If you like this, then there are many ways to see the other stuff I've done: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;My main blog: &lt;a href="http://hamletdarcy.blogspot.com/"&gt;http://hamletdarcy.blogspot.com&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;My other JetBrains.tv posts: &lt;a href="http://tv.jetbrains.net/tags/hamlet"&gt;http://tv.jetbrains.net/tags/hamlet&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;IDEA related posts on my blog: &lt;a href="http://hamletdarcy.blogspot.com/search/label/IDEA"&gt;http://hamletdarcy.blogspot.com/search/label/IDEA&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;My screencasts on YouTube: &lt;a href="http://www.youtube.com/user/HamletDRC"&gt;http://www.youtube.com/user/HamletDRC&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;IDEA related Posts on my work blog: &lt;a href="http://www.canoo.com/blog/tag/idea/"&gt;http://www.canoo.com/blog/tag/idea/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Or follow me on Twitter: &lt;a href="http://twitter.com/hamletdrc"&gt;@HamletDRC&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Phew, that's a lot of self-promotion :)&lt;/p&gt;&lt;p&gt;The screencast was created with Ubuntu 10.04, PiTiVi, Audicity, gtk-RecordMyDesktop, IntelliJ IDEA, and LibreOffice. OS from top to bottom.&lt;/p&gt;&lt;p&gt;Thanks for watching, and leave a comment! &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1131743317466123876?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1131743317466123876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1131743317466123876' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1131743317466123876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1131743317466123876'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/07/mock-objects-with-spock-screencast.html' title='Mock Objects with Spock Screencast'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-5466557701321704238</id><published>2011-07-11T15:11:00.001-05:00</published><updated>2011-07-11T15:11:33.393-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Grails Podcast Interview with Hamlet D'Arcy</title><content type='html'>Last week I sat down with the gang at the &lt;a href="http://www.grailspodcast.com/"&gt;Grails Podcast&lt;/a&gt; and talked shop for about 45 minutes. We talked about a lot of different topics such as Groovy, Lean software, Spock, Groovy in Action, and of course Hackergarten. Check out the full audio and shownotes over at &lt;a href="http://www.grailspodcast.com/blog/id/247"&gt;Grails Podcast Episode 125&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-5466557701321704238?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/5466557701321704238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=5466557701321704238' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5466557701321704238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5466557701321704238'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/07/grails-podcast-interview-with-hamlet.html' title='Grails Podcast Interview with Hamlet D&apos;Arcy'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6754030648015608422</id><published>2011-05-23T09:00:00.002-05:00</published><updated>2011-05-23T09:08:39.942-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>IntelliJ IDEA 10.5 for the Groovy and Grails Developer</title><content type='html'>The formal release of &lt;a href="http://www.jetbrains.com/idea/whatsnew/"&gt;IntelliJ IDEA 10.5&lt;/a&gt; came out this month, and the new Groovy features are all part of the free and open source Community Edition, and the Grails features are part of the Ultimate Edition. IDEA X (or 10 to you non-Romans) was a larger release of the product, and I already blogged about &lt;a href="http://www.canoo.com/blog/2010/12/20/intellij-idea-x-for-groovy-developers/"&gt;IDEA X for Groovy&lt;/a&gt; and &lt;a href="http://www.canoo.com/blog/2010/12/23/idea-x-for-the-grails-developer/"&gt;IDEA X for Grails&lt;/a&gt;. There’s still plenty of nice features in 10.5 though. The prices for IDEA recently dropped between $100 and $50, and anyone purchasing IDEA since last November gets 10.5 as a free upgrade.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can read the full article detailing &lt;a href="http://www.canoo.com/blog/2011/05/23/intellij-idea-10-5-for-the-groovy-and-grails-developer/"&gt;my overview of the features&lt;/a&gt; over on &lt;a href="http://www.canoo.com/blog/2011/05/23/intellij-idea-10-5-for-the-groovy-and-grails-developer/"&gt;the Canoo blog&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There is also a whole bunch of other IDEA related content on &lt;a href="http://hamletdarcy.blogspot.com/search/label/IDEA"&gt;my own blog&lt;/a&gt; and on &lt;a href="http://www.canoo.com/blog/tag/idea/"&gt;the Canoo blog&lt;/a&gt;. And if you're feeling promotional, you can always &lt;a href="http://www.dzone.com/links/intellij_idea_105_for_the_groovy_and_grails_devel.html"&gt;upvote at DZone&lt;/a&gt;. Enjoy. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6754030648015608422?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6754030648015608422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6754030648015608422' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6754030648015608422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6754030648015608422'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/05/intellij-idea-105-for-groovy-and-grails.html' title='IntelliJ IDEA 10.5 for the Groovy and Grails Developer'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6517918989785885946</id><published>2011-05-06T06:25:00.001-05:00</published><updated>2011-05-06T06:28:56.006-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><title type='text'>IntelliJ IDEA Keyboard Stickers</title><content type='html'>&lt;p&gt;They finally arrived: &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt; keyboard stickers!&lt;/p&gt;        &lt;p&gt;Inspired by the &lt;a href="http://www.4keyboard.com/viandvimeditorkeyboardsticker-p-350.html"&gt;Vi Keyboard Stickers&lt;/a&gt;, I've been working with JetBrains over the last couple weeks to create keyboard stickers to remind users (and myself) of the most common IDE shortcuts. Here are the stickers applied to my keyboard: &lt;/p&gt;        &lt;a href="http://www.hackergarten.net/images/2011/keyboard.jpg"&gt;&lt;img width="600px" src="http://www.hackergarten.net/images/2011/keyboard.jpg" alt="keyboard" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Do you see the subliminal advertising? No really, my business card always sits by my monitor like that.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, the keys and modifiers are color coded. Blue is control, red underline is Shift. So then the F9 key has the word "Compile" with a blue background and a red underline, it means that Ctrl+Shift+F9 is the shortcut for Compile.&lt;br /&gt;&lt;br /&gt;       &lt;a href="http://www.hackergarten.net/images/2011/sticker.jpg"&gt;&lt;img width="600px" src="http://www.hackergarten.net/images/2011/sticker.jpg" alt="sticker" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had to trim a few of the stickers for my Swiss keyboard (the Shift key is much smaller for instance), but otherwise the stickers adhere well and don't come up. I hand wrote all the Shift-values for the numbers, so that I can remember that Shift-3 is the * character (again, good for non-US keyboards). Also, there are one or two stickers that may not apply to non-US keyboards (I can't type Shift+[ for instance).&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Remember to be extra careful when applying the stickers. Overlapping on the upper edge tends to catch your fingers, so either center them exactly or err on the side of bottom edge overlaps. And one last errata: the sticker for space is labeled "Backspace". This was my fault, but you can take a pen and scratch out the work "back". Viola, fixed.&lt;br /&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/div&gt;&lt;div&gt;Would you like a copy of the stickers for yourself? I have a giant stack of them and so does JetBrains. Here are some ideas on getting them from me, based on location:&lt;br /&gt;&lt;ul&gt;            &lt;li&gt;Near &lt;strong&gt;Switzerland&lt;/strong&gt;? Come to a &lt;a href="http://www.hackergarten.net/"&gt;Hackergarten&lt;/a&gt; in Basel or just DM me (&lt;a href="http://twitter.com/hamletdrc"&gt;@HamletDRC&lt;/a&gt;)&lt;/li&gt;            &lt;li&gt;&lt;strong&gt;Denmark?&lt;/strong&gt; I'll be at GR8 Conf May 17th to 19th&lt;/li&gt;            &lt;li&gt;&lt;b&gt;Poland&lt;/b&gt;? I'll be at GeeCON in Krakow next week&lt;/li&gt;            &lt;li&gt;In the &lt;b&gt;US&lt;/b&gt;? I'll soon be in New York and Salt Lake City for &lt;a href="http://www.nofluffjuststuff.com/"&gt;No Fluff&lt;/a&gt;, Denver for &lt;a href="http://uberconf.com/"&gt;ÜberConf&lt;/a&gt;, and Minneapolis for &lt;a href="http://www.gr8conf.us/"&gt;GR8 in the US&lt;/a&gt;&lt;/li&gt;            &lt;li&gt;&lt;b&gt;Spain&lt;/b&gt;? I'll be at &lt;a href="http://twitter.com/greach_es"&gt;Greach&lt;/a&gt; in Madrid in November&lt;/li&gt;            &lt;li&gt;Anywhere else in &lt;b&gt;Europe&lt;/b&gt;?&lt;/li&gt; Invite me to give a talk at your company! I am happy to jump on a plane and visit almost&lt;a href="http://www.blogger.com/post-create.g?blogID=7290642316743338665#star1"&gt;*&lt;/a&gt; anywhere. I can do IntelliJ IDEA specific &lt;a href="http://dl.dropbox.com/u/138156/StaticAnalysisInIDEA.pdf"&gt;talks and training&lt;/a&gt;, as well as any of the &lt;a href="http://www.nofluffjuststuff.com/conference/speaker/hamlet_d'archy"&gt;Java, Groovy, or Agile talks listed here&lt;/a&gt;. Invite me, and I'll see what I can do.&lt;br /&gt;       &lt;/ul&gt;        &lt;a name="star1"&gt;*&lt;/a&gt; I am no longer legally able to visit Barneveld in the Netherlands. &lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6517918989785885946?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6517918989785885946/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6517918989785885946' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6517918989785885946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6517918989785885946'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/05/intellij-idea-keyboard-stickers.html' title='IntelliJ IDEA Keyboard Stickers'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3732887530033076700</id><published>2011-04-15T10:58:00.002-05:00</published><updated>2011-04-15T11:01:53.068-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Getting Started with Spock and Groovy</title><content type='html'>&lt;p&gt;This screencast demonstrates how to create Spock testing specifications. It covers creating basic when/then blocks, given/when/then blocks, expect/where blocks, and data tables. It explains how to create Spock file templates and Spock Live Templates for IDEA.&lt;/p&gt;&lt;p&gt;If there are any playback issues then you might try watching it from the &lt;a href="http://tv.jetbrains.net/videocontent/getting-started-with-spock-and-groovy"&gt;JetBrains.tv site&lt;/a&gt;. &lt;/p&gt;&lt;br /&gt;&lt;object width="400" height="300" id="_player" name="_player" data="http://tv.jetbrains.net/sites/default/files/flowplayer3/flowplayer-3.2.2.swf" type="application/x-shockwave-flash"&gt;&lt;param name="movie" value="http://tv.jetbrains.net/sites/default/files/flowplayer3/flowplayer-3.2.2.swf"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;param name="flashvars" value="config={&amp;quot;clip&amp;quot;:{&amp;quot;baseUrl&amp;quot;:&amp;quot;http://tv.jetbrains.net&amp;quot;,&amp;quot;scaling&amp;quot;:&amp;quot;orig&amp;quot;,&amp;quot;autoPlay&amp;quot;:false,&amp;quot;autoBuffering&amp;quot;:true,&amp;quot;url&amp;quot;:&amp;quot;sites/default/files/videos/converted/spock.flv&amp;quot;},&amp;quot;plugins&amp;quot;:{&amp;quot;controls&amp;quot;:{&amp;quot;stop&amp;quot;:true}},&amp;quot;playlist&amp;quot;:[{&amp;quot;baseUrl&amp;quot;:&amp;quot;http://tv.jetbrains.net&amp;quot;,&amp;quot;scaling&amp;quot;:&amp;quot;orig&amp;quot;,&amp;quot;autoPlay&amp;quot;:false,&amp;quot;autoBuffering&amp;quot;:true,&amp;quot;url&amp;quot;:&amp;quot;http://tv.jetbrains.net/sites/default/files/videos/converted/spock.flv&amp;quot;}]}"&gt;&lt;/object&gt;&lt;br /&gt;&lt;p&gt;Here are some useful links to read for this webcast:&lt;/p&gt;&lt;ul&gt;    &lt;li&gt;Spock Framework - &lt;a href="http://code.google.com/p/spock/"&gt;http://code.google.com/p/spock/&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;IDEA File Templates - &lt;a href="http://www.jetbrains.com/idea/webhelp/file-templates.html"&gt;http://www.jetbrains.com/idea/webhelp/file-templates.html&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;IDEA Live Templates - &lt;a href="http://www.jetbrains.com/idea/webhelp/live-templates.html"&gt;http://www.jetbrains.com/idea/webhelp/live-templates.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To work with Spock, I use one file template and three live templates. &lt;/p&gt;&lt;p&gt;My file template creates a Spock Specification with the correct java package and javadoc: &lt;/p&gt;&lt;p&gt;&lt;a href="http://hackergarten.net/images/2011/filetemplate.png"&gt;&lt;img alt="idea file template" width="450" height="253" src="http://hackergarten.net/images/2011/filetemplate.png" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The text of the template is:&lt;/p&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end&lt;br /&gt;&lt;br /&gt;import spock.lang.Specification&lt;br /&gt;&lt;br /&gt;#parse("File Header.java")&lt;br /&gt;class ${NAME} extends Specification {&lt;br /&gt;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;My first Live Template is the when-then template: &lt;/p&gt;&lt;p&gt;&lt;a href="http://hackergarten.net/images/2011/whenthentemplate.png"&gt;&lt;img alt="when then" width="350" height="401" src="http://hackergarten.net/images/2011/whenthentemplate.png" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The text of the template is:&lt;/p&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def "$NAME$"() {&lt;br /&gt;  when:&lt;br /&gt;  $END$&lt;br /&gt;&lt;br /&gt;  then:&lt;br /&gt;  true&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The second template is the given/when/then template: &lt;/p&gt;&lt;p&gt;&lt;a href="http://hackergarten.net/images/2011/givenwhenthentemplate.png"&gt;&lt;img alt="given when then template" width="350" height="438" src="http://hackergarten.net/images/2011/givenwhenthentemplate.png" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The text of the template is:&lt;/p&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def "$NAME$"() {&lt;br /&gt;  given:&lt;br /&gt;  $END$&lt;br /&gt;&lt;br /&gt;  when:&lt;br /&gt;  // TODO: add when&lt;br /&gt;&lt;br /&gt;  then:&lt;br /&gt;  true&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The last template is the expect/where template: &lt;/p&gt;&lt;p&gt;&lt;a href="http://hackergarten.net/images/2011/expectwheretemplate.png"&gt;&lt;img width="350" height="401" alt="" src="http://hackergarten.net/images/2011/expectwheretemplate.png" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The text of the template is:&lt;/p&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def "$NAME$"() {&lt;br /&gt;  expect:&lt;br /&gt;  $END$&lt;br /&gt;&lt;br /&gt;  where:&lt;br /&gt;  // TODO add where block&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I've made a lot of screencasts and blog posts over the years. If you like this, then there are many ways to see the other stuff I've done: &lt;/p&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;My main blog: &lt;a href="http://hamletdarcy.blogspot.com/"&gt;http://hamletdarcy.blogspot.com&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;My other JetBrains.tv posts: &lt;a href="http://tv.jetbrains.net/tags/hamlet"&gt;http://tv.jetbrains.net/tags/hamlet&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;IDEA related posts on my blog: &lt;a href="http://hamletdarcy.blogspot.com/search/label/IDEA"&gt;http://hamletdarcy.blogspot.com/search/label/IDEA&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;My screencasts on YouTube: &lt;a href="http://www.youtube.com/user/HamletDRC"&gt;http://www.youtube.com/user/HamletDRC&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;IDEA related Posts on my work blog: &lt;a href="http://www.canoo.com/blog/tag/idea/"&gt;http://www.canoo.com/blog/tag/idea/&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;Or follow me on Twitter: &lt;a href="http://twitter.com/hamletdrc"&gt;@HamletDRC&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Phew, that's a lot of self-promotion :)&lt;/p&gt;&lt;p&gt;Thanks for watching, and leave a comment! &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3732887530033076700?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3732887530033076700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3732887530033076700' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3732887530033076700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3732887530033076700'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/04/getting-started-with-spock-and-groovy.html' title='Getting Started with Spock and Groovy'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-7880400153276688391</id><published>2011-04-01T01:50:00.004-05:00</published><updated>2011-04-01T01:57:46.177-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><title type='text'>New in IntelliJ IDEA 10.5: Less Clutter</title><content type='html'>&lt;a href="http://imgur.com/t4RlV" title="Hosted by imgur.com"&gt;&lt;img src="http://i.imgur.com/t4RlV.png" width="420px" title="Hosted by imgur.com" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-7880400153276688391?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/7880400153276688391/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=7880400153276688391' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7880400153276688391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7880400153276688391'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/04/new-in-intellij-idea-105-less-clutter.html' title='New in IntelliJ IDEA 10.5: Less Clutter'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8678390258144140344</id><published>2011-03-31T04:45:00.003-05:00</published><updated>2011-03-31T04:54:03.083-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Interview with Antonio Goncalves about the past, present, and future of Java EE</title><content type='html'>I got a chance to sit down and talk to Java Champion &lt;a href="http://www.antoniogoncalves.org/"&gt;Antonio Goncalves&lt;/a&gt; about the past, present, and future of Java EE. I've been working for the last six months in a heavy EE/SOA stack, and it's been interesting to see the advantages and disadvantages. I definitely come from the other side of the world where specifications aren't seen as an inherent sign of quality, and frameworks not sanctioned by Sun/Oracle are not to be feared. It was fun to get his opinions about this stuff.&lt;br /&gt;&lt;br /&gt;The full interview is on the &lt;a href="http://jetbrains.dzone.com/articles/java-champion-antonio"&gt;JetBrains Zone at DZone&lt;/a&gt;. We're both JetBrains Academy Members and we're slowly interviewing each other.&lt;br /&gt;&lt;br /&gt;P.S. This is the first post I've ever made that mentioned Java Enterprise Edition. I suspect the next time EE is mentioned will be in another few years :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8678390258144140344?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8678390258144140344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8678390258144140344' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8678390258144140344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8678390258144140344'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/03/interview-with-antonio-goncalves-about.html' title='Interview with Antonio Goncalves about the past, present, and future of Java EE'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8328426278566071102</id><published>2011-03-29T04:13:00.000-05:00</published><updated>2011-03-29T04:15:24.125-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><title type='text'>IntelliJ IDEA Static Analysis: Custom Rules with Structural Search &amp; Replace</title><content type='html'>Well, well, I made another screencast. This time I'm taking on IntelliJ IDEA code inspections, and writing your own static code analysis rule (and quick fix!) using Structural Search &amp;amp; Replace. Not bad for under 5 minutes.&lt;br /&gt;&lt;br /&gt;If you have any trouble viewing the video then perhaps you should watch it directly on the &lt;a href="http://tv.jetbrains.net/videocontent/intellij-idea-static-analysis-custom-rules-with-structural-search-replace"&gt;JetBrains site&lt;/a&gt;. And if you're feeling generous, then &lt;a href="http://www.dzone.com/links/intellij_idea_static_code_analysis_screencast.html"&gt;clicky clicky&lt;/a&gt; to upvote at DZone.&lt;br /&gt;&lt;br /&gt;&lt;object id="_player" name="_player" data="http://tv.jetbrains.net/sites/default/files/flowplayer3/flowplayer-3.2.2.swf" type="application/x-shockwave-flash" width="400" height="300"&gt;&lt;param name="movie" value="http://tv.jetbrains.net/sites/default/files/flowplayer3/flowplayer-3.2.2.swf"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;param name="flashvars" value="config={&amp;quot;clip&amp;quot;:{&amp;quot;baseUrl&amp;quot;:&amp;quot;http://tv.jetbrains.net&amp;quot;,&amp;quot;scaling&amp;quot;:&amp;quot;orig&amp;quot;,&amp;quot;autoPlay&amp;quot;:false,&amp;quot;autoBuffering&amp;quot;:true,&amp;quot;url&amp;quot;:&amp;quot;sites/default/files/videos/converted/ideastaticanalysis.flv&amp;quot;},&amp;quot;plugins&amp;quot;:{&amp;quot;controls&amp;quot;:{&amp;quot;stop&amp;quot;:true}},&amp;quot;playlist&amp;quot;:[{&amp;quot;baseUrl&amp;quot;:&amp;quot;http://tv.jetbrains.net&amp;quot;,&amp;quot;scaling&amp;quot;:&amp;quot;orig&amp;quot;,&amp;quot;autoPlay&amp;quot;:false,&amp;quot;autoBuffering&amp;quot;:true,&amp;quot;url&amp;quot;:&amp;quot;http://tv.jetbrains.net/sites/default/files/videos/converted/ideastaticanalysis.flv&amp;quot;}]}"&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Check out these pages for more information on IDEA inspections:&lt;br /&gt;  &lt;/p&gt;&lt;ul&gt;&lt;li&gt;JetBrains' &lt;a href="http://www.jetbrains.com/idea/features/code_inspection.html"&gt;Code Inspection page&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;    &lt;li&gt;IDEA's &lt;a href="http://www.jetbrains.com/idea/webhelp/inspecting-source-code.html"&gt;Webhelp for inspections&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Read these pages to learn more about Structural Search and Replace:&lt;br /&gt;  &lt;ul&gt;&lt;li&gt;JetBrains' &lt;a href="http://www.jetbrains.com/idea/documentation/ssr.html"&gt;Structural Search and Replace Documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;IDEA's &lt;a href="http://www.jetbrains.com/idea/webhelp/structural-search-and-replace.html"&gt;Webhelp for Structural Search and Replace&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I've made a lot of screencasts and blog posts over the years. If you like this, then there are many ways to see the other stuff I've done:&lt;br /&gt;&lt;/p&gt;    &lt;ul&gt;&lt;li&gt;My main blog: &lt;a href="http://hamletdarcy.blogspot.com/"&gt;http://hamletdarcy.blogspot.com&lt;/a&gt;&lt;/li&gt;&lt;li&gt;My other JetBrains.tv posts: &lt;a href="http://tv.jetbrains.net/tags/hamlet"&gt;http://tv.jetbrains.net/tags/hamlet&lt;/a&gt;&lt;/li&gt;&lt;li&gt;IDEA related posts on my blog: &lt;a href="http://hamletdarcy.blogspot.com/search/label/IDEA"&gt;http://hamletdarcy.blogspot.com/search/label/IDEA&lt;/a&gt;&lt;/li&gt;&lt;li&gt;My screencasts on YouTube: &lt;a href="http://www.youtube.com/user/HamletDRC"&gt;http://www.youtube.com/user/HamletDRC&lt;/a&gt;&lt;/li&gt;&lt;li&gt;IDEA related Posts on my work blog: &lt;a href="http://www.canoo.com/blog/tag/idea/"&gt;http://www.canoo.com/blog/tag/idea/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Or follow me on Twitter: &lt;a href="http://twitter.com/hamletdrc"&gt;@HamletDRC&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Phew, that's a lot of self-promotion :)&lt;/p&gt;&lt;p&gt;Thanks for watching, and leave a comment! &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8328426278566071102?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8328426278566071102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8328426278566071102' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8328426278566071102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8328426278566071102'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/03/intellij-idea-static-analysis-custom.html' title='IntelliJ IDEA Static Analysis: Custom Rules with Structural Search &amp; Replace'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1977062906037008588</id><published>2011-03-08T07:39:00.002-06:00</published><updated>2011-03-08T07:41:14.116-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>Waste!</title><content type='html'>&lt;em&gt;In our industry no one recommends increasing waste, there are no waste evangelists, and no pro-waste lobby. So why is there so much of it? As we scramble frantically through the day to please our customers we are often not even aware of the pointless trail of half done work and unwanted features we leave in our wake. This article helps you understand what waste is, where it comes from, and what you can do about it by mapping the seven wastes of Lean Manufacturing into the software development field. If you want both better software and happier customers then quit wasting time and read this article.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;This article originally appeared in the October issue of &lt;a href="http://www.nofluffjuststuff.com/home/magazine_subscribe?id=18"&gt;No Fluff Just Stuff magazine&lt;/a&gt;. The full article is available on the &lt;a href="http://www.canoo.com/blog/2011/03/08/waste/"&gt;Canoo blog&lt;/a&gt;. As always, you can upvote at &lt;a href="http://www.dzone.com/links/waste_20.html"&gt;DZone&lt;/a&gt;. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks for bearing with the teaser/redirect thing I keep having to do.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1977062906037008588?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1977062906037008588/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1977062906037008588' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1977062906037008588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1977062906037008588'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/03/waste.html' title='Waste!'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3853255048839016881</id><published>2011-03-04T02:12:00.002-06:00</published><updated>2011-03-04T02:19:28.817-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Griffon MVC Groups and Event System</title><content type='html'>Griffon has a strong MVC focus, and functionality is built using MVC groups. This is not a screen or a form, an MVC group is a piece of functionality, and a single form is made of MVC groups composed together. The way MVC groups talk to each other is through an event bus, rather than being coupled directly to each other. &lt;br /&gt;&lt;br /&gt;I created a screencast that demonstrates these concepts in just under 7 minutes. In the video, I create an app, create several MVC groups, and then wire them together with the event bus. &lt;br /&gt;&lt;br /&gt;If the video doesn't play correctly, you may want to launch it from the &lt;a href="http://tv.jetbrains.net/videocontent/griffon-mvc-groups-and-event-system"&gt;JetBrains.tv site&lt;/a&gt;. Also, if you want to be nice then you can &lt;a href="http://www.dzone.com/links/griffon_mvc_groups_and_event_system.html"&gt;upvote this at DZone&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;&lt;object width="400" height="300" id="_player" name="_player" data="http://tv.jetbrains.net/sites/default/files/flowplayer3/flowplayer-3.2.2.swf" type="application/x-shockwave-flash"&gt;&lt;param name="movie" value="http://tv.jetbrains.net/sites/default/files/flowplayer3/flowplayer-3.2.2.swf" /&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="flashvars" value='config={"clip":{"baseUrl":"http://tv.jetbrains.net","scaling":"orig","autoPlay":false,"autoBuffering":true,"url":"sites/default/files/videos/converted/griffonmvc.flv"},"plugins":{"controls":{"stop":true}},"playlist":[{"baseUrl":"http://tv.jetbrains.net","scaling":"orig","autoPlay":false,"autoBuffering":true,"url":"http://tv.jetbrains.net/sites/default/files/videos/converted/griffonmvc.flv"}]}' /&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Boom. Winning.&lt;br /&gt;&lt;br /&gt;If you like this, you can check out my other screencasts on YouTube (&lt;a href="http://www.youtube.com/user/HamletDRC"&gt;http://www.youtube.com/user/HamletDRC&lt;/a&gt;) or JetBrains.tv (&lt;a href="http://tv.jetbrains.net/tags/hamlet"&gt;http://tv.jetbrains.net/tags/hamlet&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;If you want written documentation on these topics, then please read: &lt;br /&gt;* The Griffon RefCard - &lt;a href="http://refcardz.dzone.com/refcardz/getting-started-griffon"&gt;http://refcardz.dzone.com/refcardz/getting-started-griffon&lt;/a&gt;&lt;br /&gt;* The Griffon User Guide - &lt;a href="http://dist.codehaus.org/griffon/guide/index.html"&gt;http://dist.codehaus.org/griffon/guide/index.html&lt;/a&gt;&lt;br /&gt;* The Griffon Main Site - &lt;a href="http://griffon.codehaus.org/"&gt;http://griffon.codehaus.org/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3853255048839016881?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3853255048839016881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3853255048839016881' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3853255048839016881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3853255048839016881'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/03/griffon-mvc-groups-and-event-system.html' title='Griffon MVC Groups and Event System'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8370513578905443908</id><published>2011-03-02T08:41:00.003-06:00</published><updated>2011-03-02T08:46:31.106-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><title type='text'>CDI Event Bus Basics Screencast</title><content type='html'>Another day another screencast. This one's about the Event Bus that is part of CDI. Contexts and Dependency Injection is part of Java EE but available in SE using the Weld framework. This screencast shows you how to use CDI events and the event system, which is just one part of the larger CDI feature set. The screencast briefly explains the benefits of an event system and then shows how easy it is to use it from CDI.&lt;br /&gt;&lt;br /&gt;If it doesn't play correctly, you may want to launch it from the &lt;a href="http://tv.jetbrains.net/videocontent/cdi-event-bus-basics"&gt;JetBrains.tv site&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;object width="400" height="300" id="_player" name="_player" data="http://tv.jetbrains.net/sites/default/files/flowplayer3/flowplayer-3.2.2.swf" type="application/x-shockwave-flash"&gt;&lt;param name="movie" value="http://tv.jetbrains.net/sites/default/files/flowplayer3/flowplayer-3.2.2.swf"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;param name="flashvars" value="config={&amp;quot;clip&amp;quot;:{&amp;quot;baseUrl&amp;quot;:&amp;quot;http://tv.jetbrains.net&amp;quot;,&amp;quot;scaling&amp;quot;:&amp;quot;orig&amp;quot;,&amp;quot;autoPlay&amp;quot;:false,&amp;quot;autoBuffering&amp;quot;:true,&amp;quot;url&amp;quot;:&amp;quot;sites/default/files/videos/converted/cdievents.flv&amp;quot;},&amp;quot;plugins&amp;quot;:{&amp;quot;controls&amp;quot;:{&amp;quot;stop&amp;quot;:true}},&amp;quot;playlist&amp;quot;:[{&amp;quot;baseUrl&amp;quot;:&amp;quot;http://tv.jetbrains.net&amp;quot;,&amp;quot;scaling&amp;quot;:&amp;quot;orig&amp;quot;,&amp;quot;autoPlay&amp;quot;:false,&amp;quot;autoBuffering&amp;quot;:true,&amp;quot;url&amp;quot;:&amp;quot;http://tv.jetbrains.net/sites/default/files/videos/converted/cdievents.flv&amp;quot;}]}"&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;You could do worse with 5 minutes of your time. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you like this, you can check out my other screencasts on YouTube (&lt;a href="http://www.youtube.com/user/HamletDRC"&gt;http://www.youtube.com/user/HamletDRC&lt;/a&gt;) or JetBrains.tv (&lt;a href="http://tv.jetbrains.net/tags/hamlet"&gt;http://tv.jetbrains.net/tags/hamlet&lt;/a&gt;)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8370513578905443908?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8370513578905443908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8370513578905443908' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8370513578905443908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8370513578905443908'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/03/cdi-event-bus-basics-screencast.html' title='CDI Event Bus Basics Screencast'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6292616063517306628</id><published>2011-03-02T04:38:00.003-06:00</published><updated>2011-03-02T04:43:28.971-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>Lean Groovy 7 - Optimize the Whole</title><content type='html'>The successful software project is dependent on more than just the proper functioning of each part of the life-cycle: coding, testing, analysis, and deployment. Success hinges on how well all of these pieces fit together. Optimizing the Whole in Lean refers to making sure you always measure up. Improving your business is too often an exercise in sub-optimization: you may spend all your effort on improving the unit testing experience without realizing that it’s your interactions with operations that are derailing the project, or you may perfect your team’s delivery process while the rest of the company continues behaving wastefully...&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Yep, it happened again. I put a two sentence teaser here only to redirect you to the &lt;a href="http://www.canoo.com/blog/2011/03/02/lean-groovy-7-optimize-the-whole/"&gt;full article&lt;/a&gt; over on the &lt;a href="http://www.canoo.com/blog/2011/03/02/lean-groovy-7-optimize-the-whole/"&gt;Canoo web site&lt;/a&gt;. That's just how I roll. I've got tiger blood from a different terrestrial plane. Or something. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, check out the full article and &lt;a href="http://www.dzone.com/links/lean_groovy_7_optimize_the_whole.html"&gt;vote at DZone&lt;/a&gt;! &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6292616063517306628?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6292616063517306628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6292616063517306628' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6292616063517306628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6292616063517306628'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/03/lean-groovy-7-optimize-whole.html' title='Lean Groovy 7 - Optimize the Whole'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3995519575693544538</id><published>2011-02-25T08:40:00.005-06:00</published><updated>2011-02-25T08:46:49.026-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Screencast: GWT Event Bus Basics</title><content type='html'>Wheee! I made a screencast. Happy Friday to you too. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This screencast is about the GWT Event Bus. It explains how an Event Bus can be used to loosely couple controllers or views in MVC applications, and includes live coding of a GWT using the SimpleEventBus client. The source is all &lt;a href="https://github.com/HamletDRC/presentations/tree/master/presopatterns/samples/GwtEventDemo"&gt;available on GitHub&lt;/a&gt;. And as always, &lt;a href="http://www.dzone.com/links/gwt_event_bus_basics.html"&gt;up votes are appreciated&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;If it doesn't play correctly, you may want to launch it from the &lt;a href="http://tv.jetbrains.net/videocontent/gwt-event-bus-basics"&gt;JetBrains.tv site&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;&lt;object width="400" height="300" id="_player" name="_player" data="http://tv.jetbrains.net/sites/default/files/flowplayer3/flowplayer-3.2.2.swf" type="application/x-shockwave-flash"&gt;&lt;param name="movie" value="http://tv.jetbrains.net/sites/default/files/flowplayer3/flowplayer-3.2.2.swf"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;param name="flashvars" value="config={&amp;quot;clip&amp;quot;:{&amp;quot;baseUrl&amp;quot;:&amp;quot;http://tv.jetbrains.net&amp;quot;,&amp;quot;scaling&amp;quot;:&amp;quot;orig&amp;quot;,&amp;quot;autoPlay&amp;quot;:false,&amp;quot;autoBuffering&amp;quot;:true,&amp;quot;url&amp;quot;:&amp;quot;sites/default/files/videos/converted/gwtevents.flv&amp;quot;},&amp;quot;plugins&amp;quot;:{&amp;quot;controls&amp;quot;:{&amp;quot;stop&amp;quot;:true}},&amp;quot;playlist&amp;quot;:[{&amp;quot;baseUrl&amp;quot;:&amp;quot;http://tv.jetbrains.net&amp;quot;,&amp;quot;scaling&amp;quot;:&amp;quot;orig&amp;quot;,&amp;quot;autoPlay&amp;quot;:false,&amp;quot;autoBuffering&amp;quot;:true,&amp;quot;url&amp;quot;:&amp;quot;http://tv.jetbrains.net/sites/default/files/videos/converted/gwtevents.flv&amp;quot;}]}"&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;"&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif; font-size: 14px; color: rgb(73, 73, 73); line-height: 20px; "&gt;This screencast explains why MVC applications benefit from an event bus, and it demonstrates how to create, wire, and respond to events in Google Web Toolkit (GWT). Not bad for just six and a half minutes." Too much fun. &lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3995519575693544538?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3995519575693544538/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3995519575693544538' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3995519575693544538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3995519575693544538'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/02/screencast-gwt-event-bus-basics.html' title='Screencast: GWT Event Bus Basics'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1385660685182625435</id><published>2011-01-25T14:11:00.002-06:00</published><updated>2011-01-25T14:15:35.516-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Effective Groovy with CodeNarc 0.12</title><content type='html'>The new release of everyone’s favorite static anaylsis engine for Groovy is here. Time to download &lt;a href="http://codenarc.sourceforge.net/"&gt;CodeNarc 0.12&lt;/a&gt; while it’s hot. And in case this is your first time, CodeNarc analyzes your Groovy code and looks for potential problems and errors, creating a nice report or flagging the problem in your IDE. It’s like FindBugs, Lint, or PMD, but for Groovy.&lt;br /&gt;&lt;br /&gt;So what’s new in 0.12? Performance improvements, 35 new analysis rules, and a new logo. It’s supposed to be an armadillo, but no one can tell. We’re calling it the CodeNarc Grue, as in “You are in a maze of twisty little groovy scripts, all alike.” Anyway, you can read the full rundown over on the Canoo blog. My blog post describes the rules and reasons why you might want to use them. &lt;br /&gt;&lt;br /&gt;Read the Canoo &lt;a href="http://www.canoo.com/blog/2011/01/25/effective-groovy-with-codenarc-0-13/"&gt;Blog Post here&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;And as usual, &lt;a href="http://www.dzone.com/links/effective_groovy_with_codenarc_012.html"&gt;vote at DZone&lt;/a&gt; or Retweet to spread the word.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1385660685182625435?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1385660685182625435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1385660685182625435' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1385660685182625435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1385660685182625435'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2011/01/effective-groovy-with-codenarc-012.html' title='Effective Groovy with CodeNarc 0.12'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6769969574792309349</id><published>2010-12-23T00:08:00.002-06:00</published><updated>2010-12-23T00:14:01.633-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>IDEA X for the Grails Developer</title><content type='html'>The new version of &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt; was released last week. I already blogged what &lt;a href="http://www.canoo.com/blog/2010/12/20/intellij-idea-x-for-groovy-developers/"&gt;IDEA X means for Groovy developers&lt;/a&gt;, and all of those features are obviously available to any Community Edition user (that’s the free one). This post looks at all the new Grails features available in the Ultimate Edition (the one you pay for). These features are a little harder for me to try out personally as my current project is EJB3 and not Grails (someone save me please!). I’ve tried quite a few of them personally, but feedback is always welcome in case I miss or exaggerate something.&lt;br /&gt;&lt;br /&gt;As usual, you can read the &lt;a href="http://www.canoo.com/blog/2010/12/23/idea-x-for-the-grails-developer/"&gt;full article&lt;/a&gt; over on the &lt;a href="http://www.canoo.com/blog/2010/12/23/idea-x-for-the-grails-developer/"&gt;Canoo blog&lt;/a&gt;. Feeling magnanimous? &lt;a href="http://www.dzone.com/links/idea_x_for_the_grails_developer.html"&gt;Upvote&lt;/a&gt; at &lt;a href="http://www.dzone.com/links/idea_x_for_the_grails_developer.html"&gt;DZone&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Happy holidays everyone. Six years ago this week I decided to take a few vacation days at my in-law's house and finally get serious about learning Java. I wrote a little Swing app called "&lt;a href="http://hamletdarcy.com/hamletdarcy.com/pub/timetool/"&gt;TimeTool&lt;/a&gt;" whose source code I would be thoroughly embarrassed by today. What a long, strange trip it's been.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6769969574792309349?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6769969574792309349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6769969574792309349' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6769969574792309349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6769969574792309349'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/12/idea-x-for-grails-developer.html' title='IDEA X for the Grails Developer'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8511545439635744710</id><published>2010-12-22T00:48:00.002-06:00</published><updated>2010-12-22T00:52:40.176-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>Beginner Bash: Must-Know Bash Commands</title><content type='html'>&lt;p&gt;I switched full time to Ubuntu Linux last year and haven’t looked back. In this year I’ve learned to love the Bash shell (which includes the Terminal in Mac and Cygwin on Windows). At this point, I can finally say I’m faster in Bash then I was in Windows Explorer, Commander, Nautilus, or the Windows command prompt; and I prided myself on being a guy with a lot of .bat files. My goal now is to write some tips I learned in the last year. Before explaining the more advanced stuff I want to introduce some of the most basic basics.&lt;/p&gt; &lt;p&gt;So here it is: "Stuff I wish someone had explained clearly to me a year ago". Almost all these apply to Cygwin in Windows as well as Mac/Ubuntu Terminal.&lt;/p&gt;&lt;p&gt;As is usual these days, the &lt;a href="http://www.canoo.com/blog/2010/12/22/beginner-bash-must-know-bash-commands/"&gt;full article&lt;/a&gt; is available on the &lt;a href="http://www.canoo.com/blog/2010/12/22/beginner-bash-must-know-bash-commands/"&gt;Canoo blog&lt;/a&gt;. And if you want to upvote then head on &lt;a href="http://www.dzone.com/links/rich_internet_applications_ria_blog_archive_begin.html"&gt;over to DZone &lt;/a&gt;or clicky clicky on up arrow at the bottom of the post.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8511545439635744710?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8511545439635744710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8511545439635744710' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8511545439635744710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8511545439635744710'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/12/beginner-bash-must-know-bash-commands.html' title='Beginner Bash: Must-Know Bash Commands'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-950021229319828396</id><published>2010-12-20T04:07:00.001-06:00</published><updated>2010-12-20T04:09:18.896-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>IntelliJ IDEA X for Groovy Developers</title><content type='html'>The new version of &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt; was released last week. Here’s what it means for Groovy developers. I’ve tried out most of these new features, but there are one or two that I haven’t yet seen in action. Also, there’s a whole slew of Grails features that I’ll cover in a later blog post.&lt;br /&gt;&lt;br /&gt;Without further ado, read about the features over &lt;a href="http://www.canoo.com/blog/2010/12/20/intellij-idea-x-for-groovy-developers/"&gt;on the Canoo Blog&lt;/a&gt;. As always, if you want to contribute to the hype cycle then &lt;a href="http://www.dzone.com/links/intellij_idea_x_for_groovy_developers.html"&gt;vote this up at DZone&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-950021229319828396?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/950021229319828396/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=950021229319828396' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/950021229319828396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/950021229319828396'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/12/intellij-idea-x-for-groovy-developers.html' title='IntelliJ IDEA X for Groovy Developers'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-7622788584470876326</id><published>2010-12-14T23:40:00.000-06:00</published><updated>2010-12-14T23:41:29.455-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><title type='text'>Mockito – Screencasts for Stubbing, Verifying, and Argument Matching</title><content type='html'>We're rolling out &lt;a href="http://www.mockito.org"&gt;Mockito&lt;/a&gt; and trying to raise our testability at work and I'm set to give a presentation/training session tomorrow to a few new teams. In case you don't know, Mockito is a mock object framework for Java. It's competitors are EasyMock, JMock, and others if you're more familiar with those. If you haven't seen it then you may want to check out my old post "&lt;a href="http://hamletdarcy.blogspot.com/2010/09/mockito-pros-cons-and-best-practices.html"&gt;Mockito - Pros, Cons, and Best Practices&lt;/a&gt;". To prepare for my presentation I decided to record myself practicing my material and post it on youtube. Enjoy!&lt;br /&gt;&lt;br /&gt;The first screencast is about creating mock objects and stubbing behavior. These are the absolute basics of mocking. &lt;br /&gt;&lt;object width="480" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/DyuWgBHfxNQ?fs=1&amp;amp;hl=en_US&amp;amp;rel=0"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/DyuWgBHfxNQ?fs=1&amp;amp;hl=en_US&amp;amp;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;The second screencast is about verifying behavior, or verifying side effects, using Mockito. This is a little more advanced but still an essential API in working with Mockito. YouTube reports this video as 13 minutes long, but don't worry it is only 4:45. Some quirk of YouTube.&lt;br /&gt;&lt;object width="480" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/Qq0uziWeMAA?fs=1&amp;amp;hl=en_US&amp;amp;rel=0"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/Qq0uziWeMAA?fs=1&amp;amp;hl=en_US&amp;amp;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;The final screencast is about argument matchers, which add flexibility to your stub and verify phases. &lt;br /&gt;&lt;object width="480" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/razPMCf66_0?fs=1&amp;amp;hl=en_US&amp;amp;rel=0"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/razPMCf66_0?fs=1&amp;amp;hl=en_US&amp;amp;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;I hope you enjoyed these. They could be a little more practiced, but I'm happy enough with the quality. I recorded these on Ubuntu 10.4 using recordMyDesktop and mencode to convert from .ogv to .avi.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-7622788584470876326?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/7622788584470876326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=7622788584470876326' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7622788584470876326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7622788584470876326'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/12/mockito-screencasts-for-stubbing.html' title='Mockito – Screencasts for Stubbing, Verifying, and Argument Matching'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1600665177942227535</id><published>2010-12-07T14:36:00.002-06:00</published><updated>2010-12-07T14:39:58.755-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Slimmed Down Software – A Lean, Groovy Approach Part 6 – Respect People</title><content type='html'>&lt;blockquote&gt;Respecting people means creating an environment where the human element drives innovation and value. Creative problem solving and spontaneity are our most valuable assets, and great companies arrange their development process to let every single employee be able to exercise these traits... &lt;/blockquote&gt;&lt;div&gt;The entire article, as usual, is available over to &lt;a href="http://www.canoo.com/blog/2010/12/07/slimmed-down-software-a-lean-groovy-approach-part-6-respect-people/"&gt;the Canoo Blog&lt;/a&gt;. And you can of course &lt;a href="http://www.dzone.com/links/lean_groovy_part_6_respect_people.html"&gt;vote on DZone&lt;/a&gt;.&lt;br /&gt;&lt;p&gt;This article originally appeared in the September 2010 edition of &lt;a href="http://www.groovymag.com/"&gt;GroovyMag, the Groovy and Grails magazine&lt;/a&gt;. Part 7 is currently available for download from the magazine’s site, and more will come each month. Previous articles in this series are on the Canoo website: &lt;a href="http://canoo.com/blog/2010/06/04/slimmed-down-software-a-lean-groovy-approach-part-1-eliminate-waste/"&gt;Part 1: Eliminate Waste&lt;/a&gt;, &lt;a href="http://canoo.com/blog/2010/07/05/slimmed-down-software-a-lean-groovy-approach-part-2-build-quality-in/"&gt;Part 2: Build Quality In&lt;/a&gt;, &lt;a href="http://canoo.com/blog/2010/08/12/slimmed-down-software-a-lean-groovy-approach-part-3-create-knowledge/"&gt;Part 3: Create Knowledge&lt;/a&gt;, &lt;a href="http://canoo.com/blog/2010/09/13/slimmed-down-software-a-lean-groovy-approach-part-4-defer-commitment/"&gt;Part 4: Defer Commitment&lt;/a&gt;, and &lt;a href="http://www.canoo.com/blog/2010/10/28/slimmed-down-software-a-lean-groovy-approach-part-4-deliver-fast/"&gt;Part 5: Deliver Fast&lt;/a&gt;. Lastly, if you like this, you may want to check out some of my older blog posts from my &lt;a href="http://hamletdarcy.blogspot.com/search/label/craft"&gt;personal site&lt;/a&gt; under the ‘craft’ category. Enjoy!&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1600665177942227535?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1600665177942227535/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1600665177942227535' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1600665177942227535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1600665177942227535'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/12/slimmed-down-software-lean-groovy.html' title='Slimmed Down Software – A Lean, Groovy Approach Part 6 – Respect People'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4633972941672976213</id><published>2010-12-02T05:02:00.001-06:00</published><updated>2010-12-02T05:06:39.109-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Remote Script Execution with GroovySocketServer</title><content type='html'>File under: extremely dangerous but definitely fun. Here's some directions on how to execute any arbitrary Groovy script on a remote server. We're going to write a one line Groovy script that, when run, will listen to a socket and execute any incoming text as if it were Groovy script and return the result to the client. We'll do it from the command line and programatically. The client is actually more difficult to write and weighs in at a whooping 5 lines. Let's get started.&lt;br /&gt;&lt;br /&gt;The whole article is available on &lt;a href="http://www.canoo.com/blog/2010/12/02/remote-script-execution-with-groovysocketserver/"&gt;the Canoo Blog&lt;/a&gt;. For those inclined there is certainly a &lt;a href="http://www.dzone.com/links/remote_script_execution_with_groovysocketserver.html"&gt;Dzone Link to upvote&lt;/a&gt;. And none of the URLs have dirty words in them this time!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-4633972941672976213?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/4633972941672976213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=4633972941672976213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4633972941672976213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4633972941672976213'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/12/remote-script-execution-with.html' title='Remote Script Execution with GroovySocketServer'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4869482768148961268</id><published>2010-11-29T12:40:00.002-06:00</published><updated>2010-11-29T12:41:06.727-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>CodeNarc and GroovyServ Screencasts</title><content type='html'>At the last &lt;a href="http://www.hackergarten.net/"&gt;Hackergarten&lt;/a&gt; we came together and created two screencasts, both about projects in the Groovy ecosystem.&lt;br /&gt;&lt;br /&gt;The first is about &lt;a href="http://codenarc.sourceforge.net/"&gt;CodeNarc&lt;/a&gt;, a static analysis tool for Groovy similar to FindBugs or PMD for Java. The screencast can be &lt;a href="http://www.dzone.com/links/groovy_codenarc_screencast_creating_a_static_anal.html?ref=ps"&gt;upvoted at DZone&lt;/a&gt; or watched below:&lt;br /&gt;&lt;br /&gt;&lt;object width="480" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/ZPu8FaZZwRw?fs=1&amp;amp;hl=en_US&amp;amp;rel=0"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/ZPu8FaZZwRw?fs=1&amp;amp;hl=en_US&amp;amp;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;The second is about &lt;a&gt;GroovyServ&lt;/a&gt;, an application that increases the startup time of Groovy scripts. It is in German, but is easy to follow along even if you don't speak the language. You can vote for it at &lt;a href="http://www.dzone.com/links/groovyserv_textmate_hackergarten.html"&gt;DZone&lt;/a&gt; here and watch it below:&lt;br /&gt;&lt;br /&gt;&lt;object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="480" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;param name="src" value="http://www.youtube.com/v/WyVcjsaVAfk?fs=1&amp;amp;hl=en_US&amp;amp;rel=0"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;embed type="application/x-shockwave-flash" width="480" height="385" src="http://www.youtube.com/v/WyVcjsaVAfk?fs=1&amp;amp;hl=en_US&amp;amp;rel=0" allowscriptaccess="always" allowfullscreen="true"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Be sure to follow the mailing list for future Hackergarten events... it would be great to have some more people come out and join us next time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-4869482768148961268?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/4869482768148961268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=4869482768148961268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4869482768148961268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4869482768148961268'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/11/codenarc-and-groovyserv-screencasts.html' title='CodeNarc and GroovyServ Screencasts'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8244610760683681335</id><published>2010-11-15T12:04:00.002-06:00</published><updated>2010-11-15T12:09:19.938-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy CodeNarc 0.11 Unofficial Guide</title><content type='html'>Groovy CodeNarc is a static analysis tool for the Groovy language and does for Groovy what PMD and FindBugs does for Java: it analyses Groovy code for defects, mistakes, and bad practices. The new version 0.11 is a huge release for us. We’ve added over 50 new rules to the product (bringing the total to 130+ rules) and a few really great features. This is THE new look CodeNarc, and it’s ready to use today, try it out in the &lt;a href="https://meetcodenarc.appspot.com/edit/2001"&gt;CodeNarc Web Console&lt;/a&gt; or download the package directly from the &lt;a href="http://codenarc.sourceforge.net/"&gt;CodeNarc site&lt;/a&gt;. (Ant, Maven, grails, gradle, and griffon plugins all exist as well). &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To announce the release I wrote up the &lt;a href="http://canoo.com/blog/2010/11/13/groovy-codenarc-0-11-unofficial-guide/"&gt;Groovy CodeNarc 0.11 Unofficial Guide&lt;/a&gt;. You can read it over on the &lt;a href="http://www.canoo.com"&gt;Canoo site&lt;/a&gt; and please, if you like, vote &lt;a href="http://www.dzone.com/links/groovy_codenarc_011_unofficial_guide.html"&gt;over at DZone&lt;/a&gt;. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8244610760683681335?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8244610760683681335/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8244610760683681335' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8244610760683681335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8244610760683681335'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/11/groovy-codenarc-011-unofficial-guide.html' title='Groovy CodeNarc 0.11 Unofficial Guide'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-335522998167172940</id><published>2010-11-08T14:39:00.003-06:00</published><updated>2010-11-08T15:01:23.163-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='recursion'/><category scheme='http://www.blogger.com/atom/ns#' term='functional'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>There and Back Again - A Developer's Recursion Tale</title><content type='html'>Recursive functions are &lt;a href="http://hamletdarcy.blogspot.com/search/label/recursion"&gt;so 2009&lt;/a&gt;. All the cool kids are now scrambling to convert those legacy recursive functions into stack based iteration. Why would you ever need this, you ask? Maybe you’ve heard of my friend “StackOverflowError”, he likes to hang out on the JVM. Or maybe you’re a browser kinda guy and you’ve seen your alert messages say “Stack Overflow”. Or worst case (like me), you’re supporting IE6 and you finally figured out that the “Browser shows a blank screen” defect you can’t reproduce is IE’s way of overflowing (oh yes it really is). Well, stack based iteration is a way to leave your nice recursive function the way it is, yet still avoid the overflow errors. You just have to keep track of the function stack frames yourself by adding a little boilerplate around your method (and even that can be cleaned up fairly easily).&lt;br /&gt;&lt;br /&gt;So here is the tale of taking the road now commonly traveled. Learning to program imperatively, writing some &lt;a href="http://hamletdarcy.blogspot.com/2008/07/why-functional-programming.html"&gt;beautiful recursive functions&lt;/a&gt;, and then &lt;a href="http://hamletdarcy.blogspot.com/2009/08/how-to-tell-your-co-workers-have.html"&gt;ripping it out again&lt;/a&gt; because of platform limitations. There and Back Again – A Developer’s Tale of Recursion...&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Read the full article &lt;a href="http://canoo.com/blog/2010/11/08/there-and-back-again-a-developers-recursion-tale/"&gt;over on the Canoo blog&lt;/a&gt;. And if you want to be kind and vote, then head &lt;a href="http://canoo.com/blog/2010/11/08/there-and-back-again-a-developers-recursion-tale/"&gt;over to DZone first&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-335522998167172940?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/335522998167172940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=335522998167172940' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/335522998167172940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/335522998167172940'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/11/there-and-back-again-developers.html' title='There and Back Again - A Developer&apos;s Recursion Tale'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4833270758824889211</id><published>2010-11-05T12:25:00.002-05:00</published><updated>2010-11-05T12:28:13.284-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><title type='text'>Advanced Mockito: Capturing State with Answer and Captors</title><content type='html'>Hmmm… I really need to mock out &lt;a href="http://download.oracle.com/javase/6/docs/api/java/sql/ResultSet.html"&gt;java.sql.ResultSet&lt;/a&gt;, I know I’ll just subclass it with a hand-rolled mock. Oh-no, the default implementation without method bodies is 650 lines of code long. WTF? Did you know there are 197 public methods on the java.sql.ResultSet interface? This is an absurdly large interface, possibly the largest in the JDK (if not drop a comment, I’d love to know what the largest is). The workaround is to throw one together in &lt;a href="http://mockito.org/"&gt;Mockito&lt;/a&gt; (or your &lt;a href="http://easymock.org/"&gt;mock framework&lt;/a&gt; of choice). My implementation turned out to be 21 lines of code long. Not bad at all. To do it I creatively used ArgumentCaptors, Answer objects, and anonymous inner classes to capture state... (read on for the full article).&lt;br /&gt;&lt;br /&gt;&lt;div&gt;The &lt;a href="http://canoo.com/blog/2010/11/05/advanced-mocking-capturing-state-with-answer-and-captors/"&gt;full article&lt;/a&gt; is posted over on the &lt;a href="http://canoo.com/blog/2010/11/05/advanced-mocking-capturing-state-with-answer-and-captors/"&gt;Canoo Blog&lt;/a&gt;. And don't forget to &lt;a href="http://www.dzone.com/links/advanced_mockito_capturing_state_with_answer_and.html"&gt;vote at dzone&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-4833270758824889211?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/4833270758824889211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=4833270758824889211' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4833270758824889211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4833270758824889211'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/11/advanced-mockito-capturing-state-with.html' title='Advanced Mockito: Capturing State with Answer and Captors'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-5999702100004089358</id><published>2010-11-05T01:56:00.002-05:00</published><updated>2010-11-05T01:58:53.634-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Interview with Dierk Koenig – Author of Groovy in Action</title><content type='html'>Early this week I pestered Dierk Koenig into letting me ask him a few questions about Groovy past and present and the upcoming release of &lt;a href="http://www.manning.com/koenig2/"&gt;Groovy in Action 2nd Edition&lt;/a&gt;. If you aren’t aware already, Dierk is the author of &lt;a href="http://www.manning.com/koenig/"&gt;Groovy in Action&lt;/a&gt;, a &lt;a href="http://www.canoo.com/"&gt;Canoo&lt;/a&gt; Fellow, and a Groovy, Grails and GPars committer.&lt;br /&gt;&lt;br /&gt;You can read the &lt;a href="http://canoo.com/blog/2010/11/03/interview-with-dierk-koenig-author-of-groovy-in-action/"&gt;complete interview&lt;/a&gt; over at the Canoo blog. And if you want to be a kind bro then you can &lt;a href="http://www.dzone.com/links/interview_with_dierk_koenig_author_of_groovy_in_a.html"&gt;vote at DZone&lt;/a&gt;. Do people even say "kind bro" anymore? Anyway... happy Friday.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-5999702100004089358?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/5999702100004089358/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=5999702100004089358' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5999702100004089358'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5999702100004089358'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/11/interview-with-dierk-koenig-author-of.html' title='Interview with Dierk Koenig – Author of Groovy in Action'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-2064692388385180038</id><published>2010-10-28T14:56:00.002-05:00</published><updated>2010-10-28T15:00:13.895-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>Slimmed Down Software- A Lean, Groovy Approach Part 5 - Deliver Fast</title><content type='html'>&lt;p&gt;"It is clear and logical that developing features in small increments means you deliver sooner, and there is value in that. Delivering a partial system on an earlier calendar date means the customer starts accruing a return on investment before project completion, and this can even result in the system paying for itself before the project is even finished. But will delivering smaller increments really increase your output in the long term? The answer from queuing theory research is a resounding "yes"...&lt;/p&gt;&lt;p&gt;&lt;a href="http://is.gd/gp2wO"&gt;Part 5 of Slimmed Down Software&lt;/a&gt; is now available on the Canoo Blog. To read the entire article please surf on over there. And if you want to be kind then &lt;a href="http://is.gd/gp2uS"&gt;upvote at DZone&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;This article originally appeared in the August 2010 edition of &lt;a href="http://www.groovymag.com/"&gt;GroovyMag, the Groovy and Grails magazine&lt;/a&gt;. Parts 6 and 7 are currently available for download from the magazine’s site, and more will come each month. Previous articles in this series are on the Canoo website: &lt;a href="http://canoo.com/blog/2010/06/04/slimmed-down-software-a-lean-groovy-approach-part-1-eliminate-waste/"&gt;Part 1: Eliminate Waste&lt;/a&gt;, &lt;a href="http://canoo.com/blog/2010/07/05/slimmed-down-software-a-lean-groovy-approach-part-2-build-quality-in/"&gt;Part 2: Build Quality In&lt;/a&gt;, &lt;a href="http://canoo.com/blog/2010/08/12/slimmed-down-software-a-lean-groovy-approach-part-3-create-knowledge/"&gt;Part 3: Create Knowledge&lt;/a&gt;, and &lt;a href="http://canoo.com/blog/2010/09/13/slimmed-down-software-a-lean-groovy-approach-part-4-defer-commitment/"&gt;Part 4: Defer Commitment&lt;/a&gt;. Lastly, if you like this, you may want to check out some of my older blog posts from my &lt;a href="http://hamletdarcy.blogspot.com/search/label/craft"&gt;personal site&lt;/a&gt; under the ‘craft’ category. Enjoy!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-2064692388385180038?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/2064692388385180038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=2064692388385180038' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/2064692388385180038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/2064692388385180038'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/10/slimmed-down-software-lean-groovy.html' title='Slimmed Down Software- A Lean, Groovy Approach Part 5 - Deliver Fast'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4632612333110248953</id><published>2010-10-27T12:50:00.002-05:00</published><updated>2010-10-27T12:57:10.706-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='event'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Speaking at Devoxx</title><content type='html'>Good news for me, I'll be giving a 15-minute quickie at &lt;a href="http://www.devoxx.com/display/Devoxx2K10/Home"&gt;Devoxx&lt;/a&gt; on the topic of Groovy Code Generation. The talk is normally a little longer, but most talks can be improved by making them shorter. I'm sure the 15 minutes will be great fun. Check out the slides for the &lt;a href="http://dl.dropbox.com/u/138156/CodeGeneration_2gx.pdf"&gt;longer version here&lt;/a&gt;. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you can't make Devoxx, then be sure to catch fellow Canooie Dierk König at &lt;a href="http://jax.de/"&gt;W-JAX&lt;/a&gt; during the same time. His slots are all in German, but the code samples will surely be in Groovy. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For those interested here is the abstract for my talk. If you run or help organize a JUG and want a speaker then please contact me. I'm excited to travel around in 2011, see more of the world, and meet great people.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code Generation on the JVM: Writing Code that Writes Code&lt;/b&gt;&lt;br /&gt;"The Pragmatic Programmer" admonished us all to "write code that writes code": use code generators to increase productivity and avoid duplication. Today's language communities have clearly caught on, as more and more frameworks generate code at compile time: AST Transforms, Project Lombok, Spring Roo, and more.&lt;br /&gt;&lt;br /&gt;This session reviews these approaches including examples of how and why we'd want to do this. Come see the newest Groovy language tools, look in-depth at production deployed AST Transforms, and view libraries based on these techniques.&lt;br /&gt;&lt;br /&gt;Audience: developers searching for cutting edge solutions to increasing team velocity.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-4632612333110248953?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/4632612333110248953/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=4632612333110248953' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4632612333110248953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4632612333110248953'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/10/speaking-at-devoxx.html' title='Speaking at Devoxx'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4933210933107717402</id><published>2010-10-11T15:57:00.005-05:00</published><updated>2010-10-16T02:13:08.256-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>IntelliJ IDEA Shortcut Wallpaper</title><content type='html'>The fastest developers use the keyboard almost exclusively. To help you learn the &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt; shortcuts, I created a desktop wallpaper that lists the most common ones for Linux, Mac and Windows users. Can't remember the command? Just pop up the desktop and check it out. Bored while waiting for a compile? Ditto.&lt;br /&gt;&lt;br /&gt;&lt;img style="cursor: pointer; width: 200px; height: 125px;" src="http://www.hackergarten.net/wallpaper/IdeaCanoo1680x1050.png" alt="" id="BLOGGER_PHOTO_ID_5527049329622102210" border="0" /&gt;&lt;br /&gt;There are a few resolutions:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/138156/wallpaper/IdeaCanoo1440x900.png"&gt;IntelliJ IDEA Linux/Windows 1440x900&lt;/a&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/138156/wallpaper/IdeaCanoo1440x900_Mac.png"&gt;IntelliJ IDEA Macintosh 1440x900&lt;/a&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/138156/wallpaper/IdeaCanoo1680x1050.png"&gt;IntelliJ IDEA Linux/Windows 1680x1050&lt;/a&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/138156/wallpaper/IdeaCanoo1680x1050_Mac.png"&gt;IntelliJ IDEA Macintosh 1680x1050&lt;/a&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/138156/wallpaper/IdeaCanoo1920x1200.png"&gt;IntelliJ IDEA Linux/Windows 1920x1200&lt;/a&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/138156/wallpaper/IdeaCanoo1920x1200_Mac.png"&gt;IntelliJ IDEA Macintosh 1920x1200&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Not on IDEA? You can download the &lt;a href="http://hamletdarcy.blogspot.com/2010/10/eclipse-keyboard-shortcut-wallpaper.html"&gt;Eclipse Desktop wallpaper&lt;/a&gt; from us, or the &lt;a href="http://naleid.com/blog/2010/10/04/vim-movement-shortcuts-wallpaper/"&gt;vim quick reference&lt;/a&gt; from our friend Ted Naleid.&lt;br /&gt;&lt;br /&gt;doce ut discas - Teach, that you yourself may learn.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-4933210933107717402?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/4933210933107717402/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=4933210933107717402' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4933210933107717402'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4933210933107717402'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/10/intellij-idea-shortcut-wallpaper.html' title='IntelliJ IDEA Shortcut Wallpaper'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-7741773859191136813</id><published>2010-10-11T15:53:00.013-05:00</published><updated>2010-10-16T02:14:03.621-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>Eclipse Keyboard Shortcut Wallpaper</title><content type='html'>The fastest developers use the keyboard almost exclusively. To help you (and me) learn the &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; shortcuts, I created a desktop wallpaper that lists the most common ones for Linux, Macintosh and Windows users. Can't remember the command? Just pop up the desktop and check it out. Bored while waiting for a compile? Ditto.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px; height: 125px;" src="http://www.hackergarten.net/wallpaper/EclipseCanoo1440x900.png" alt="" id="BLOGGER_PHOTO_ID_5527048243792697778" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;There are a few resolutions:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/138156/wallpaper/EclipseCanoo1280x1024.png"&gt;Eclipse Linux/Windows 1280x1024&lt;/a&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/138156/wallpaper/EclipseCanoo1440x900.png"&gt;Eclipse Linux/Windows 1440x900&lt;/a&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/138156/wallpaper/EclipseCanoo1680x1050.png"&gt;Eclipse Linux/Windows 1680x1050&lt;/a&gt;&lt;br /&gt;&lt;a href="http://dl.dropbox.com/u/138156/wallpaper/EclipseCanoo1920x1080.png"&gt;Eclipse Linux/Windows 1920x1080&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Not on Eclipse? You can download the &lt;a href="http://hamletdarcy.blogspot.com/2010/10/intellij-idea-shortcut-wallpaper.html"&gt;IntelliJ IDEA wallpaper&lt;/a&gt; from us, or the &lt;a href="http://naleid.com/blog/2010/10/04/vim-movement-shortcuts-wallpaper/"&gt;vim quick reference&lt;/a&gt; from our friend Ted Naleid.&lt;br /&gt;&lt;br /&gt;doce ut discas - Teach, that you yourself may learn.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-7741773859191136813?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/7741773859191136813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=7741773859191136813' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7741773859191136813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7741773859191136813'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/10/eclipse-keyboard-shortcut-wallpaper.html' title='Eclipse Keyboard Shortcut Wallpaper'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-7571951919554956017</id><published>2010-09-29T15:04:00.003-05:00</published><updated>2010-09-30T10:58:06.737-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><title type='text'>Mockito - Pros, Cons, and Best Practices</title><content type='html'>Mockito - Pros, Cons, and Best Practices&lt;br /&gt;&lt;br /&gt;It's been almost 4 years since I wrote a blog post called "&lt;a href="http://hamletdarcy.blogspot.com/2007/02/easymock-pros-cons-and-best-practices.html"&gt;EasyMock - Pros, Cons, and Best Practices&lt;/a&gt;, and a lot has happened since. You don't hear about &lt;a href="http://easymock.org/"&gt;EasyMock&lt;/a&gt; much any more, and &lt;a href="http://mockito.org/"&gt;Mockito&lt;/a&gt; seems to have replaced it in mindshare. And for good reason: it is better. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;A Good Humane Interface for Stubbing&lt;/strong&gt;&lt;br /&gt;Just like EasyMock, Mockito allows you to chain method calls together to produce less imperative looking code. Here's how you can make a &lt;a href="http://martinfowler.com/articles/mocksArentStubs.html"&gt;Stub&lt;/a&gt; for the canonical Warehouse object: &lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;Warehouse mock = Mockito.mock(Warehouse.class);&lt;br /&gt;Mockito.when(mock.hasInventory(TALISKER, 50)).&lt;br /&gt;        thenReturn(true);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;I know, I like a crazy formatting. Regardless, giving your System Under Test (SUT) indirect input couldn't be easier. There is no big advantage over EasyMock for stubbing behavior and passing a stub off to the SUT. Giving indirect input with mocks and then using standard JUnit asserts afterwards is simple with both tools, and both support the standard Hamcrest matchers.  &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Class (not just Interface) Mocks&lt;/strong&gt;&lt;br /&gt;Mockito allows you to mock out classes as well as interfaces. I know the EasyMock ClassExtensions allowed you to do this as well, but it is a little nicer to have it all in one package with Mockito. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Supports Test Spies, not just Mocks&lt;/strong&gt;&lt;br /&gt;There is a difference between &lt;a href="http://hamletdarcy.blogspot.com/2007/10/mocks-and-stubs-arent-spies.html"&gt;spies and mocks&lt;/a&gt;. Stubs allow you to give indirect input to a test (the values are read but never written), Spies allow you to gather indirect output from a test (the mock is written to and verified, but does not give the test input), and Mocks are both (your object gives indirect input to your test through Stubbing &lt;i&gt;and&lt;/i&gt; gathers indirect output through spying). The difference is illustrated between two code examples. In EasyMock, you only have mocks. You must set all input and output expectations before running the test, then verify afterwards. &lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;// arrange&lt;br /&gt;Warehouse mock = EasyMock.createMock(Warehouse.class); &lt;br /&gt;EasyMock.expect(&lt;br /&gt;    mock.hasInventory(TALISKER, 50)).&lt;br /&gt;    andReturn(true).once();&lt;br /&gt;EasyMock.expect(&lt;br /&gt;    mock.remove(TALISKER, 50)).&lt;br /&gt;    andReturn(true).once();&lt;br /&gt;EasyMock.replay(mock); &lt;br /&gt;&lt;br /&gt;//act&lt;br /&gt;Order order = new Order(TALISKER, 50);&lt;br /&gt;order.fill(warehouse); &lt;br /&gt;&lt;br /&gt;// assert&lt;br /&gt;EasyMock.verify(mock); &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;That's a lot of code, and not all of it is needed. The arrange section is setting up a stub (the warehouse has inventory) and setting up a mock expectation (the remove method will be called later). The assertion in all this is actually the little verify() method at the end. The main point of this test is that remove() was called, but that information is buried in a nest of expectations. Mockito improves on this by throwing out both the record/playback mode and a generic verify() method. It is shorter and clearer this way: &lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;// arrange&lt;br /&gt;Warehouse mock = Mockito.mock(Warehouse.class);&lt;br /&gt;Mockito.when(mock.hasInventory(TALISKER, 50)).&lt;br /&gt;        thenReturn(true);&lt;br /&gt;&lt;br /&gt;//act&lt;br /&gt;Order order = new Order(TALISKER, 50);&lt;br /&gt;order.fill(warehouse); &lt;br /&gt;&lt;br /&gt;// assert&lt;br /&gt;Mockito.verify(warehouse).remove(TALISKER, 50);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The verify step with Mockito is spying on the results of the test, not recording and verifying. Less code and a clearer picture of what really is expected. &lt;br /&gt;Update: There is a separate Spy API you can use in Mockito as well: &lt;a href=" http://mockito.googlecode.com/svn/branches/1.8.3/javadoc/org/mockito/Mockito.html#13 "&gt;http://mockito.googlecode.com/svn/branches/1.8.3/javadoc/org/mockito/Mockito.html#13&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Better Void Method Handling&lt;/strong&gt;&lt;br /&gt;Mockito handles void methods better than EasyMock. The fluent API works fine with a void method, but in EasyMock there were some special methods you had to write. First, the Mockito code is fairly simple to read: &lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;// arrange&lt;br /&gt;Warehouse mock = Mockito.mock(Warehouse.class);&lt;br /&gt;&lt;br /&gt;//act&lt;br /&gt;Order order = new Order(TALISKER, 50);&lt;br /&gt;order.fill(warehouse); &lt;br /&gt;&lt;br /&gt;// assert&lt;br /&gt;Mockito.verify(warehouse).remove(TALISKER, 50);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Here is the same in EasyMock. Not as good: &lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;// arrange&lt;br /&gt;Warehouse mock = EasyMock.createMock(Warehouse.class); &lt;br /&gt;mock.remove(TALISKER, 50); &lt;br /&gt;EasyMock.expectLastMethodCall().once(); &lt;br /&gt;EasyMock.replay(mock); &lt;br /&gt;&lt;br /&gt;//act&lt;br /&gt;Order order = new Order(TALISKER, 50);&lt;br /&gt;order.fill(warehouse); &lt;br /&gt;&lt;br /&gt;// assert&lt;br /&gt;EasyMock.verify(mock); &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Mock Object Organization Patterns&lt;/strong&gt;&lt;br /&gt;Both Mockito and EasyMock suffer from difficult maintenance. What I said in my original EasyMock post holds true for Mockito: &lt;br /&gt;&lt;quote&gt;The method chaining style interface is easy to write, but I find it difficult to read. When a test other than the one I'm working on fails, it's often very difficult to determine what exactly is going on. I end up having to examine the production code and the test expectation code to diagnose the issue. Hand-rolled mock objects are much easier to diagnose when something breaks... This problem is especially nasty after refactoring expectation code to reduce duplication. For the life of me, I cannot follow expectation code that has been refactored into shared methods. &lt;/quote&gt;&lt;br /&gt;Now, four years later, I have a solution that works well for me. With a little care you can make your mocks reusable, maintainable, and readable. This approach was battle tested over many months in an Enterprise Environment(tm). Create a private &lt;i&gt;static&lt;/i&gt; method the first time you need a mock. Any important data needs to be passed in as a parameter. Using constants or "magic" fields hides important information and obfuscates tests. For example: &lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;User user = createMockUser("userID", "name"); &lt;br /&gt;...&lt;br /&gt;assertEquals("userID", result.id()); &lt;br /&gt;assertEquals("name", result.name(); &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Everything important is visible and in the test, nothing important is hidden. You need to completely hide the replay state behind this factory method if you're still on EasyMock. The Mock framework in use is an implementation detail and try not to let it leak. &lt;br /&gt;Next, as your dependencies grow, be sure to &lt;i&gt;always&lt;/i&gt; pass them in as factory method parameters. If you need a User and a Role object, then don't create one method that creates both mocks. One method instantiates one object, otherwise it is a parameter and compose your mock objects in the test method: &lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;User user = createMockUser(&lt;br /&gt;    "userID", &lt;br /&gt;    "name", &lt;br /&gt;    createMockRole("role1"), &lt;br /&gt;    createMockRole("role2")&lt;br /&gt;); &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;When each object type has a factory method, then it makes it much easier to compose the different types of objects together. Reuse. But you can only reuse the methods when they are simple and with few dependencies, otherwise they become too specific and difficult to understand. &lt;br /&gt;The first time you need to reuse one of these methods, then move the method to a utility class called "*Mocker", like UserMocker or RoleMocker. Follow a naming convention so that they are always easy to find. If you remembered to make the private factory methods static then moving them should be very simple. Your client code ends up looking like this, but you can use static imports to fix that: &lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;User user = UserMocker.createMockUser(&lt;br /&gt;    "userID", &lt;br /&gt;    "name", &lt;br /&gt;    RoleMocker.createMockRole("role1"), &lt;br /&gt;    RoleMocker.createMockRole("role2")&lt;br /&gt;); &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;User overloaded methods liberally. Don't create one giant method with every possible parameter in the parameter list. There are good reasons to avoid overloading in production, but this is test. Use overloading so that the test methods only display data relevant to that test and nothing more. Using Varargs can also help keep a clean test. &lt;br /&gt;Lastly, don't use constants. Constants hide the important information out of sight, at the top of the file where you can't see it or in a Mocker class. It's OK to use constants within the test case, but don't define constants in the Mockers, it just hides relevant information and makes the test harder to read later. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Avoid Abstract Test Cases&lt;/strong&gt;&lt;br /&gt;Managing mock objects within abstract test cases has been very difficult for me, especially when managing replay and record states. I've given up mixing mock objects and abstract TestCase objects. When something breaks it simply takes too long to diagnose. An alternative is to create custom assertion methods that can be reused. Beyond that, I've given up on Abstract TestCase objects anyway, on the grounds of preferring composition of inheritance.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Don't Replace Asserts with Verify&lt;/strong&gt;&lt;br /&gt;My original comments about EasyMock are still relevant for Mockito: The easiest methods to understand and test are methods that perform some sort of work. You run the method and then use asserts to make sure everything worked. In contrast, mock objects make it easy to test delegation, which is when some object other than the SUT is doing work. Delegation means the method's purpose is to produce a side-effect, not actually perform work. Side-effect code is sometimes needed, but often more difficult to understand and debug. In fact, some languages don't even allow it! If you're test code contains assert methods then you have a good test. If you're code doesn't contain asserts, and instead contains a long list of verify() calls, then you're relying on side effects. This is a unit-test bad smell, especially if there are several objects than need to be verified. Verifying several objects at the end of a unit test is like saying, "My test method needs to do several things: x, y, and z." The charter and responsibility of the method is no longer clear. This is a candidate for refactoring.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;No More All or Nothing Testing&lt;/strong&gt;&lt;br /&gt;Mockito's verify() methods are much more flexible than EasyMock's. You can verify that only one or two methods on the mock were called, while EasyMock had just one coarse verify() method. With EasyMock I ended up littering the code with meaningless expectations, but not so in Mockito. This alone is reason enough to switch. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Failure: Expected X received X&lt;/strong&gt;&lt;br /&gt;For the most part, Mockito error messages are better than EasyMock's. However, you still sometimes see a failure that reads "Failure. Got X Expected X." Basically, this means that your toString() methods produce the same results but equals() does not. Every user who starts out gets confused by this message at some point. Be Warned.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Don't Stop Handrolling Mocks&lt;/strong&gt;&lt;br /&gt;Don't throw out hand-rolled mock objects. They have their place. &lt;a href="http://hamletdarcy.blogspot.com/2009/07/groovytestability-maybe-not-killer.html"&gt;Subclass and Override&lt;/a&gt; is a very useful technique for creating a testing seam, use it. &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Learn to Write an ArgumentMatcher&lt;/strong&gt;&lt;br /&gt;Learn to write an &lt;a href="http://mockito.googlecode.com/svn/tags/latest/javadoc/org/mockito/ArgumentMatcher.html"&gt;ArgumentMatcher&lt;/a&gt;. There is a learning curve but it's over quickly. This post is long enough, so I won't give an example. &lt;br /&gt;&lt;br /&gt;That's it. See you again in 4 years when the next framework comes out!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-7571951919554956017?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/7571951919554956017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=7571951919554956017' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7571951919554956017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7571951919554956017'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/09/mockito-pros-cons-and-best-practices.html' title='Mockito - Pros, Cons, and Best Practices'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3236649051806165809</id><published>2010-09-27T16:11:00.002-05:00</published><updated>2010-09-27T16:14:10.726-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><title type='text'>Clearer Unit Tests: Assert, Guard, and Throw</title><content type='html'>I hate the book “&lt;a href="http://xunitpatterns.com/"&gt;xUnit Test Patterns&lt;/a&gt;” for being over 800 pages long. I am convinced a good editor can turn any 800 page book into a 700 pager with the exact same content… that includes you Leo Tolstoy! The problem is that xUnit Patterns is still the definitive reference to test concepts and implementation. There is no better book on testing available, but the sheer weight and size the book means few have actually read it. Well I have, and I highlighted the damn thing just to prove it. In this post you’ll find 3 techniques to improve test clarity that, in my opinion, are underutilized in the development world today.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Surf over to &lt;a href="http://canoo.com/blog/2010/09/27/clearer-unit-tests-assert-guard-and-throw/"&gt;http://canoo.com/blog&lt;/a&gt; to read the &lt;a href="http://canoo.com/blog/2010/09/27/clearer-unit-tests-assert-guard-and-throw/"&gt;rest of the article&lt;/a&gt;, or go straight to the &lt;a href="http://www.dzone.com/links/clearer_unit_tests_assert_guard_and_throw.html"&gt;Dzone link&lt;/a&gt; if you're inclined to vote it up. Thanks!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3236649051806165809?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3236649051806165809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3236649051806165809' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3236649051806165809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3236649051806165809'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/09/clearer-unit-tests-assert-guard-and.html' title='Clearer Unit Tests: Assert, Guard, and Throw'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4925886538802129757</id><published>2010-09-24T13:20:00.002-05:00</published><updated>2010-09-24T13:22:58.729-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Beautiful Java Enums</title><content type='html'>File under “It’s never too late to blog about Java 5 features” and “you wrote 1000 words on what?”.&lt;br /&gt;&lt;br /&gt;Way back before Java 5 I fell in love with the Type Safe Enum pattern described in Martin Fowler’s Refactoring. You know the one, where an instance of a class has members of itself as public static fields. It was so clever (not always a compliment) and I applied it everywhere I could. Fowler’s example dealt with blood types...  to read the full article surf over to &lt;a href="http://canoo.com/blog/2010/09/24/beautiful-java-enums/"&gt;http://canoo.com/blog/2010/09/24/beautiful-java-enums/&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And don't forget to spread a little &lt;a href="http://www.dzone.com/links/beautiful_java_enums.html"&gt;DZone love&lt;/a&gt;...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-4925886538802129757?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/4925886538802129757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=4925886538802129757' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4925886538802129757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4925886538802129757'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/09/beautiful-java-enums.html' title='Beautiful Java Enums'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8582318805977704154</id><published>2010-09-20T14:37:00.001-05:00</published><updated>2010-09-20T14:39:05.087-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>@Log – Groovy’s New and Extensible Logging Conveniences</title><content type='html'>The latest version &lt;a href="http://groovy.codehaus.org/Download"&gt;1.8 snapshot of Groovy&lt;/a&gt; includes a cool new logging feature called @Log. The key of @Log and the other logging annotations is that the parameters sent to logging methods are not evaluated unless that specific log level is enabled. For instance, you can call Logger.debug with a long running closure as a parameter, and if the debug log level is not enabled then the parameter is never evaluated.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My full article on the Canoo blog shows the details, all the frameworks supported, and how to use your own logging framework with the feature: &lt;a href="http://canoo.com/blog/2010/09/20/log-groovys-new-and-extensible-logging-conveniences/"&gt;@Log – Groovy’s New and Extensible Logging Conveniences&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8582318805977704154?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8582318805977704154/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8582318805977704154' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8582318805977704154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8582318805977704154'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/09/log-groovys-new-and-extensible-logging.html' title='@Log – Groovy’s New and Extensible Logging Conveniences'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-7633098280770150592</id><published>2010-09-19T14:51:00.003-05:00</published><updated>2010-09-19T14:55:14.428-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>More Pecha Kucha Lessons Learned</title><content type='html'>&lt;p&gt;Last weekend was Canoo’s annual Continuous Improvement workshop, where we retreat to our secret Alp fortress to discuss the coming year and where we want to go as a company. My favorite memory is getting licked by a cow in a breakout session. Only in Switzerland. My second favorite was the Pecha Kucha contest.&lt;/p&gt;&lt;p&gt;A Pecha Kucha is a 20 slide presentation where each slide is presented for only 20 seconds. That’s 6 minutes and 20 seconds total. It’s a lot different than a normal presentation, and I’ve already blogged my &lt;a href="http://hamletdarcy.blogspot.com/2008/04/pecha-kucha-9-beginner-mistakes.html" style="color: rgb(227, 0, 74); text-decoration: none; "&gt;“9 Beginner Mistakes”&lt;/a&gt; a few years ago. After watching 6 other people give Pecha Kuchas, I was struck by a couple common themes in what was working and what wasn’t. Check out my Canoo.com blog post &lt;a href="http://canoo.com/blog/2010/09/19/more-pecha-kucha-lessons-learned/"&gt;"More Pecha Kucha Lessons Learned"&lt;/a&gt; to read more about Pecha Kuchas and what I think it takes to deliver a great one. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-7633098280770150592?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/7633098280770150592/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=7633098280770150592' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7633098280770150592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7633098280770150592'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/09/httpcanoocomblog20100919more-pecha.html' title='More Pecha Kucha Lessons Learned'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-5528055978319901586</id><published>2010-09-13T14:40:00.002-05:00</published><updated>2010-09-13T14:44:57.186-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Slimmed Down Software – A Lean, Groovy Approach Part 4 – Defer Commitment</title><content type='html'>&lt;div&gt;Just published a new blog post over on &lt;a href="http://canoo.com/"&gt;Canoo.com&lt;/a&gt;. In my humble opinion, this is the best one of the series. Less code, more jokes, and more ideas than normal. Check it out here: &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://canoo.com/blog/2010/09/13/slimmed-down-software-a-lean-groovy-approach-part-4-defer-commitment/"&gt;Part 4 of Lean Groovy - Deferred Commitment&lt;/a&gt;&lt;/div&gt;&lt;div&gt;(or be kind and &lt;a href="http://www.dzone.com/links/deferred_commitment_real_options_and_groovy.html"&gt;vote at DZone&lt;/a&gt;.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;This article originally appeared in the July 2010 edition of &lt;a href="http://www.groovymag.com/"&gt;GroovyMag, the Groovy and Grails magazine&lt;/a&gt;. Parts 5 and 6 are currently available for download from the magazine’s site, and more will come each month. Previous articles in this series are on the Canoo website: &lt;a href="http://canoo.com/blog/2010/06/04/slimmed-down-software-a-lean-groovy-approach-part-1-eliminate-waste/"&gt;Part 1: Eliminate Waste&lt;/a&gt;, &lt;a href="http://canoo.com/blog/2010/07/05/slimmed-down-software-a-lean-groovy-approach-part-2-build-quality-in/"&gt;Part 2: Build Quality In&lt;/a&gt;, and &lt;a href="http://canoo.com/blog/2010/08/12/slimmed-down-software-a-lean-groovy-approach-part-3-create-knowledge/"&gt;Part 3: Create Knowledge&lt;/a&gt;. Lastly, if you like this, you may want to check out some of my older blog posts from my personal site &lt;a href="http://hamletdarcy.blogspot.com/search/label/craft"&gt;under the “craft” category&lt;/a&gt;. Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-5528055978319901586?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/5528055978319901586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=5528055978319901586' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5528055978319901586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5528055978319901586'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/09/slimmed-down-software-lean-groovy.html' title='Slimmed Down Software – A Lean, Groovy Approach Part 4 – Defer Commitment'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6188369432698225059</id><published>2010-08-12T06:55:00.004-05:00</published><updated>2010-11-29T12:41:40.041-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Slimmed Down Software – A Lean, Groovy Approach Part 3 – Create Knowledge</title><content type='html'>Alright, another episode of Lean Groovy has entered the public domain. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This month we take a look at the Spock framework with "&lt;a href="http://canoo.com/blog/2010/08/12/slimmed-down-software-a-lean-groovy-approach-part-3-create-knowledge/"&gt;Slimmed Down Software – A Lean, Groovy Approach Part 3 – Create Knowledge&lt;/a&gt;".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Part 4 and 5 are available today from &lt;a href="http://groovymag.com/"&gt;GroovyMag&lt;/a&gt;. More to come shortly. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you like it vote at DZone: &lt;a href="http://is.gd/eenuZ"&gt;http://is.gd/eenuZ&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6188369432698225059?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6188369432698225059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6188369432698225059' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6188369432698225059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6188369432698225059'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/08/slimmed-down-software-lean-groovy.html' title='Slimmed Down Software – A Lean, Groovy Approach Part 3 – Create Knowledge'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-2095193027990603448</id><published>2010-07-27T01:55:00.002-05:00</published><updated>2010-07-27T01:58:13.098-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Project Lombok - Java Without the Boilerplate</title><content type='html'>I've been playing around with Project Lombok and Canoo's RIA Suite (nee ULC) recently, getting ready for my next project. Lombok is a pure Java library that does compile time byte code generation to remove/generate a whole bunch of Java boilerplate for for you... getters, setters, toStrings, etc.&lt;br /&gt;&lt;br /&gt;You can read about Lombok, and how to use it within RIA Suite, on the &lt;a href="http://www.dzone.com/links/r/project_lombok_java_without_the_boilerplate.html"&gt;Canoo Blog&lt;/a&gt;. And, of course, you may &lt;a href="http://www.dzone.com/links/r/project_lombok_java_without_the_boilerplate.html"&gt;vote for it on DZone&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-2095193027990603448?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/2095193027990603448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=2095193027990603448' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/2095193027990603448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/2095193027990603448'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/07/project-lombok-java-without-boilerplate.html' title='Project Lombok - Java Without the Boilerplate'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1292172111603761245</id><published>2010-07-20T06:41:00.003-05:00</published><updated>2010-07-21T00:34:46.727-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>Ubuntu Kung-Fu – 10 Best Tricks (and some even work on Macs)</title><content type='html'>I switched to Ubuntu at home about a year ago and at work on January 1st. At this point I don't think I could ever go back to anything else (including my wife's sleek looking Macintosh). &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Over my summer break I bought the book &lt;a href="http://pragprog.com/titles/ktuk/ubuntu-kung-fu"&gt;Ubuntu Kung-Fu&lt;/a&gt;. It was a fun and valuable read. I wrote up a quick note about my 10 favorite tricks over on the &lt;a href="http://is.gd/dzid4"&gt;Canoo blog&lt;/a&gt;. You can &lt;a href="http://is.gd/dzid4"&gt;read it there&lt;/a&gt; or head over to DZone to show your love with &lt;a href="http://is.gd/dzie5"&gt;an upvote&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1292172111603761245?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1292172111603761245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1292172111603761245' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1292172111603761245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1292172111603761245'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/07/ubuntu-kung-fu-10-best-tricks-and-some.html' title='Ubuntu Kung-Fu – 10 Best Tricks (and some even work on Macs)'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-39444790855082778</id><published>2010-07-19T03:16:00.004-05:00</published><updated>2010-07-19T03:20:42.646-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='griffon'/><title type='text'>Griffon Refcard Released, Lead Interviewed</title><content type='html'>Big Griffon news today.&lt;br /&gt;&lt;br /&gt;First, the &lt;a href="http://refcardz.dzone.com/refcardz/getting-started-griffon"&gt;Griffon Refcard&lt;/a&gt; is available from DZone. It is a concise 6-page reference to getting started and working with Griffon. If the only thing you know about Griffon is that it is a Grails and Groovy based framework for building desktop applications, then this RefCard will fill you in with tons more details. And if you’re an old Griffon hack, then you’ll probably still pick up some new tips and tricks. I wrote it, and always like to hear feedback.&lt;br /&gt;&lt;br /&gt;Plus, DZone published an interview with Canooie Andres Almiray, the Griffon project lead. You can&lt;a href="http://www.dzone.com/links/r/andres_almiray_on_griffon_the_road_behind_and_the.html"&gt; read the interview here&lt;/a&gt;, or click the RefCard below to download the card.&lt;br /&gt;&lt;br /&gt;Anyone interested in Griffon in the Swiss area should come out to &lt;a href="http://hackergarten.net/"&gt;Hackergarten&lt;/a&gt; on the 30th of July. Several experienced Griffon developers will be present including Andres. And there is free pizza!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://refcardz.dzone.com/refcardz/getting-started-griffon"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 309px; height: 400px;" src="http://4.bp.blogspot.com/_dVhQbe4S9AM/TEQKbl__mhI/AAAAAAAAALA/fdEKKZTDYzI/s400/RefCard.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5495528914472114706" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-39444790855082778?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/39444790855082778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=39444790855082778' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/39444790855082778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/39444790855082778'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/07/griffon-refcard-released-lead.html' title='Griffon Refcard Released, Lead Interviewed'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_dVhQbe4S9AM/TEQKbl__mhI/AAAAAAAAALA/fdEKKZTDYzI/s72-c/RefCard.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3536313010701876803</id><published>2010-07-14T08:04:00.001-05:00</published><updated>2010-07-14T08:06:35.557-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='event'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Code Generation on the JVM: Video and Slides</title><content type='html'>Two weeks ago I spoke at the Chech Java User Group (CZJUG) on the topic of “Code Generation on the JVM”. Some of the technologies covered are Lombok, Groovy, GContracts, Spock, AST Transformations, Spring Roo, and other fun stuff.&lt;br /&gt;&lt;br /&gt;Links to the slides and videos are available on the Canoo Blog: &lt;a href="http://canoo.com/blog/2010/07/14/code-generation-on-the-jvm-video-and-slides/"&gt;http://canoo.com/blog/2010/07/14/code-generation-on-the-jvm-video-and-slides/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3536313010701876803?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3536313010701876803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3536313010701876803' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3536313010701876803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3536313010701876803'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/07/code-generation-on-jvm-video-and-slides.html' title='Code Generation on the JVM: Video and Slides'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3070731172734923216</id><published>2010-07-05T09:07:00.002-05:00</published><updated>2010-07-05T09:10:30.261-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Slimmed Down Software – A Lean, Groovy Approach Part 2 – Build Quality In</title><content type='html'>The 2nd part of "&lt;a href="http://canoo.com/blog/2010/07/05/slimmed-down-software-a-lean-groovy-approach-part-2-build-quality-in/"&gt;Slimmed Down Software - A Lean, Groovy Approach&lt;/a&gt;" is posted over on the &lt;a href="http://canoo.com/blog/2010/07/05/slimmed-down-software-a-lean-groovy-approach-part-2-build-quality-in/"&gt;Canoo Blog&lt;/a&gt;. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This was originally printed in &lt;a href="http://www.groovymag.com/"&gt;GroovyMag&lt;/a&gt;, and parts 3 and 4 are available now from the &lt;a href="http://www.groovymag.com/"&gt;GroovyMag&lt;/a&gt; website. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you like it then be sure to &lt;a href="http://www.dzone.com/links/build_quality_in_with_lean_and_groovy.html"&gt;vote at DZone&lt;/a&gt;. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3070731172734923216?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3070731172734923216/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3070731172734923216' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3070731172734923216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3070731172734923216'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/07/slimmed-down-software-lean-groovy.html' title='Slimmed Down Software – A Lean, Groovy Approach Part 2 – Build Quality In'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-5715824756147717113</id><published>2010-06-09T02:24:00.003-05:00</published><updated>2010-06-09T02:32:01.555-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>IT Certification Alternatives: Cost Benefit Analysis</title><content type='html'>I wrote a blog post about IT Certifications over on the &lt;a href="http://canoo.com/blog"&gt;Canoo Blog&lt;/a&gt;.&lt;br /&gt;&lt;div&gt;&lt;blockquote&gt;&lt;a href="http://canoo.com/blog/2010/06/09/it-certification-alternatives-cost-benefit-analysis/"&gt;IT Certification Alternatives: Cost Benefit Analysis&lt;/a&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;I think there are a lot of good opportunities outside of the traditional MCSP/SCJP track that are lower risk, higher value, and lower cost. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As always, votes at &lt;a href="http://www.dzone.com/links/it_certification_alternatives_cost_benefit_analys.html"&gt;DZone&lt;/a&gt; or &lt;a href="http://www.reddit.com/tb/cd1k5"&gt;Reddit&lt;/a&gt; appreciated.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-5715824756147717113?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/5715824756147717113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=5715824756147717113' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5715824756147717113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5715824756147717113'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/06/it-certification-alternatives-cost.html' title='IT Certification Alternatives: Cost Benefit Analysis'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-5196286778857959530</id><published>2010-06-07T01:18:00.002-05:00</published><updated>2010-06-07T01:23:06.326-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Slimmed Down Software – A Lean, Groovy Approach Part 1 – Eliminate Waste</title><content type='html'>GroovyMag is currently running a 7 part series I wrote called "Slimmed Down Software - A Lean, Groovy Approach". Part 1 started in the April 2010 edition, and now that it is June the copyright has reverted back to me and I get to self publish it on the web! If you like this then consider buying the May and June issues. &lt;p&gt;&lt;/p&gt;&lt;p&gt;The full article is published on the &lt;a href="http://www.dzone.com/links/r/slimmed_down_software_a_lean_groovy_approach_part.html"&gt;Canoo Blog&lt;/a&gt;. As usual, up-votes at &lt;a href="http://www.dzone.com/links/slimmed_down_software_a_lean_groovy_approach_part.html"&gt;DZone&lt;/a&gt; are welcome. &lt;/p&gt;&lt;p&gt;Here's the summary: &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;The Groovy Programming Language advertises itself as an “agile and dynamic language for the JVM”, but what does this mean exactly? This series of articles explains Lean Software Development, and shows how your choice of programming language can make your entire process remain nimble and adaptive. Each month will cover one of the seven Lean Software Development principles and explain how Groovy and the associated ecosystem help eliminate waste, defer commitment, and build quality into your product.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-5196286778857959530?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/5196286778857959530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=5196286778857959530' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5196286778857959530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5196286778857959530'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/06/slimmed-down-software-lean-groovy.html' title='Slimmed Down Software – A Lean, Groovy Approach Part 1 – Eliminate Waste'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-2571032480454176929</id><published>2010-05-24T10:44:00.001-05:00</published><updated>2010-05-24T10:46:27.732-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>GR8 Conference Europe Wrap Up</title><content type='html'>&lt;div&gt;Last week was the GR8 Conference for Groovy, Grails, Griffon, etc. in Copenhagen Denmark. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Besides having an awesome Hackergarten event, there was a traditional conference as well. A few of us at work were lucky (or hard working) enough to go. We wrote our experiences up on the Canoo blog. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Post is here: &lt;a href="http://is.gd/cn2PW"&gt;http://is.gd/cn2PW&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And DZone Upvotes always appreciated: &lt;a href="http://is.gd/cn2YG"&gt;http://is.gd/cn2YG&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-2571032480454176929?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/2571032480454176929/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=2571032480454176929' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/2571032480454176929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/2571032480454176929'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/05/gr8-conference-europe-wrap-up.html' title='GR8 Conference Europe Wrap Up'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6903945475106468215</id><published>2010-05-07T12:40:00.002-05:00</published><updated>2010-05-07T12:45:05.192-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><title type='text'>Gilad Bracha and the Java Post Mortem</title><content type='html'>At Jax.de this week I got to see two sessions with Gilad Bracha and sit on a panel with him (never would have imagined that).&lt;br /&gt;&lt;br /&gt;I wrote my thoughts about the day up on the &lt;a href="http://canoo.com"&gt;Canoo&lt;/a&gt; blog in a piece called "&lt;a href="http://canoo.com/blog/2010/05/07/java-post-mortem-with-gilad-bracha/"&gt;Gilad Bracha and the Java Post Mortem&lt;/a&gt;"&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dzone.com/links/java_post_mortem_with_gilad_bracha.html"&gt;Upvotes&lt;/a&gt; always appreciated!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6903945475106468215?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6903945475106468215/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6903945475106468215' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6903945475106468215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6903945475106468215'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/05/gilad-bracha-and-java-post-mortem.html' title='Gilad Bracha and the Java Post Mortem'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3064491761640670203</id><published>2010-04-21T08:23:00.002-05:00</published><updated>2010-04-21T08:26:55.425-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Spock Framework Mock Objects: Better Groovy Based Testing</title><content type='html'>I wrote an article on the &lt;a href="http://canoo.com"&gt;Canoo&lt;/a&gt; blog called "&lt;a href="http://canoo.com/blog/2010/04/20/spock-and-test-spies-a-logical-choice/"&gt;Spock and Test Spies: A Logical Choice&lt;/a&gt;". &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you are interested in alternative (and better) mock object frameworks in Groovy then check it out. Spock is a heavy user of Groovy AST Transformations, so those interested in transformations may also want to take a peek. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And if you have come here simply to vote the article up on DZone, then &lt;a href="http://www.dzone.com/links/mock_objects_with_spock_framework.html"&gt;click away&lt;/a&gt;!&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3064491761640670203?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3064491761640670203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3064491761640670203' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3064491761640670203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3064491761640670203'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/04/spock-framework-mock-objects-better.html' title='Spock Framework Mock Objects: Better Groovy Based Testing'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8339179162207115422</id><published>2010-04-15T00:48:00.002-05:00</published><updated>2010-04-15T00:51:51.826-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Groovy Interview and GR8 Conference Website</title><content type='html'>Søren over at the &lt;a href="http://www.gr8conf.org/"&gt;GR8 Conference European Headquarters&lt;/a&gt; was kind enough to ask me a few questions about Groovy. I find the itnerview an entertaining read, but then I'm maybe biased just a little.&lt;br /&gt;&lt;br /&gt;Check it out here: &lt;a href="http://www.gr8conf.org/blog/2010/04/15/70"&gt;http://www.gr8conf.org/blog/2010/04/15/70&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.gr8conf.org/front/images/front/gr8conf_vertical.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 150px; height: 570px;" src="http://www.gr8conf.org/front/images/front/gr8conf_vertical.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8339179162207115422?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8339179162207115422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8339179162207115422' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8339179162207115422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8339179162207115422'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/04/groovy-interview-and-gr8-conference.html' title='Groovy Interview and GR8 Conference Website'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-952131249832055840</id><published>2010-04-08T14:50:00.002-05:00</published><updated>2010-04-08T14:56:24.742-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy 1.7.2 - Three Features Worth the Upgrade</title><content type='html'>&lt;a href="http://docs.codehaus.org/display/GROOVY/2010/04/07/Groovy+1.7.2+released"&gt;Groovy 1.7.2&lt;/a&gt; was released 22 hours ago, so by now you have surely spent hours playing with the &lt;a href="http://docs.codehaus.org/display/GROOVY/Download"&gt;new bits&lt;/a&gt; and combing through the &lt;a href="http://jira.codehaus.org/secure/ReleaseNote.jspa?projectId=10242&amp;amp;version=16237"&gt;release notes&lt;/a&gt; looking for new nuggets of productivity.&lt;br /&gt;&lt;br /&gt;Or maybe not.&lt;br /&gt;&lt;br /&gt;For all those busier than me, here are the top 3 reasons to upgrade to the point release:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Convert GPathResults to XML &lt;/b&gt;&lt;/span&gt;- &lt;a href="http://jira.codehaus.org/browse/GROOVY-1178"&gt;JIRA 1178&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groovy.codehaus.org/Reading+XML+using+Groovy's+XmlSlurper"&gt;XmlSlurper&lt;/a&gt; is a great way to parse, manipulate, and generally tease XML. The problem is that once you start drilling into XML using the dynamic syntax, then you are working with GPathResults objects and not plain text or Strings. It was quite hard to pull out snippets of XML as text. No more! Now you can use XmlSlurper to pull out pieces of XML and then easily manipulate them as text by converting a GPathResult into a String.&lt;br /&gt;&lt;br /&gt;Here is the classic XML structure from the XmlSlurper documentation:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def CAR_RECORDS = '''&lt;br /&gt;   &amp;lt;records&amp;gt;&lt;br /&gt;     &amp;lt;car name='HSV Maloo' make='Holden' year='2006' &amp;gt;&lt;br /&gt;       &amp;lt;country&amp;gt;Australia&amp;lt;/country&amp;gt;&lt;br /&gt;       &amp;lt;record type='speed'&amp;gt;Production Pickup Truck with speed of 271kph&amp;lt;/record&amp;gt;&lt;br /&gt;     &amp;lt;/car&amp;gt;&lt;br /&gt;     &amp;lt;car name='P50' make='Peel' year='1962'&amp;gt;&lt;br /&gt;       &amp;lt;country&amp;gt;Isle of Man&amp;lt;/country&amp;gt;&lt;br /&gt;       &amp;lt;record type='size'&amp;gt;Smallest Street-Legal Car at 99cm wide and 59 kg in weight&amp;lt;/record&amp;gt;&lt;br /&gt;     &amp;lt;/car&amp;gt;&lt;br /&gt;     &amp;lt;car name='Royale' make='Bugatti' year='1931'&amp;gt;&lt;br /&gt;       &amp;lt;country&amp;gt;France&amp;lt;/country&amp;gt;&lt;br /&gt;       &amp;lt;record type='price'&amp;gt;Most Valuable Car at $15 million&amp;lt;/record&amp;gt;&lt;br /&gt;     &amp;lt;/car&amp;gt;&lt;br /&gt;   &amp;lt;/records&amp;gt;&lt;br /&gt; '''&lt;/code&gt;&lt;/pre&gt;Hopefully Blogger hasn't totally destroyed the XML tags. Yet one more reason to hate on XML. So anyway, XmlSlurper makes it trivial to pull out the second car element from the example XML:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def records = new XmlSlurper().parseText(CAR_RECORDS)&lt;br /&gt;def secondCar = records.car[1]&lt;br /&gt;assert secondCar.getClass() == NodeChild&lt;br /&gt;assert secondCar.toString() == 'Isle of ManSmallest Street-Legal Car at 99cm wide and 59 kg in weight'&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;There are a few problems with this example, and it isn't that the second car element has an index of 1. The secondCar variable is of type NodeChild. This is great if you want to perform more dynamic matching against NodeChild, but not so great if you want to get the full XML of the child and all descendants. The toString() is pretty meaningless, it's just a concatenation of all the child node values. In 1.7.2, StreamingMarkupBuilder lets you quickly get the child XML as a String. The assertion and code sample is messy, but the feature isn't:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def xmlString = new StreamingMarkupBuilder().bindNode(secondCar).toString()&lt;br /&gt;assert xmlString == "&amp;lt;car name='P50' year='1962' make='Peel'&amp;gt;&amp;lt;country&amp;gt;Isle of Man&amp;lt;/country&amp;gt;&amp;lt;record type='size'&amp;gt;Smallest Street-Legal Car at 99cm wide and 59 kg in weight&amp;lt;/record&amp;gt;&amp;lt;/car&amp;gt;"&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Nice. I understand you could somehow get the XML in previous Groovy versions, but I never figured it out. I'm lucky if I can just get something to pretty print.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;Easier Map and Property Sorting&lt;/b&gt;&lt;/span&gt; - &lt;a href="http://jira.codehaus.org/browse/GROOVY-2597"&gt;JIRA 2597&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is easier than ever to sort Maps and Properties objects. The first step is to create an unsorted Map:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def map = [c: 1, b: 2, a: 3]&lt;/code&gt;&lt;/pre&gt;In previous Groovy releases there were two options to sort a Map. One &lt;a href="http://groovy.codehaus.org/groovy-jdk/java/util/Map.html#sort(groovy.lang.Closure)"&gt;sort method&lt;/a&gt; took a closure that would be invoked like a Comparator, and the other way is just to wrap the Map in a TreeMap. Here are some assertions showing how they worked:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;assert map.sort { Entry it -&amp;gt; it.key }*.key == ['a', 'b', 'c']&lt;br /&gt;assert new TreeMap(map)*.key == ['a', 'b', 'c']&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Not bad, but now the Map object has a &lt;a href="http://groovy.codehaus.org/groovy-jdk/java/util/Map.html#sort()"&gt;no-arg sort&lt;/a&gt; that does default sorting and an API that lets you pass a &lt;a href="http://groovy.codehaus.org/groovy-jdk/java/util/Map.html#sort(java.util.Comparator)"&gt;real Comparator&lt;/a&gt;:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;assert map.sort()*.key == ['a', 'b', 'c']&lt;br /&gt;assert map.sort({ a, b -&amp;gt; a &amp;lt;=&amp;gt; b } as Comparator)*.key == ['a', 'b', 'c']&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;And remember, these methods return a new Map, they do not mutate the original. No Maps are harmed during the sorting of Maps.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;ncurry and rcurry&lt;/span&gt;&lt;/b&gt; - JIRA &lt;a href="http://jira.codehaus.org/browse/GROOVY-4144"&gt;4144&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://groovy.codehaus.org/gapi/groovy/lang/Closure.html#curry(Object[])"&gt;curry&lt;/a&gt; method has been around Groovy for a &lt;a href="http://hamletdarcy.blogspot.com/2008/01/curry-vs-closure-wrapping-in-groovy.html"&gt;long&lt;/a&gt; &lt;a href="http://www.ibm.com/developerworks/java/library/j-pg08235/index.html"&gt;time&lt;/a&gt;. It lets you bind variables into closures from left to right:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def multiply = { a, b -&amp;gt; a * b }&lt;br /&gt;def doubler = multiply.curry(2)&lt;br /&gt;assert doubler(4) == 8&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;In the above example, multiply has a type signature of "Object -&gt; Object -&gt; Object" (two Object parameters and an Object return type). When you curry multiply into doubler you get a type signature of "Object -&gt; Object" (one Object parameter and an Object return type). Parameters are bound from left to right. Curry always bound the left most parameter in the parameter list. Until now.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groovy.codehaus.org/gapi/groovy/lang/Closure.html#rcurry(Object[])"&gt;rcurry&lt;/a&gt; will bind parameters from right to left. So a halver can now be made from a divider. Whee!&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def divider = { a, b -&amp;gt; a / b }&lt;br /&gt;def halver = divider.rcurry(2)&lt;br /&gt;assert 5 == halver(10)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;a href="http://groovy.codehaus.org/gapi/groovy/lang/Closure.html#ncurry(Object[])"&gt;ncurry&lt;/a&gt; is the API sibling of curry and rcurry. It lets you bind parameters based on the integer index of the parameter in the signature. So you can bind parameter 2, 3, 4, or whatever. Check it out:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def operation = { int x, Closure f, int y -&amp;gt; f(x, y) }&lt;br /&gt;def divider = operation.ncurry(1) { a, b -&amp;gt; a / b }&lt;br /&gt;assert 5 == divider(10, 2)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Before you go too crazy with ncurry and rcurry, be warned that I think there is a bug when you try to mix them. Using ncurry and rcurry alone seems to work great, but rcurrying an ncurried closure does not currently work. I have a hunch that this does not effect a whole lot of people. I'll post a comment when I know what is wrong or when it is fixed.&lt;br /&gt;&lt;br /&gt;Now go upgrade to 1.7.2!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-952131249832055840?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/952131249832055840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=952131249832055840' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/952131249832055840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/952131249832055840'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/04/groovy-172-three-features-worth-upgrade.html' title='Groovy 1.7.2 - Three Features Worth the Upgrade'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1587540077042233618</id><published>2010-04-07T01:51:00.004-05:00</published><updated>2010-04-07T01:56:40.569-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Slimmed Down Software – A Lean, Groovy Approach in GroovyMag</title><content type='html'>The newest issue of &lt;a href="http://groovymag.com/"&gt;GroovyMag&lt;/a&gt; is hot off the presses, and it contains the first of seven articles on Lean Software and Groovy.&lt;br /&gt;&lt;br /&gt;The title is “Slimmed Down Software – A Lean, Groovy Approach Part 1 – Eliminate Waste”, and from the article:&lt;br /&gt;&lt;blockquote&gt;The Groovy Programming Language advertises itself as an “agile and dynamic language for the JVM”, but what does this mean exactly? This series of articles explains Lean Software Development, and shows how your choice of programming language can make your entire process remain nimble and adaptive. Each month will cover one of the seven Lean Software Development principles and explain how Groovy and the associated ecosystem help eliminate waste, defer commitment, and build quality into your product.&lt;/blockquote&gt;&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.groovymag.com/"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 154px; height: 200px;" src="http://4.bp.blogspot.com/_dVhQbe4S9AM/S7wsOcBA1tI/AAAAAAAAAK4/rsOrax3opxI/s200/gm18_400.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5457285475016431314" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1587540077042233618?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1587540077042233618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1587540077042233618' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1587540077042233618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1587540077042233618'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/04/slimmed-down-software-lean-groovy.html' title='Slimmed Down Software – A Lean, Groovy Approach in GroovyMag'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_dVhQbe4S9AM/S7wsOcBA1tI/AAAAAAAAAK4/rsOrax3opxI/s72-c/gm18_400.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-5520155331321586544</id><published>2010-03-31T04:44:00.002-05:00</published><updated>2010-03-31T04:54:09.224-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Gradle Plugin Conventions: Groovy Magic Explained</title><content type='html'>&lt;a href="http://hackergarten.net/"&gt;Hackergarten&lt;/a&gt; last Friday was a big success. About 10 of us (not all &lt;a href="http://canoo.com/"&gt;Canooies&lt;/a&gt;!) stayed up late and created an Announce plugin for &lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt;. In the 0.9 release you will be able to announce build events to &lt;a href="http://www.twitter.com/"&gt;Twitter&lt;/a&gt;, &lt;a href="http://www.fullphat.net/index.php"&gt;Snarl&lt;/a&gt;, and the &lt;a href="http://manpages.ubuntu.com/manpages/karmic/man1/notify-send.1.html"&gt;Ubuntu notification service&lt;/a&gt; (sorry, no Growl yet, it is coming). It was fun, educational, and energizing, and you should sign up for the &lt;a href="http://groups.google.com/group/hackergarten/"&gt;Google Group&lt;/a&gt; and come to the next event.&lt;br /&gt;&lt;br /&gt;While writing the plugin, we were briefly delayed by a technical detail. The &lt;a href="http://www.gradle.org/0.9-preview-1/docs/userguide/userguide_single.html#custom_plugins"&gt;user guide&lt;/a&gt; explains how to pass simple parameters to a plugin, but does not explain how to nest parameters within a closure. For instance, in the announce plugin you specify the Twitter username and password within an announce block:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;announce {&lt;br /&gt;  username 'your-username'&lt;br /&gt;  password 'your-password'&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;It turns out to be easy (just not documented, but we will fix that soon). Here is the full gradle build that shows you how to do it, with a detailed explanation of how it works below. As an example, we'll extend the Gradle documentation greeter custom plugin. This whole thing is runnable from the command line with "gradle hello":&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;apply plugin: GreetingPlugin&lt;br /&gt;&lt;br /&gt;greet {&lt;br /&gt;  message = 'Hi from Gradle'&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class GreetingPlugin implements Plugin&amp;lt;Project&amp;gt; {&lt;br /&gt;  def void apply(Project project) {&lt;br /&gt;&lt;br /&gt;      project.convention.plugins.greeting = new GreetingPluginConvention()&lt;br /&gt;      project.task('hello') &amp;lt;&amp;lt; {&lt;br /&gt;          println project.convention.plugins.greeting.message&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class GreetingPluginConvention {&lt;br /&gt;  String message&lt;br /&gt;&lt;br /&gt;  def greet(Closure closure) {&lt;br /&gt;      closure.delegate = this&lt;br /&gt;      closure()&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Starting at the top... there is a property declaration called "message" within a "greet" block. This is a much nicer configuration option than just using build-global variables, and your plugin should do something like this. It is important to understand what this block actually is and how it works. In Groovy, parentheses on method calls are optional and curly braces declare a closure. So this greet block is really an invocation of a method with type "Object greet(Closure)". To read and capture this message variable, you must somewhere declare and wire in this "Object greet(Closure)" method within your plugin.&lt;br /&gt;&lt;br /&gt;Moving on to the Plugin declaration. Plugin configuration is captured in something Gradle calls a "Convention" object. It is just a plain old Groovy object, and there is no Gradle magic... all the magic happending is standard Groovy. Let's examine the apply() method closely:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def void apply(Project project) {&lt;br /&gt;&lt;br /&gt;  project.convention.plugins.greeting = new GreetingPluginConvention()&lt;br /&gt;  project.task('hello') &amp;amp;lt;&amp;amp;lt; {&lt;br /&gt;      println project.convention.plugins.greeting.message&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;During the configuration phase (before any targets are run) you will be given a &lt;a href="http://www.gradle.org/0.9-preview-1/docs/javadoc/org/gradle/api/Project.html"&gt;Project&lt;/a&gt; object, and that Project object has a &lt;a href="http://www.gradle.org/0.9-preview-1/docs/javadoc/org/gradle/api/plugins/Convention.html"&gt;Convention&lt;/a&gt; object that holds onto a Map of &lt;a href="http://www.gradle.org/0.9-preview-1/docs/javadoc/org/gradle/api/plugins/Convention.html#getPlugins()"&gt;all the project conventions&lt;/a&gt;. Three pieces of Groovy magic: Getters can be accessed with property notation, Map entries can be accessed with dot notation, and Map.put can be called with the = sign. So this line:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;project.convention.plugins.greeting = new GreetingPluginConvention()&lt;/code&gt;&lt;/pre&gt;Is the same as the Java equivalent:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;project.getConvention().getPlugins().put("greeting", new GreetingPluginConvention());&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;During the build, Gradle is going to execute the build script. Any time an unknown property is assigned or an undeclared method is invoked, Gradle will look at this plugins Map and use the &lt;a href="http://groovy.codehaus.org/groovy-jdk/java/lang/Object.html#respondsTo(java.lang.String)"&gt;respondTo&lt;/a&gt; method to check if any of the Plugin conventions accepts that variable. If it does, then your convention object gets invoked and that variable is set. Gradle takes care of translating an unknown method call of "Object greet(Closure)" into a call to &lt;strong&gt;your&lt;/strong&gt; convention object. All that you need to do is make sure the greet(Closure) method is defined properly:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;class GreetingPluginConvention {&lt;br /&gt;  String message&lt;br /&gt;&lt;br /&gt;  def greet(Closure closure) {&lt;br /&gt;      closure.delegate = this&lt;br /&gt;      closure()&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Now it is up to you to dispatch the parameters declared within the closure into fields on your convention object. If you just try to execute the closure then you will receive a nice PropertyMissingException because the "message" field is not declared anywhere. You get around this by defining a "message" field on your object and then setting "this" to the closure's delegate. Groovy method dispatch is flexible (complex?). Closures have a delegate object that will act as a sort of "this" reference when the closure executes. So the message field was out of scope when the closure was created, but adding a delegate makes the message field from the convention object in scope. When the closure assigns message a value, it will be the message on your Convention object. Check out my old blog post &lt;a href="http://hamletdarcy.blogspot.com/2007/11/fun-with-groovy-closures-variable-scope.html"&gt;Fun with Closures&lt;/a&gt; for a more in depth explanation.&lt;br /&gt;&lt;br /&gt;Now your convention object has the message String, hooray! You can do something interesting with it, like printing it out to the console:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;println project.convention.plugins.greeting.message&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Or maybe you had something more interesting in mind for your cool plugin. Let us hope.&lt;br /&gt;&lt;br /&gt;By the way, you can just as easily declare a settings variable. This is an equivilent implementation of apply:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;def settings = new GreetingPluginConvention()&lt;br /&gt;project.convention.plugins.greeting = settings&lt;br /&gt;project.task('hello') &amp;lt;&amp;lt; {&lt;br /&gt;  println settings.message&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;And now there is just one last piece of Groovy magic left unexplained:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;apply plugin: GreetingPlugin&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This too is plain old Groovy. Method parenthesis are optional. Method parameters can be passed in as name value pairs. And Class literals can be referenced without the .class extension. The apply plugin statement is really just a plain old method call in disguise, and it is an invocation of apply(Map). The apply statement can be written in Java as:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;Map map = new HashMap();&lt;br /&gt;map.put("plugin", GreetingPlugin.class);&lt;br /&gt;apply(map);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Groovy magic is good. Thanks for taking some time to understand it. Hopefully this example makes it to the Gradle user guide in the next few days.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-5520155331321586544?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/5520155331321586544/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=5520155331321586544' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5520155331321586544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5520155331321586544'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/03/gradle-plugin-conventions-groovy-magic.html' title='Gradle Plugin Conventions: Groovy Magic Explained'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1086415666935470592</id><published>2010-03-23T15:54:00.004-05:00</published><updated>2010-03-23T16:26:42.197-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Unrolling Spock: Advanced @Unroll Usages in 0.4</title><content type='html'>Some of the &lt;a href="http://code.google.com/p/spock/"&gt;Spock Framework&lt;/a&gt; 0.4 features are starting to see the light of day, with the &lt;a href="http://meetspock.appspot.com/?id=8001"&gt;Data Tables&lt;/a&gt; being explained last week in a nice &lt;a href="http://pniederw.wordpress.com/2010/03/11/whats-new-in-spock-0-4-episode-1-data-tables/"&gt;blog post&lt;/a&gt; from Peter Niederwieser. One of the new features that I had not seen before is the new advanced @Unroll usage. Mixed with Data Tables, it produces some very cool results, and it can still be used with 0.3 style specs as well. Here's the juice:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;b&gt;JUnit Integration and @Unroll&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Spock is built on JUnit, and has always had good IDE support without any effort from you as a user. For the most part, the IDEs just think Spock is another unit test. Here's the a Spock spec for the new Data Tables feature and how it shows up in an IDE.&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;import spock.lang.*&lt;br /&gt;&lt;br /&gt;class TableTest extends Specification {&lt;br /&gt;&lt;br /&gt;  def "maximum of two numbers"() {&lt;br /&gt;     expect:&lt;br /&gt;     Math.max(a, b) == c&lt;br /&gt;&lt;br /&gt;     where:&lt;br /&gt;     a | b | c&lt;br /&gt;     3 | 7 | 7&lt;br /&gt;     5 | 4 | 5&lt;br /&gt;     9 | 9 | 9&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The assertion will be run 3 times: once for each row in the data table. And JUnit faithfully reports the method name correctly, even when the method names has a space in it: &lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dVhQbe4S9AM/S6ks6biSD2I/AAAAAAAAAKg/B8TfCbD4DWM/s1600-h/basic.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 238px;" src="http://3.bp.blogspot.com/_dVhQbe4S9AM/S6ks6biSD2I/AAAAAAAAAKg/B8TfCbD4DWM/s400/basic.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5451938206244278114" /&gt;&lt;/a&gt;The problem with data driven tests and xUnit is poor error location. When a test fails you will receive an error stating which method is the culprit... but what if the method runs an assertion across 50 or 60 pieces of data? The cause of a failure is almost never clear with data driven tests. At it's worst you have to step through several iterations of code waiting for an exception. Good tests have a clear point of failure, but good tests also do not repeat themselves with boilerplate. This is exactly why Spock has the @Unroll annotation. As a test author you get to write one concise unit test, and JUnit does the work of reporting results that help you isolate failures. Consider the same test method with the @Unroll annotation and the accompanying IDE output.&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;@Unroll&lt;br /&gt;def "maximum of two numbers"() {&lt;br /&gt;   expect:&lt;br /&gt;   Math.max(a, b) == c&lt;br /&gt;&lt;br /&gt;   where:&lt;br /&gt;   a | b | c&lt;br /&gt;   3 | 7 | 7&lt;br /&gt;   5 | 4 | 5&lt;br /&gt;   9 | 9 | 9&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;When executed, JUnit sees three test methods instead of one: one for each row in the data table:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dVhQbe4S9AM/S6ktAxHXVgI/AAAAAAAAAKo/1pN_oPdd6Rw/s1600-h/unrolled.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 220px;" src="http://2.bp.blogspot.com/_dVhQbe4S9AM/S6ktAxHXVgI/AAAAAAAAAKo/1pN_oPdd6Rw/s400/unrolled.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5451938315116172802" /&gt;&lt;/a&gt;The end result for you as a test writer is accurate failure resolution. You can pinpoint exactly which row failed. This feature is available in Spock 0.3 and you can use it today. What is new in 0.4 is the ability to change the test name dynamically. Here is a full @Unroll annotation that changes the method name:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;@Unroll("maximum of #a and #b is #c")&lt;br /&gt;def "maximum of two numbers"() {&lt;br /&gt;   expect:&lt;br /&gt;   Math.max(a, b) == c&lt;br /&gt;&lt;br /&gt;   where:&lt;br /&gt;   a | b | c&lt;br /&gt;   3 | 7 | 7&lt;br /&gt;   5 | 4 | 5&lt;br /&gt;   9 | 9 | 9&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Notice the #variable syntax in the annotation parameter. The # produces a sort of GString-like variable substitution that lets you bind columns from your data table into your test name. The annotation parameter references #a, #b, and #c, which aligns with the data table definition of a | b | c.  Check out the IDE output:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dVhQbe4S9AM/S6ktHbVGjBI/AAAAAAAAAKw/148LLAmB-F8/s1600-h/advanced_unrolled.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 220px;" src="http://3.bp.blogspot.com/_dVhQbe4S9AM/S6ktHbVGjBI/AAAAAAAAAKw/148LLAmB-F8/s400/advanced_unrolled.png" border="0" alt="" rid="BLOGGER_PHOTO_ID_5451938429527297042" /&gt;&lt;/a&gt;Previously, the test name was just the iteration number within the test. The new @Unroll parameter allows you to make the test name much more meaningful. Your tests will improve because failures become more descriptive. Unrolled failure messages before simply had the iteration name embedded in them, while now they can have meaningful data that you prescribe.&lt;br /&gt;&lt;br /&gt;My favorite part of playing with the new @Unroll was to see the default value of the parameter within the Spock source code:&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;java.lang.String value() default "#featureName[#iterationCount]";&lt;/code&gt;&lt;/pre&gt;Talk about eating your own dog food... the default value is a test name template, just like you could have written in your own test. Makes you wonder what other variables are in scope, huh?&lt;br /&gt;&lt;br /&gt;Spock snapshot builds for 0.4 are available at: &lt;a href="http://m2repo.spockframework.org/snapshots/org/spockframework/spock-core/"&gt;http://m2repo.spockframework.org&lt;/a&gt;. Get it before the link breaks.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1086415666935470592?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1086415666935470592/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1086415666935470592' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1086415666935470592'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1086415666935470592'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/03/unrolling-spock-advanced-unroll-usages.html' title='Unrolling Spock: Advanced @Unroll Usages in 0.4'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dVhQbe4S9AM/S6ks6biSD2I/AAAAAAAAAKg/B8TfCbD4DWM/s72-c/basic.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-327949296048954570</id><published>2010-03-19T03:11:00.002-05:00</published><updated>2010-03-19T03:16:53.105-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='usability'/><title type='text'>10 Lessons Learned from Usability Testing</title><content type='html'>This morning I published an article on my lessons learned from 7 years of experimenting with usability testing. It is called "&lt;a href="http://canoo.com/blog/2010/03/19/10-lessons-learned-from-usability-testing/"&gt;10 Lessons Learned from Usability Testing&lt;/a&gt;". Creative, huh? The post is on the Canoo blog instead of here... most modern web browsers will show you the article if you click the link above. I say most because I can't trust IE 6 to do anything right. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you like it then please do the &lt;a href="http://www.dzone.com/links/10_lessons_learned_from_usability_testing.html"&gt;up-vote thing at DZone&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Happy Friday everyone. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-327949296048954570?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/327949296048954570/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=327949296048954570' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/327949296048954570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/327949296048954570'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/03/10-lessons-learned-from-usability.html' title='10 Lessons Learned from Usability Testing'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1746745267853490519</id><published>2010-03-18T16:18:00.002-05:00</published><updated>2010-03-18T16:28:16.746-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='event'/><title type='text'>Hackergarten in Basel Next Friday</title><content type='html'>There is a new group starting up, and if you're anywhere near Basel Switzerland next Friday (March 26th) then you definitely want to stop by and participate. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.hackergarten.net/"&gt;Hackergarten&lt;/a&gt; is a group for people who define themselves by what they make, not what they consume. We've decided to meet regularly to create things as a group and give our work back to the community. Our goal is to create something that others can use; whether it be working software, improved documentation, or better educational materials. Our intent is to end each meeting with a patch or similar contribution submitted to an open and public project. Membership is open to anyone willing to contribution their time. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Our first event this Friday is a "Gradle Jam" at the Canoo offices in Basel. We are planning to add an "announce" plugin to Gradle that integrates with Twitter, Mongrel, and other messaging services. I expect a lot of pair programming, so please do not worry if you have no Gradle, Groovy, or Java experience. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The best way to get started is to join the &lt;a href="http://groups.google.com/group/hackergarten/"&gt;mailing list&lt;/a&gt; and lurk around or follow the Twitter account &lt;a href="http://twitter.com/Hackergarten"&gt;@Hackergarten&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I expect this to be a lot of fun, a little work, and ultimately rewarding. Please do stop by! &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1746745267853490519?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1746745267853490519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1746745267853490519' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1746745267853490519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1746745267853490519'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/03/hackergarten-in-basel-next-friday.html' title='Hackergarten in Basel Next Friday'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1498093113045289785</id><published>2010-03-06T14:12:00.002-06:00</published><updated>2010-03-06T14:26:54.835-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='event'/><title type='text'>Upcoming Gigs: Cologne, Frankfurt, Copenhagen, and Prague</title><content type='html'>The Groovy roadshow is on tour this Spring! My &lt;a href="http://canoo.com/"&gt;benevolent benefactors&lt;/a&gt; are letting me out of the office to visit a few user groups and conferences: &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;March 8 - Cologne JUG - Groovy AST Transformations&lt;/div&gt;&lt;div&gt;May 3rd - 7th - Jax.de - Code Generation on the JVM&lt;/div&gt;&lt;div&gt;May 19th to 20th - GR8 Conference - Groovy AST Transformations&lt;br /&gt;&lt;div&gt;June 28th - Czech JUG - Code Generation on the JVM&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sadly, I am not going to be at GR8 North America... but if you are in the US then that is the event of the Spring, in my opinion. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm crazy excited to visit places I have never been to and meet other programmers. If you have any desire to see any of my talks then drop me an email. I think these are my three best sessions:&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Code Generation on the JVM&lt;/b&gt;&lt;/div&gt;&lt;div&gt;We're seeing more and more JVM frameworks designed to generate code at compile time: AST Transforms, Project Lombok, Spring Roo, Clojure Macros, and more. This session reviews these approaches, including examples of how and why we'd want to do this. We'll see the newest Groovy language tools, write our own AST Transform, and look at some amazing libraries based on these techniques.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;b&gt;Slimmed Down Software: A Lean, Groovy Approach&lt;/b&gt;&lt;/div&gt;&lt;div&gt;The Groovy Programming Language advertises itself as an "agile and dynamic Language for the JVM", but what does this mean exactly? This sessions explain Lean Software Development, and shows how your choice of programming language can your entire process remain nimble and adaptive. Come learn about the principles of Lean, and see how Groovy and the associated ecosystem help eliminate waste, defer commitment, and build quality into your product.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Legacy Code, Groovy, and You&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Thinking about writing Groovy unit tests for your legacy Java code? This session is an honest discussion about what Groovy will gain you and what it won't. Come learn the engineering practices and tools that you can use to battle tight coupling, monolithic projects, and tangled dependencies, and then decide for yourself whether Groovy is the answer for your project. Plan on returning to work with a vision of what your team can do to write better software. &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1498093113045289785?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1498093113045289785/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1498093113045289785' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1498093113045289785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1498093113045289785'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/03/upcoming-gigs-cologne-frankfurt.html' title='Upcoming Gigs: Cologne, Frankfurt, Copenhagen, and Prague'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4716886547142721501</id><published>2010-02-19T09:03:00.002-06:00</published><updated>2010-02-19T09:07:41.311-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy ANTLR Plugins for Better DSLs</title><content type='html'>DSLs, ANTLR, and Groovy in one blog post? Oh yes, this should be good: a trifecta of interesting keywords. &lt;br /&gt;&lt;br /&gt;There is a horrible scourge upon Groovy based Domain Specific Languages, and no I'm not talking about curly braces. That awful syntax blocking our users from natural language based productivity is that insidious amalgamation of about 5 pixels called "the comma". If only we could rid ourselves and our users of this terrible burden! &lt;br /&gt;&lt;br /&gt;Some are trying: &lt;a href="http://docs.codehaus.org/display/GroovyJSR/GEP+3+-+Command+Expression+based+DSL"&gt;GEP-3&lt;/a&gt; is the Groovy Enhancement Proposal called "Command Expression based DSL" that will allow some commas to be optional. While interesting, there has not been much public activity on it recently. One of the requirements of dropping commas from methods invocations is that "the evaluation must be easily explainable". I think most people agree that we have more work to do before the proposal is easily explained. &lt;br /&gt;&lt;br /&gt;So where does that leave us? Does Groovy force these spurious commas on unsuspecting programmers? Hardly. The compiler architecture of Groovy is fairly open, and with a little creativity you can make the commas optional in your DSL. As long as you have access to the CompilerConfiguration then you have options, whether it be an AST Transformation or an ANTLR Plugin. And remember, if you are using GroovyShell then you have access to it. &lt;br /&gt;&lt;br /&gt;As an example, consider the &lt;a href="http://www.easyb.org/"&gt;easyb&lt;/a&gt; syntax for behaviors. What I would like to see is the comma dropped. Mmmm... it looks so much better without the commas: &lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;given &amp;quot;some data&amp;quot; {&lt;br /&gt;    println '... setting expectations'&lt;br /&gt;}&lt;br /&gt;when &amp;quot;a method is called&amp;quot; {&lt;br /&gt;    println '... calling some method'&lt;br /&gt;}&lt;br /&gt;then &amp;quot;some condition should exist&amp;quot; {&lt;br /&gt;    println '... making an assertion'&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;At some point in the compilation process, this source code will be represented as a text stream. What we're going to do is intercept that text stream, and provide some simple rewrite rules to add the comma in where it should be. An ANTLR plugin can intercept this text, add commas into it, and then pass it only to the Groovy compiler: Groovy is none the wiser. There is some boilerplate wiring together to do, but the bulk of the work is defining the rewrite rule (also known as a production). For the simple case, we can use a regular expression to add the comma in: &lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;String addCommas(text) {&lt;br /&gt;    def pattern = ~/(.*)(given&amp;#124;when&amp;#124;then) &amp;quot;([^&amp;quot;\\]*(\\.[^&amp;quot;\\]*)*)&amp;quot; \{(.*)/&lt;br /&gt;    def replacement = /$1$2 &amp;quot;$3&amp;quot;, {$4/&lt;br /&gt;    (text =~ pattern).replaceAll(replacement)&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Does a regular expression scale well to larger problems? No really. At some point you will need an alternative (maybe even at this point!) For instance, this Regex matches nested quotes, but the quotes must be double quotes, and Groovy's single quotes and multiline strings are not supported. Oh well, it is just an example. &lt;br /&gt;&lt;br /&gt;The "wiring together boilerplate" consists of subclassing AntlrParserPlugin so that you can write the text and subclassing ParserPluginFactory so you can wire in your AntlrParserPlugin subclass. The ParserPluginFactory can then be passed directly to the CompilerConfiguration which is passed to GrovoyShell. That makes no sense to me even as I write it, so it is probably best to go look at the &lt;a href="http://groovyconsole.appspot.com/script/73001"&gt;full source code listing&lt;/a&gt; in Groovy Web Console. &lt;br /&gt;&lt;br /&gt;For those of you using browsers not supporting anchor tags, here is the code inline: &lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&lt;br /&gt;class SourceModifierParserPlugin extends AntlrParserPlugin {&lt;br /&gt;    Reduction parseCST(SourceUnit sourceUnit, Reader reader) throws CompilationFailedException {&lt;br /&gt;        def text = addCommas(reader.text)&lt;br /&gt;        StringReader stringReader = new StringReader(text)&lt;br /&gt;        super.parseCST(sourceUnit, stringReader)&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def parserPluginFactory = new ParserPluginFactory() {&lt;br /&gt;    ParserPlugin createParserPlugin() {&lt;br /&gt;        new SourceModifierParserPlugin()&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def conf = new CompilerConfiguration(pluginFactory: parserPluginFactory)&lt;br /&gt;def binding = ... &lt;br /&gt;def shell = new GroovyShell(binding, conf)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And once you have a GroovyShell you can evaluate the world! Including the pseudo-easyb script from the beginning of the post. It runs with no problems... missing commas and all. &lt;br /&gt;&lt;br /&gt;ANTLR plugins have been around Groovy for a long time, and this example is based off of Guillaume Laforge's &lt;i&gt;famous&lt;/i&gt; Groovy Web Console &lt;a href="http://groovyconsole.appspot.com/script/3"&gt;Script #3&lt;/a&gt;. There is nothing particularly hard about writing an ANTLR plugin, but there might be something difficult with maintaining it. DSLs come with a host of issues including versioning. If you create an external DSL then you've published a language. It's fun at first but not so much later. &lt;br /&gt;&lt;br /&gt;And there you have it. No more of those despicable commas! Now we just need to do something about those &lt;a href="http://www.oreillynet.com/onlamp/blog/2007/05/the_is_it_a_dsl_or_an_api_ten.html"&gt;dispicable DSLs&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-4716886547142721501?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/4716886547142721501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=4716886547142721501' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4716886547142721501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4716886547142721501'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/02/groovy-antlr-plugins-for-better-dsls.html' title='Groovy ANTLR Plugins for Better DSLs'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4526003479768642411</id><published>2010-02-19T01:59:00.002-06:00</published><updated>2010-02-19T02:04:04.124-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Testing Asynchronous Code with GPars Dataflows</title><content type='html'>In my &lt;a href="http://hamletdarcy.blogspot.com/2010/02/asynchronous-unit-test-coordination.html"&gt;last post&lt;/a&gt; I showed how to use &lt;a href="http://code.google.com/p/jconch/"&gt;JConch 1.2&lt;/a&gt; to unit test asynchronous code. It contains a locking/barrier mechanism that allows you to gracefully tell your unit test how to wait and proceed for off thread events without sleeping or polling. Whee!&lt;br /&gt;&lt;br /&gt;As a small example, here is how the TestCoordinator would be used to test a mouse click event that happens on a different thread:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;TestCoordinator coord = new TestCoordinator()&lt;br /&gt;&lt;br /&gt;MyComponent component = new MyComponent()&lt;br /&gt;component.addActionListener({ ActionEvent e -&amp;gt;&lt;br /&gt;   assert "click" == e.actionCommand&lt;br /&gt;   coord.finishTest()&lt;br /&gt;} as ActionListener)&lt;br /&gt;&lt;br /&gt;component.click()&lt;br /&gt;coord.delayTestFinish(1, TimeUnit.SECONDS)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;If you are living in a Groovy world, then you should consider using &lt;a href="http://gpars.codehaus.org/"&gt;GPars&lt;/a&gt; &lt;a href="http://www.gpars.org/guide/guide/7.%20Dataflow%20Concurrency.html"&gt;Dataflow variables&lt;/a&gt; instead of the JConch TestCoordinator. The advantage of using Dataflows is that you get a similar thread coordination API but &lt;i&gt;also&lt;/i&gt; get a variable capture API, allowing you to move assertion statements to the end of your unit test where they belong. If you are looking for a clean, minimalist approach to capturing off thread events, then dataflows might be exactly what you need:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;import java.awt.event.*&lt;br /&gt;import javax.swing.SwingUtilities&lt;br /&gt;import groovyx.gpars.dataflow.DataFlowVariable&lt;br /&gt;&lt;br /&gt;def event = new DataFlowVariable()&lt;br /&gt;&lt;br /&gt;MyComponent component = new MyComponent()&lt;br /&gt;component.addActionListener({ ActionEvent e -&amp;gt;&lt;br /&gt;   event &amp;lt;&amp;lt; e&lt;br /&gt;   } as ActionListener)&lt;br /&gt;&lt;br /&gt;component.click()&lt;br /&gt;&lt;br /&gt;ActionEvent e = event.val&lt;br /&gt;assert e.source != null&lt;br /&gt;&lt;br /&gt;assert e.actionCommand == "click"&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;A DataFlowVariable is a little like a Java &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/Future.html"&gt;Future&lt;/a&gt; mixed with an immutable, thread safe object. The DataFlowVariable has an underlying value which can be set once, and only once, and trying to access that value will block the caller until the value is available. In this example, setting the value is done in the event handler with the "event &amp;lt;&amp;lt; e" line, and accessing the value is done in the "event.val" line. Getting the "val" will block the caller until a value is available. (Remember, in Groovy .val property access is translated into a getVal() method call).&lt;br /&gt;&lt;br /&gt;The advantage of using Dataflows in testing, when compared to Java, is that you get a nicer thread synchronization API than what the java.util.concurrent primitives provide. The advantage of Dataflows, when compared to JConch, is that you get to move your assertion methods back to the end of the unit tests. William Wake described a format for unit tests called &lt;a href="http://agileinaflash.blogspot.com/2009/03/arrange-act-assert.html"&gt;Arrange-Act-Assert&lt;/a&gt;, and it is still one of the best guidelines to writing clear and understandable unit tests. Assertion methods belong at the end of your test and arrangement code belongs at the beginning (note how many mock object frameworks subvert this ordering!). Capturing a variable is a good way to move the assertions to the end of the method, but in most frameworks it requires copious amounts of accidentally complex code.&lt;br /&gt;&lt;br /&gt;The downside of using Dataflows is that you once again have to set an @Timeout value on your unit test in the event that you never get a value (otherwise your tests will hang). OH WAIT, that is totally wrong. The GPars authors did provide a timeout value on DataFlowVariable#getVal():&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;ActionEvent e = event.getVal(4, TimeUnit.SECONDS)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;I had you there for a second though, right? Be warned, if the timeout value is exceeded then getVal() returns null, it does not throw an exception.&lt;br /&gt;&lt;br /&gt;The only downside to using DataFlow concurrency that I can see is that you actually need to understand a little bit about DataFlow concurrency. Who would have thought? DataFlowVariable is just the tip of the iceberg when it comes to GPars DataFlow support, and is not even the primary use case. The &lt;a href="http://www.gpars.org/guide/guide/7.%20Dataflow%20Concurrency.html"&gt;Dataflow User Guide&lt;/a&gt; is a good read and will explain a lot more about the concepts and GPars' implementation.&lt;br /&gt;&lt;br /&gt;Feel free to try this yourself. You don't even need to download any jars or change your project files. Just add the correct Grapes to the top of your unit test:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;@Grab(group='org.codehaus.gpars', module='gpars', version='0.9')&lt;br /&gt;@GrabResolver(name='jboss', root='http://repository.jboss.org/maven2/')&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;If you need more help, then check out the &lt;a href="http://svn.assembla.com/svn/SampleCode/gpars/TestCoordinatorTest.groovy"&gt;full example&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Happy Testing!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-4526003479768642411?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/4526003479768642411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=4526003479768642411' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4526003479768642411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4526003479768642411'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/02/testing-asynchronous-code-with-gpars.html' title='Testing Asynchronous Code with GPars Dataflows'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4728508622792572906</id><published>2010-02-09T10:00:00.000-06:00</published><updated>2010-02-09T10:59:18.134-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Asynchronous Unit Test Coordination with JConch 1.2</title><content type='html'>Slowly but surely, &lt;a href="http://code.google.com/p/jconch/"&gt;JConch&lt;/a&gt; Java Concurrency Library is becoming a depot for multithreaded and asynchronous testing on the Java platform. First there was &lt;a href="http://hamletdarcy.blogspot.com/2007/05/unit-testing-multi-threaded-code-with.html"&gt;SerialExectorService&lt;/a&gt;, allowing you to test with a Java ExecutorService that never started threads (&lt;a href="http://code.google.com/p/jconch/source/browse/trunk/eg/eg/jconch/testing/SerialExecutorServiceExample.java"&gt;example&lt;/a&gt;, &lt;a href="http://smokejumperit.com/jconch/1.1/jconch/testing/SerialExecutorService.html"&gt;javadoc&lt;/a&gt;). Then there was &lt;a href="http://hamletdarcy.blogspot.com/2009/01/test-driven-synchronization-policies.html"&gt;assertSynchronized&lt;/a&gt;, allowing you to make easy unit test assertions about your object's synchronization policy (&lt;a href="http://smokejumperit.com/jconch/1.1/jconch/testing/Assert.html"&gt;javadoc&lt;/a&gt;, &lt;a href="http://code.google.com/p/jconch/source/browse/trunk/eg/eg/jconch/testing/AssertExample.groovy"&gt;example&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;And now JConch 1.2 offers &lt;a href="http://jconch.googlecode.com/svn/trunk/src/main/java/jconch/testing/TestCoordinator.java"&gt;TestCoordinator&lt;/a&gt;: a tool for testing asynchronous code and multi-threaded callbacks. The TestCoordinator solves the problem of how to properly wait for asynchronous method calls without littering your unit tests with wait/join calls or CyclicBarrier/CountDownLatch API calls. In this regard, it provides a useful unit testing abstraction over the great Java 5 concurrency primitives.&lt;br /&gt;&lt;br /&gt;Note: If you'd like to skip all the prose then go straight to the &lt;a href="http://code.google.com/p/jconch/source/browse/trunk/eg/eg/jconch/testing/TestCoordinatorExamples.groovy"&gt;example&lt;/a&gt; and &lt;a href="http://code.google.com/p/jconch/source/browse/trunk/test/jconch/testing/TestCoordinatorTest.java"&gt;unit tests&lt;/a&gt; that are part of JConch 1.2.&lt;br /&gt;&lt;br /&gt;Writing good unit tests requires the same input as writing good production code: practice, dedication, and about &lt;a href="http://ebiquity.umbc.edu/blogger/2008/11/16/gladdwell-10000-hours-to-success/"&gt;10,000 hours&lt;/a&gt; hours experience. Almost any component framework that requires some sort of event listener invariably has a unit test that looks like this:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;MyComponent component = new MyComponent()&lt;br /&gt;&lt;br /&gt;ActionEvent event&lt;br /&gt;component.addActionListener({ ActionEvent e -&amp;gt;&lt;br /&gt;   event = e&lt;br /&gt;} as ActionListener)&lt;br /&gt;&lt;br /&gt;component.click()&lt;br /&gt;Thread.sleep(1000)&lt;br /&gt;&lt;br /&gt;assert event.source != null&lt;br /&gt;assert "click" == event.actionCommand&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;OK, usually it's in Java and not Groovy, but you get the point. Life's too short to write Java at home. The simple format is 1) create a component with a listener that captures the input, 2) activate the component, and 3) put the thread to sleep for a while and hope that the event fires before your assertions get run. The obvious problem is that you end up with either slow or intermittently failing unit tests depending on how long you sleep (no, there really isn't a perfect sleep number that avoids both).&lt;br /&gt;&lt;br /&gt;In the Java 4 days this was "solved" by monkeying with Object#wait and Object#notify method calls. Ewww. Java 5 introduced &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CyclicBarrier.html"&gt;CyclicBarrier&lt;/a&gt; and &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html"&gt;CountDownLatch&lt;/a&gt; which solved the problem nicely albeit in a primitive way. It is an improvement, but we can do better than this:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;@Test(timeout=5000)&lt;br /&gt;public void testClick() {&lt;br /&gt; CyclicBarrier gate = new CyclicBarrier(2)&lt;br /&gt;&lt;br /&gt; MyComponent component = new MyComponent()&lt;br /&gt;&lt;br /&gt; component.addActionListener({ ActionEvent e -&amp;gt;&lt;br /&gt;    assert "click" == e.actionCommand&lt;br /&gt;    gate.await()&lt;br /&gt;  } as ActionListener)&lt;br /&gt;&lt;br /&gt; component.click()&lt;br /&gt; gate.await()&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This approach allows us to move the assertion methods inside the callback, because we're insured that either the callback will be called or the test will fail with a timeout (the @Test(timeout=5000) bit). It is simpler and hides some complexity, but there is still a bunch of primitives distracting the reader from the core content of the test... what is that (2) parameter on the barrier constructor? Is the timeout value clear or is it hidden within a method annotation? And just what does await() mean? There is a lot of primitiveness involved here, which is what TestCoordinator abstracts over:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;import jconch.testing.TestCoordinator&lt;br /&gt;&lt;br /&gt;TestCoordinator coord = new TestCoordinator()&lt;br /&gt;&lt;br /&gt;MyComponent component = new MyComponent()&lt;br /&gt;component.addActionListener({ ActionEvent e -&amp;gt;&lt;br /&gt;  assert "click" == e.actionCommand&lt;br /&gt;  coord.finishTest()&lt;br /&gt;} as ActionListener)&lt;br /&gt;&lt;br /&gt;component.click()&lt;br /&gt;coord.delayTestFinish(1, TimeUnit.SECONDS)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;As you can see, TestCoordinator acts alot like a barrier or latch, but without all the low level API. When you've activated your class under test then you call delayTestFinish(...); the unit test will wait unit the listener calls finishTest(). And if finishTest() has already been called (a frequent possibility with multithreaded systems), then delayTestFinish just proceeds. If the timeout value expires then the test fails. No funny timeout annotation. No funny API. Just a simple coordinator. You want to delay a test until a callback is finished, and the API is designed around this nomenclature.&lt;br /&gt;&lt;br /&gt;There are two other options to delay as well:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;coord.delayTestFinish(1000) // milliseconds&lt;br /&gt;coord.delayTestFinish()     // requires @Timeout value!&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;For those of you coming from GWT... yes, this is almost exactly the API of &lt;a href="http://www.ibm.com/developerworks/java/library/j-cq07247/index.html"&gt;GWTTestCase&lt;/a&gt;. Use what works, I say.&lt;br /&gt;&lt;br /&gt;For more info on TestCoordinator, check out the &lt;a href="http://code.google.com/p/jconch/source/browse/trunk/test/jconch/testing/TestCoordinatorTest.java"&gt;UnitTest&lt;/a&gt; and the &lt;a href="http://code.google.com/p/jconch/source/browse/trunk/eg/eg/jconch/testing/TestCoordinatorExamples.groovy"&gt;example&lt;/a&gt;. Happy Testing!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-4728508622792572906?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/4728508622792572906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=4728508622792572906' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4728508622792572906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4728508622792572906'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/02/asynchronous-unit-test-coordination.html' title='Asynchronous Unit Test Coordination with JConch 1.2'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8276875654748496728</id><published>2010-02-07T09:58:00.002-06:00</published><updated>2010-02-07T10:06:41.135-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>New in Groovy 1.7.1: Constructor Mocking and Half Mocks</title><content type='html'>The Groovy MockFor object got some fun new features this weekend: &lt;a href="http://jira.codehaus.org/browse/GROOVY-1823"&gt;constructor mocking&lt;/a&gt; and "&lt;a href="http://jira.codehaus.org/browse/GROOVY-2630"&gt;half-mocks&lt;/a&gt;". The tickets are marked for Groovy 1.7.1, so these features are available in the &lt;a href="http://build.canoo.com/groovy/artifacts/"&gt;nightly builds&lt;/a&gt; or in the next few weeks as 1.7.1 is released. The easiest thing is, of course, to just &lt;a href="http://groovy.codehaus.org/Building+Groovy+from+Source"&gt;build from source&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The first feature is Constructor mocking. It is now possible to specify a return value for mock constructor calls. Here is an example that uses a "Person" object. The "tom" variable is a real Person object, while the "mary" object is not. Thanks to this new feature, instantiating Mary returns to you Tom.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;import groovy.mock.interceptor.MockFor&lt;br /&gt;&lt;br /&gt;class Person {&lt;br /&gt; String name&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;def tom = new Person(name:'Tom')&lt;br /&gt;&lt;br /&gt;def mock = new MockFor(Person, true)&lt;br /&gt;&lt;br /&gt;mock.demand.with {&lt;br /&gt; Person() { tom }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;mock.use {&lt;br /&gt; def mary = new Person(name:'Mary')&lt;br /&gt; assert tom == mary&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;There are two parts to getting this working: the "demand.with" block, where the person constructor is specified to return tom, and the true parameter passed to MockFor. To make MockFor backwards compatible, a flag was needed to control when to allow constructor mocking and when not to allow it. As you can see, after doing this, the tom and mary objects are equal (in fact, the same reference).&lt;br /&gt;&lt;br /&gt;The problem with this feature alone is that calling tom.getName() results in a mock exception saying no demand is set. If Tom is a real instance of Person then why would you get a demand exception? Well, within the mock.use block Tom &lt;span style="font-style: italic;"&gt;is&lt;/span&gt; a mock. The behaviour you probably expect is to have the real Tom methods pass through to the real implementation, which is why "half-mocks" were introduced. Check out how you can specify methods to ignore and pass through to the underlying object:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;mock.ignore(~'get.*')&lt;br /&gt;mock.demand.with {&lt;br /&gt; Person() { tom }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;mock.use {&lt;br /&gt; def mary = new Person(name:'Mary')&lt;br /&gt; assert mary.name == 'Tom'&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The ignore method takes a pattern to match, and the mock ignores those methods, passing them on to the underlying implementation. So your mock is still a mock, not a real object, but methods are passed through as needed. This is the opposite of how EasyMock partial mocking works, where a partial mock is technically a subclass of the target class, and methods are routed &lt;span style="font-style: italic;"&gt;by default&lt;/span&gt; to the real implementation. In Groovy, the method are routed &lt;span style="font-style: italic;"&gt;by default&lt;/span&gt; to the mock.&lt;br /&gt;&lt;br /&gt;Fun stuff, and thanks to Paul King for the work!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8276875654748496728?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8276875654748496728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8276875654748496728' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8276875654748496728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8276875654748496728'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/02/new-in-groovy-171-constructor-mocking.html' title='New in Groovy 1.7.1: Constructor Mocking and Half Mocks'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-202685269264319258</id><published>2010-01-22T15:45:00.008-06:00</published><updated>2010-01-22T15:58:52.029-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><title type='text'>Sharing IntelliJ IDEA Project Files in Version Control</title><content type='html'>There are quite a few benefits to having IDE project files &lt;span style="font-style: italic;"&gt;properly&lt;/span&gt; stored under version control:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;most people want to use an IDE and will need to configure the project somehow&lt;/li&gt;&lt;li&gt;a shared environment reduces costs within a corporate workplace&lt;/li&gt;&lt;li&gt;a VCed project means that the project file branches with your codebase. Need to work on an old branch? No problem, the project file already exists.&lt;/li&gt;&lt;li&gt;casual contributors will have an easier time making patches for your project&lt;/li&gt;&lt;li&gt;an IDE &lt;span style="font-style: italic;"&gt;can&lt;/span&gt; provide checkstyle and coding standards to your code&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;And when the files are stored &lt;span style="font-style: italic;"&gt;improperly &lt;/span&gt;in version control, you create a nice changelist headache for yourself and turn away the casual contributor.&lt;br /&gt;&lt;br /&gt;Here are three simple rules on how to&lt;span style="font-style: italic;"&gt; properly&lt;/span&gt; share an IntelliJ IDEA project file in version control:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rule #1&lt;/span&gt; - Check-in the .ipr and .iml files&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rule #2&lt;/span&gt; - Set an ignore flag for the .iws file (your workspace file). All proper VCSs allow you to do this.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Rule #3 &lt;/span&gt;- Make IDEA Project Variables for all the variables that vary (it's kinda the definition of variable, you know). Some common variables you'll probably need are "Tomcat Home", "Groovy Home", and "JDK Version".&lt;br /&gt;&lt;br /&gt;Creating variables is really easy. Open the .ipr/.iml in a text editor and scan for hardcoded paths or values. When you find one just replace it with $variable_name$. Now when IDEA starts, it prompts you for those variables if they are not defined. These are IDEA variable stored in your HOME directory; they have nothing to do with your operating system environment variables. Here's what a prompt looks like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dVhQbe4S9AM/S1ocn0-BpDI/AAAAAAAAAKI/lSkBCZ9l1Hw/s1600-h/undefined_var.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 341px;" src="http://1.bp.blogspot.com/_dVhQbe4S9AM/S1ocn0-BpDI/AAAAAAAAAKI/lSkBCZ9l1Hw/s400/undefined_var.png" alt="" id="BLOGGER_PHOTO_ID_5429683771307828274" border="0" /&gt;&lt;/a&gt;See that red dialog? Clicking it opens a screen where you can add values to the variables:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dVhQbe4S9AM/S1ocgOkIETI/AAAAAAAAAKA/GHyOKaHOlHc/s1600-h/add_var.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 366px;" src="http://1.bp.blogspot.com/_dVhQbe4S9AM/S1ocgOkIETI/AAAAAAAAAKA/GHyOKaHOlHc/s400/add_var.png" alt="" id="BLOGGER_PHOTO_ID_5429683640739565874" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Adding a value should be pretty self-explanatory.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Gotchas&lt;/span&gt; - There are a few gotcha's to be aware of...&lt;br /&gt;&lt;br /&gt;Using multiple versions of IDEA is not well supported. Most new versions, even minor releases, try to write some extra info to the project files. Not a problem in the corporate world, but more so in the OS one. You might try checking in a backup copy when the project lead upgrade.&lt;br /&gt;&lt;br /&gt;Making the JDK Name variable can be somewhat confusing, as it is not a path on your disk. IDEA keeps track globally (for all projects) of your installed JDKs, and each one is given a name. It is easy to find the place in the .ipr where this is specified, but it is not easy to explain to users what their's should be set to. It needs to be the name of an entry from your SDKs in Settings:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dVhQbe4S9AM/S1oc723B2hI/AAAAAAAAAKY/usQnkGKzeYw/s1600-h/SDKs.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 283px;" src="http://1.bp.blogspot.com/_dVhQbe4S9AM/S1oc723B2hI/AAAAAAAAAKY/usQnkGKzeYw/s400/SDKs.png" alt="" id="BLOGGER_PHOTO_ID_5429684115412736530" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Also, changing the inspection profiles can modify the project. The inspections are the codestyle to the project, so it may make sense to have them baked into the .ipr. However, this is an optional place to put them.  An inspection profile can be shared or not. If it is shared then it is written to the .ipr, otherwise it is an external file. The Settings screen should be self-explanatory once you understand the Shared checkbox.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dVhQbe4S9AM/S1oc3QfX4BI/AAAAAAAAAKQ/RcUpxV_dgfE/s1600-h/inspections.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 268px;" src="http://1.bp.blogspot.com/_dVhQbe4S9AM/S1oc3QfX4BI/AAAAAAAAAKQ/RcUpxV_dgfE/s400/inspections.png" alt="" id="BLOGGER_PHOTO_ID_5429684036393492498" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Lastly, adding words to the spell checker will add the word to the .ipr file, with a key of &lt;span style="font-style: italic;"&gt;your username&lt;/span&gt;. I opened a &lt;a href="http://youtrack.jetbrains.net/issue/IDEA-51682"&gt;bug for this&lt;/a&gt;, as I feel a user's name should never go in the project file, but the JetBrains guys feel that this is OK considering that switching to the ".idea" alternate project layout will separate the files out and avoid the issue.  For now, I guess the best advice is to spell words correctly and, if you're not a committer, live with the fact that your project file may be checked out because of this issue.&lt;br /&gt;&lt;br /&gt;Is all this worth it? I recently opened the &lt;a href="http://gpars.codehaus.org/"&gt;GPars&lt;/a&gt; project files, defined an SDK and a Groovy 1.6.7 library, and ran the tests successfully. For me, it was great.&lt;br /&gt;&lt;br /&gt;Rule #4 - &lt;a href="http://upload.wikimedia.org/wikipedia/en/d/dd/Gnomes_plan.png"&gt;Profit&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-202685269264319258?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/202685269264319258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=202685269264319258' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/202685269264319258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/202685269264319258'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/01/sharing-intellij-idea-project-files-in.html' title='Sharing IntelliJ IDEA Project Files in Version Control'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_dVhQbe4S9AM/S1ocn0-BpDI/AAAAAAAAAKI/lSkBCZ9l1Hw/s72-c/undefined_var.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-7058570155873273072</id><published>2010-01-11T13:26:00.001-06:00</published><updated>2010-01-11T13:29:18.698-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Accelerated GWT Report Card</title><content type='html'>&lt;table border="1"&gt;&lt;tr&gt;&lt;td style="border: none" colspan="2"&gt;  &lt;table border="0"&gt;    &lt;tr&gt;&lt;td style="border:none"&gt;Student Name:&lt;/td&gt;&lt;td style="border:none"&gt;&lt;strong&gt;Accelerated GWT&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td style="border:none"&gt;School:&lt;/td&gt;&lt;td style="border:none"&gt;&lt;strong&gt;Apress&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td style="border:none"&gt;School Year:&lt;/td&gt;&lt;td style="border:none"&gt;&lt;strong&gt;2008&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td style="border:none"&gt;Teacher:&lt;/td&gt;&lt;td style="border:none"&gt;&lt;strong&gt;Hamlet D'Arcy&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;    &lt;tr&gt;&lt;td style="border:none"&gt;Overall Grade:&lt;/td&gt;&lt;td style="border:none"&gt;&lt;strong&gt;A-&lt;/strong&gt;Strong on client side, i18n, and advanced topics.&lt;/td&gt;&lt;/tr&gt;  &lt;/table&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" style="border:none"&gt;Grading Scale: A=Outstanding, B=Good, C=Average, D=Poor, F=Fail&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" style="border:none" /&gt;&amp;nbsp;&lt;/tr&gt;&lt;tr bgcolor="#F2F2F2"&gt;&lt;td colspan="2"&gt;Teacher Comments&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2"&gt;This was a good book and a worthwhile read. It was very strong on the client side and documented many edge cases of the GWT framework without reducing itself to an overly specific "recipe" book. &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" style="border:none" /&gt;&amp;nbsp;&lt;/tr&gt;  &lt;tr bgcolor="#F2F2F2"&gt;&lt;td&gt;Client Side Programming&lt;/td&gt;&lt;td&gt;A-&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;Knowledge of Standard GWT Widget Set&lt;/td&gt;&lt;td&gt;A-&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;Great coverage of basic widget set. Contains examples and advice about how to layout widgets in various containers, including composing widgets in the Composite class. Sometimes the widget API was explained too completely and it felt like reading Javadoc, but these sections can easily be skimmed. Also, this book was written for GWT 1.4, so UiBuilder is not covered at all.&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;Knowledge of CSS Styling&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;Great coverage of how to work with the CSS of widgets including several good examples. Best coverage of the topic I could find.&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;General Client Concerns&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;Overall, the client sections are excellent. Serializing your own classes is covered, the output of the GWT compiler is given fair due, and generators for creating custom JavaScript code at compile time are covered. So far, this is the best book on client side GWT that I've found, even though it doesn't cover the 2.0 features. &lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;Knowledge of JSNI (JavaScript Native Interface)&lt;/td&gt;&lt;td&gt;D&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;JavaScript Native Interface is barely covered. In comparison, GWT in Practice covers it maybe too much. Embedding JavaScript in multiline Java comments is the most controversial part of GWT, but it's not the most important. Still, a little more info would be helpful. &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" style="border:none" /&gt;&amp;nbsp;&lt;/tr&gt;  &lt;tr bgcolor="#F2F2F2"&gt;&lt;td&gt;Server Side Programming&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;Knowledge of GWT RPC (Remote Procedure Calls)&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;GWT RPC is covered in 14 pages. Do you need more than that? Maybe not, it's pretty straight forward. The appendix does cover some of the newer 2.0/1.5 features, like generics. &lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;Knowledge of Internationalization&lt;/td&gt;&lt;td&gt;A+&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;Over 30 pages on i18n, including an example using localization at either compile time or run time. Very good chapter.&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;Knowledge of Security Concerns&lt;/td&gt;&lt;td&gt;B+&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;Same origin policy and cross site scripting: check. Not as lengthy coverage as in other books, but adequate.&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;Knowledge of GWT Testing&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;GWT Testing is surely the easiest chapter of the book to write. GWT ships with GWTTestCase for testing asynchronous calls and a benchmarking tool for measuring performance, and they are clearly explained all over the Internet. Speed Tracer, the 2.0 profiler that runs in Chrome, is of course not covered. &lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;Creative Code Samples&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;Decent enough code samples (with an occasional error) covering browser history and server sessions, as well as the other topics mentioned. Some of the code samples were a little long and ImageBundle was given too much space given that it is deprecated in 2.0. &lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;Knowledge of Alternative Server Stacks&lt;/td&gt;&lt;td&gt;D&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;Nothing on the server side beyond GWT RPC is covered. &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="2" style="border:none" /&gt;&amp;nbsp;&lt;/tr&gt;  &lt;tr bgcolor="#F2F2F2"&gt;&lt;td&gt;GWT Best Practices&lt;/td&gt;&lt;td&gt;B+&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;Tools to Write GWT Clients&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;The Enterprise means constraints: existing domain objects, maybe a crummy DAO, etc. Enterprise GWT apps will need things like custom serializers and custom generators to work around their legacy constraints, and Accelerated GWT covers these topics well. &lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td&gt;How to Design GWT Services&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;  &lt;tr&gt;&lt;td colspan="2"&gt;General advice about domain objects and writing RPC services is given and a DTO approach is avoided, which pleases me. Overall, however, not a lot of information is given on building "Enterprise" backends, which is part of the book's title.   &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-7058570155873273072?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/7058570155873273072/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=7058570155873273072' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7058570155873273072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7058570155873273072'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/01/accelerated-gwt-report-card.html' title='Accelerated GWT Report Card'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-2825967764758288717</id><published>2010-01-10T04:37:00.003-06:00</published><updated>2010-01-10T04:47:30.235-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>60 Second Agility: ROTI Meetings</title><content type='html'>Always in search of the absolute minimum of ceremony, my last team "discovered" a useful agile practice that takes 60 seconds from start to end: the ROTI Meeting.&lt;br /&gt;&lt;br /&gt;After every meeting, on the way out the door, draw a diagonal line on the whiteboard with the labels 0, 2, and 4.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dVhQbe4S9AM/S0mvWNxDAgI/AAAAAAAAAJ4/uiVFWTex4Bs/s1600-h/roti.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 400px;" src="http://3.bp.blogspot.com/_dVhQbe4S9AM/S0mvWNxDAgI/AAAAAAAAAJ4/uiVFWTex4Bs/s400/roti.png" alt="" id="BLOGGER_PHOTO_ID_5425060022331834882" border="0" /&gt;&lt;/a&gt;Each person in turn gives a number on how the meeting performed as a "Return on Time Invested" and the person with the marker draws in the rating. Here is the rating scale we used:&lt;br /&gt;&lt;br /&gt;0 = "I'd have been better off making a Starbuck's run. Complete waste of time"&lt;br /&gt;1 = "You really should have let me stay at my desk and code"&lt;br /&gt;2 = "This was an OK meeting. About as valuable as if I'd been coding"&lt;br /&gt;3 = "Surprisingly, this was more valuable than if I'd been writing code"&lt;br /&gt;4 = "Wow, this meeting saved me tons of time. Thank goodness I didn't skip it to code"&lt;br /&gt;&lt;br /&gt;And then each person answers the same question, "What could be done to improve your number by one point?"&lt;br /&gt;&lt;br /&gt;To do this in 60 seconds means there is no discussion. The feedback is what it is; no debating, no fixing problems, and no hurt feelings. &lt;br /&gt;&lt;br /&gt;ROTI meetings create tacit, organization knowledge that can be acted upon by team members in the future. It drives a team towards less meetings (almost always a good thing), pushes team members to be more respectful of each others time and expertise, and influences meeting organizers to craft more succinct, on topic, and meaningful gatherings. It takes only 60 seconds so you might as well try it a few time!&lt;br /&gt;&lt;br /&gt;... and now the historical details.&lt;br /&gt;&lt;br /&gt;ROTI analysis is nicely described in Esther Derby's great book "&lt;a href="http://pragprog.com/titles/dlret/agile-retrospectives"&gt;Agile Retrospectives&lt;/a&gt;". The practice in the context of iteration retrospectives takes more lie 5 to 10 minutes. Our team found ROTI to be so effective in retrospectives that we shortened it and held one at the end of every meeting.&lt;br /&gt;&lt;br /&gt;The actual ROTI scale is a bit more formal than what we created:&lt;br /&gt;&lt;br /&gt;0 - Lost Principle: No Benefit Received for Time Invested Break-Even:   &lt;br /&gt;1 -&lt;br /&gt;2- Received Benefit Equal to Time Invested High Return on Investment   &lt;br /&gt;3 -&lt;br /&gt;4 - Received Benefit Greater than Time Invested&lt;br /&gt;&lt;br /&gt;Lastly, ROTI charts are covered in detail a &lt;a href="http://www.ayeconference.com/the-roti-method-of-gauging-meeting-effectiveness/"&gt;few&lt;/a&gt; &lt;a href="http://blog.energizedwork.com/2006/09/retrospectives-action-begets-action.html"&gt;other&lt;/a&gt; &lt;a href="http://www.bencoombs.com/bens_blog/2008/08/agile-retrospec.html"&gt;places&lt;/a&gt; as well.&lt;br /&gt;&lt;br /&gt;For a mere 60 second investment, this practice is worth trying on your team.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-2825967764758288717?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/2825967764758288717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=2825967764758288717' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/2825967764758288717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/2825967764758288717'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/01/60-second-agility-roti-meetings.html' title='60 Second Agility: ROTI Meetings'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dVhQbe4S9AM/S0mvWNxDAgI/AAAAAAAAAJ4/uiVFWTex4Bs/s72-c/roti.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6835006282037973037</id><published>2010-01-09T15:48:00.007-06:00</published><updated>2010-01-10T04:49:36.602-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>"GWT In Practice" Report Card</title><content type='html'>&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Student Name:&lt;/td&gt;&lt;td&gt;&lt;strong&gt;GWT In Practice&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;School:&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Manning&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;School Year:&lt;/td&gt;&lt;td&gt;&lt;strong&gt;2008&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Teacher:&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Hamlet D'Arcy&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Overall Grade:&lt;/td&gt;&lt;td&gt;&lt;strong&gt;B&lt;/strong&gt; (solid effort; time well spent; not enough on client side)&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Grading Scale: A=Outstanding, B=Good, C=Average, D=Poor, F=Fail &lt;table border="1"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr style="font-weight: bold;" bgcolor="#f2f2f2"&gt;&lt;td&gt;Server Side Programming&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr style="font-weight: bold;"&gt;&lt;td&gt;Knowledge of GWT RPC (Remote Procedure Calls)&lt;/td&gt;&lt;td&gt;A+&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;How Ajax calls are made from the client to the server using GWT RPC is clearly explained in a variety of use cases (almost too many!). The difficult to understand relationship between service interfaces, server/servlet implementations, and the client asynchronous interface is explained in words, with diagrams, and within the IDE. Explaining GWT RPC is where GWT in Practice really shines... and this topic is still relevant today in GWT 2.0.&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr style="font-weight: bold;"&gt;&lt;td&gt;Knowledge of Alternative Server Stacks&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;GWT in Practice demonstrates how to consume REST and POX services with GWT, how to integrate Flash for SOAP services (not a good idea IMO), how to use Java Applets(!) for a SOAP client, and how to use Comet for streaming data to clients. The book focuses so much on server side technologies that perhaps it should have been called "GWT Server Stack Recipes".&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr style="font-weight: bold;"&gt;&lt;td&gt;Knowledge of Security Concerns&lt;/td&gt;&lt;td&gt;A&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;The Manning "In Practice" imprint means the author is targeting real world developer concerns rather than giving a generic overview, and security is one of these real world concerns. GWT in Practice does a great job explaining all the cross site scripting concerns (and how to work around them), security certificate issues (and how to work with them), and how to configure Tomcat security (which isn't even unique to GWT). It's clear the authors have real experience with securing a GWT app in a variety of contexts.&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr style="font-weight: bold;"&gt;&lt;td&gt;Knowledge of GWT Testing&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;GWT ships with both GWTTestCase (for easing the testing of asynchronous and multithreaded components) and a performance benchmarking tool. The tools are straightforward and covered in every other GWT text as well. While a testing section is essential to any GWT book, this one didn't stand out against the other material. I'd have liked to see more testing best practices. Plus, GWT ships with a new performance testing tool, so this section is starting to age.&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr style="font-weight: bold;"&gt;&lt;td&gt;Creative Code Samples&lt;/td&gt;&lt;td&gt;B&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;The book deomonstrates how to turn on history to support the browser back button and how to record and playback certain Comet messages. The former is useful (and part of the GWT project) while the latter seems unlikely to be needed by almost any other GWT developer (and is custom implemented for the book).&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;table border="1"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr style="font-weight: bold;" bgcolor="#f2f2f2"&gt;&lt;td&gt;Client Side Programming&lt;/td&gt;&lt;td&gt;C+&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td style="font-weight: bold;"&gt;Knowledge of Standard GWT Widget Set&lt;/td&gt;&lt;td style="font-weight: bold;"&gt;C&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;Granted, the "in Practice" title is not meant to be a basic introduction, but there is almost no material on the standard GWT widget set. If you want to know all the user interface widgets supported by GWT then look elsewhere. However, some widget layout and CompositeWidget material was covered, the GWT in Practice salvages a C grade.&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td style="font-weight: bold;"&gt;Knowledge of JSNI (JavaScript Native Interface)&lt;/td&gt;&lt;td style="font-weight: bold;"&gt;B&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;Surely the most controversial part of GWT is the ability to embed JavaScript within multiline comments of Java files. Sounds nasty even if IDEA does support refactoring and highlighting, right? (And as of 2.0, Eclipse does as well). This books contains a ton of JSNI. Pages of it, actually; which isn't always a good thing for the book or for GWT. GWT in Practice will definitely show you how to wrap JavaScript libraries, even if it makes for poor reading. The best part of the JSNI examples was the recipe for adding drag and drop, which appeared twice in the book for some reason. If you need drag and drop or to wrap a JavaScript library then this is the book for you!&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td style="font-weight: bold;"&gt;Knowledge of CSS Styling&lt;/td&gt;&lt;td style="font-weight: bold;"&gt;B&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;CSS styling gets a whole 2 pages. Which means there isn't much to say beyond what the browser offers already.&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr style="font-weight: bold;"&gt;&lt;td&gt;General Client Concerns&lt;/td&gt;&lt;td&gt;C&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;There simply wasn't enough information about client side programming in GWT in Practice. The example that were shown left me wondering, "Is that something I'll really need to do?"&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table border="1"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr bgcolor="#f2f2f2"&gt;&lt;td style="font-weight: bold;"&gt;GWT Best Practices&lt;/td&gt;&lt;td style="font-weight: bold;"&gt;B+&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td style="font-weight: bold;"&gt;How to Design GWT Services&lt;/td&gt;&lt;td style="font-weight: bold;"&gt;A&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;This is the only book I found that included best practices about how to design services, which the author recommended using DTOs and keeping interfaces seperate from implementations to decouple physical services. However, some of the diagrams seemed forced and pointless (and they were, did you know Manning requires a visual aid on every spread?)&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td style="font-weight: bold;"&gt;How to Design GWT Clients&lt;/td&gt;&lt;td style="font-weight: bold;"&gt;F&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;What should client side design be in an Ajax application that consists of pretty much just one web page? This wasn't covered at all. Note to authors: please include this in your GWT 2.0 update! Also, there was no coverage of how to deal with degenerate browsers like IE6. This is the bane of my current project and any hints would be appreciated.&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td style="font-weight: bold;"&gt;Knowledge of the Best Tools for the Job&lt;/td&gt;&lt;td style="font-weight: bold;"&gt;B+&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td colspan="2"&gt;GWT in Practice shows NetBeans, Eclipse, and IDEA in action. The most helpful diagram of how a GWT project is structured was actually an IDE screenshot. For builds, the Maven plugin is covered ad naseum, which is understandable considering the authors wrote it. But still, Maven is dead to me so it was time wasted (now where is that Gradle GWT plugin)?&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;table border="1"&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr style="font-weight: bold;" bgcolor="#f2f2f2"&gt;&lt;td&gt;Teacher Comments&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Even in light of the GWT 2.0 release, GWT in Practice holds up as a solid GWT book for newcomers. It definitely favors the server side and gives the client side short shrift. My biggest complaint was that it seemed to be a lot of recipes bundled into an "in Practice" format, and many of the recipes I didn't need (Flex? Applets?). Given the book is from 2008 when GWT had just been released, I wanted to dislike it. But it's held up quite well. It should not be the only GWT book you read, but probably it should be one of them. &lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6835006282037973037?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6835006282037973037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6835006282037973037' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6835006282037973037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6835006282037973037'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/01/gwt-in-practice-report-card.html' title='&quot;GWT In Practice&quot; Report Card'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6926036744223193653</id><published>2010-01-07T01:31:00.003-06:00</published><updated>2010-01-07T01:51:09.291-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy AST Transformations by Example: Adding Methods to Classes</title><content type='html'>What can you do with a &lt;a href="http://groovy.codehaus.org/Compile-time+Metaprogramming+-+AST+Transformations"&gt;Groovy AST Transformation&lt;/a&gt;? A difficult question, considering the answer is "almost anything". One frequent use of AST Transformations is to write Groovy changes into the JVM .class files so that standard Java tools will know about them. For instance, the bytecode changes produced by &lt;a href="http://docs.codehaus.org/display/GROOVY/Delegate+transformation"&gt;@Delegate&lt;/a&gt; are visible and usable from plain old Java classes. This example is going to walk you through how to add synthesized methods to a class at compile time using a Groovy AST Transformation and the AST Builder. It makes an interesting test case since it explores some of the edge cases and common pitfalls. This should be fun...&lt;br /&gt;&lt;br /&gt;(And for those of you who want to skip all this and just see the code, check out the latest Groovy example in SVN and just run the Ant script).&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;svn co http://svn.codehaus.org/groovy/trunk/groovy/groovy-core/src/examples/astbuilder&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;To start, let's better define our example. Consider the class with a public API and also a standard main() method. Frequently, the main() method simply instantiates the class and calls a single method. Wouldn't it be nice to annotate a method so that it is treated like a main method? What if this were possible:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;class MainExample {&lt;br /&gt;&lt;br /&gt;   @Main&lt;br /&gt;   public void greet() {&lt;br /&gt;       println "Hello from the greet() method!"&lt;br /&gt;   }   &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;At compile time, this annotation would synthesize a proper main method and run the same code as greet(). (We'll worry about calling an instance method from a static method later). Transforming this annotation in the AST means that both Java and Groovy would see the main() method. Let's do it; there are three things you need:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;An @Main marker interface&lt;/li&gt;&lt;li&gt;An ASTTransformation implementation make the AST changes&lt;/li&gt;&lt;li&gt;A test harness (trust me, you want this)&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;The &lt;a href="http://svn.codehaus.org/groovy/trunk/groovy/groovy-core/src/examples/astbuilder/Main.groovy"&gt;@Main&lt;/a&gt; marker interface is the easiest piece. The marker interface is used to a standard Java 5 annotation to an &lt;a href="http://groovy.codehaus.org/gapi/org/codehaus/groovy/transform/ASTTransformation.html"&gt;ASTTransformation&lt;/a&gt; implementation:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;@Retention (RetentionPolicy.SOURCE)&lt;br /&gt;@Target ([ElementType.METHOD])&lt;br /&gt;@GroovyASTTransformationClass (["MainTransformation"])&lt;br /&gt;public @interface Main {  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This is just a standard Java 5 annotation. The retention policy is SOURCE so that other objects don't see the annotation at runtime when using reflection (there is no need). The ElementType is METHOD because we only want to apply the annotation to methods. And the GroovyASTTransformationClass is "MainTransformation". This value is the fully qualified classname of the ASTTransformation implementation that the Groovy compiler is going to call when an @Main annotation is found. In practice, you will need to specify a package... I left one off here for simplicity.&lt;br /&gt;&lt;br /&gt;So this annotation will wire @Main into a class called &lt;a href="http://svn.codehaus.org/groovy/trunk/groovy/groovy-core/src/examples/astbuilder/MainTransformation.groovy"&gt;MainTransformation&lt;/a&gt;. I suppose we'd better go make this class then...&lt;br /&gt;&lt;br /&gt;The ASTTransformation interface defines one method:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;void visit(ASTNode[], SourceUnit)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The best way to understand the contents of the two parameters is to write several tests and inspect them in a debugger, and then use the AST Browser to analyze the syntax tree. In general, the ASTNode array contains what you want to manipulate and the SourceUnit provides services like error and warning reporting. Here is the skeleton of our MainTransformation that is going to add a synthesized main() method to the class:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)&lt;br /&gt;public class MainTransformation implements ASTTransformation {&lt;br /&gt;  &lt;br /&gt;   void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {&lt;br /&gt;&lt;br /&gt;       if (!astNodes) return&lt;br /&gt;       if (!astNodes[0]) return&lt;br /&gt;       if (!astNodes[1]) return&lt;br /&gt;       if (!(astNodes[0] instanceof AnnotationNode)) return&lt;br /&gt;       if (astNodes[0].classNode?.name != Main.class.getName()) return&lt;br /&gt;       if (!(astNodes[1] instanceof MethodNode)) return&lt;br /&gt;&lt;br /&gt;       MethodNode annotatedMethod = astNodes[1]&lt;br /&gt;       ClassNode declaringClass = astNodes[1].declaringClass&lt;br /&gt;&lt;br /&gt;       // makeMainMethod synthesizes a method!&lt;br /&gt;       MethodNode mainMethod = makeMainMethod(annotatedMethod)&lt;br /&gt;       declaringClass.addMethod(mainMethod)&lt;br /&gt;   }&lt;br /&gt;   ...&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Again, there are a few interesting things to notice here...&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The compiler phase chosen was INSTRUCTION_SELECTION, which was a completely arbitrary decision. Please, if you want to know which phase to target then ask on the &lt;a href="http://groovy.codehaus.org/Mailing+Lists"&gt;groovy-user&lt;/a&gt; mailing list (and asking will give us better hints as to what we need to document on the wiki).&lt;/li&gt;&lt;li&gt;The body of the transformations contains many guard clauses as a safeguard against NullPointerExceptions and unexpected input. The AST of classes changes from version to version. Defensive programming and thorough test cases highly recommended.&lt;/li&gt;&lt;li&gt;The MethodNode that was annotated comes through in the ASTNode array, and from there you can navigate most anywhere within the syntax tree.&lt;/li&gt;&lt;li&gt;The makeMainMethod is going to copy the body of the annotated method and then we will add that method back onto the declaring class.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;The last thing to do is define the makeMainMethod that actually creates the main():&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;MethodNode makeMainMethod(MethodNode source) {&lt;br /&gt;   def ast = new AstBuilder().buildFromSpec {&lt;br /&gt;       method('main', ACC_PUBLIC | ACC_STATIC, Void.TYPE) {&lt;br /&gt;           parameters {&lt;br /&gt;               parameter 'args': String[].class&lt;br /&gt;           }&lt;br /&gt;           exceptions {}&lt;br /&gt;           block { }&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;   MethodNode newMainMethod = ast[0]&lt;br /&gt;   newMainMethod.code = source.code&lt;br /&gt;   newMainMethod&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Again, a few bits and pieces to make special note of:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The AstBuilder.buildFromSpec is a DSL convenience over the concrete constructors of ASTNode and its subclasses. Thus, the API of buildFromSpec mirrors the API of the ASTNode classes. If you want to understand the arguments and parameters types, then look at the ASTNode Javadoc. In this regard, the buildFromSpec is more about making the code easier to read rather than easier to write.&lt;/li&gt;&lt;li&gt;The return type of the method is &lt;span style="font-weight: bold;"&gt;Void.TYPE&lt;/span&gt; and &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;Void.class&lt;/span&gt;. Void.class is a real class with real usages, Void.TYPE is the symbol for "little vee void".&lt;/li&gt;&lt;li&gt;The modifiers are ACC_PUBLIC | ACC_STATIC. Notice the use of | and &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; &amp;amp;. Let me editorialize briefly: I don't understood bitmasks, I never understood them, and people who design APIs around parameters typed as "int modifers" will be first against the wall when the revolution comes. If null was the &lt;a href="http://lambda-the-ultimate.org/node/3186"&gt;billion dollar mistake&lt;/a&gt; then bitmasks at least deserve to be in the tens of millions range. Anyway...&lt;/li&gt;&lt;li&gt;The codeblock of the new main method is just a reference to the codeblock of the method annotated with @Main. This will cause duplicate bytecode to be written out into the .class file (bad) but does make for a small, clear example (good). In production, you probably want to invoke the @Main method instead of copy the body.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Now, as you can see from the javap output, the compiled MainExample.groovy contains a real, live Java main class:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;hdarcy:$ groovyc MainExample.groovy&lt;br /&gt;hdarcy:$ javap MainExample&lt;br /&gt;Compiled from "MainExample.groovy"&lt;br /&gt;public class MainExample extends java.lang.Object implements groovy.lang.GroovyObject{&lt;br /&gt;   ...&lt;br /&gt;   public void greet();&lt;br /&gt;   ...&lt;br /&gt;   public static void main(java.lang.String[]);&lt;br /&gt;   ...&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Phew! That was a lot of information. The last thing to add is a simple test case using Groovy's TranformTestHelper class. A debugger helps AST Transformation development immensely, and this integration test is one way to hook one up to your transformation. I tested this in IDEA but it should work fine in Eclipse/Netbeans as well:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;class MainIntegrationTest extends GroovyTestCase {&lt;br /&gt;&lt;br /&gt;    public void testInvokeUnitTest() {&lt;br /&gt;&lt;br /&gt;       def file = new File('./MainExample.groovy')&lt;br /&gt;       assert file.exists()&lt;br /&gt;&lt;br /&gt;       def invoker = new TranformTestHelper(new MainTransformation(), CompilePhase.CANONICALIZATION)&lt;br /&gt;&lt;br /&gt;       def clazz = invoker.parse(file)&lt;br /&gt;       def tester = clazz.newInstance()&lt;br /&gt;       tester.main(null)       // main method added with AST transform&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This test case takes the example class as a simple File and then compiles it using the MainTransformation we defined. This is a great way to invoke both local and global transformations from unit tests. I'm sure there is an easier way to invoke the static main method without instantiating the class, but I'm tired and don't care all that much. It's just an example!&lt;br /&gt;&lt;br /&gt;And that's it... we created a marker interface to trigger an annotation, created an ASTTransformation to add a method onto a class, and wrote a test harness. There are just two loose ends to tie up:&lt;br /&gt;&lt;br /&gt;How can a static main method invoke a non static method like Greet? We'll, it can't really. For this example we just copied the method body into the main method. In practice, you'd want to make sure only static methods were annotated.&lt;br /&gt;&lt;br /&gt;How are inner classes handled? Short answer: not the same way. You have a test case, so just write a test method and find out!&lt;br /&gt;&lt;br /&gt;All the code was checked into the Groovy examples folder along with an Ant script. There's no better time to get the source:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;svn co http://svn.codehaus.org/groovy/trunk/groovy/groovy-core/src/examples/astbuilder&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;cd examples/astbuilder and away you go.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6926036744223193653?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6926036744223193653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6926036744223193653' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6926036744223193653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6926036744223193653'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2010/01/groovy-ast-transformations-by-example.html' title='Groovy AST Transformations by Example: Adding Methods to Classes'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3970858148545895729</id><published>2009-12-12T22:42:00.002-06:00</published><updated>2009-12-12T22:53:01.288-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Java 5 + GPars: Throttling Action Processing</title><content type='html'>An interesting question came up on the &lt;a href="http://gpars.codehaus.org/"&gt;GPars&lt;/a&gt; mailing list today: In a system that generates events, what is the best way to throttle back event processing to one event per second? I thought about an answer... then thought some more... and finally decided to write it all up in this blog post. The example uses Groovy and GPars, but it is easily adapted to a generic Java solution. Don't let the actors scare you! (or the lack of semi-colons, for that matter).&lt;br /&gt;&lt;br /&gt;The example is the classic "&lt;a href="http://en.wikipedia.org/wiki/Sleeping_barber_problem"&gt;Sleeping Barber&lt;/a&gt;" problem (I hadn't heard of it either). Basically, there is a barbershop. The barber is asleep. Customers walk into the waiting room periodically, and the barber wakes up to give each of them a haircut. When he's done he returns to his slumber. It's a lesson in reaction: something is asleep, then awakens to do some work, then returns to sleep.&lt;br /&gt;&lt;br /&gt;The GPars docs provide a decent &lt;a href="http://code.google.com/p/gparallelizer/wiki/ActorsExamples"&gt;Actor based solution&lt;/a&gt; to this problem: there is a waiting room and a barber, and both are actors. When the barber is free, a customer from the waiting room is moved into the barber's chair. The barber and waiting room communicate via actor messages. But what if our barber is a bit of a diva, and no matter how busy the shop gets, he wants to give one haircut every 15 minutes and never any more (otherwise, he might get burnt out you see). That is the throttling problem: how do you make sure events are processed (a haircut is given) no more than x number of times in a given time period?&lt;br /&gt;&lt;br /&gt;My solution: keep a work queue, and have a scheduled executor pull work off the queue at a specified interval. Java 5 gives you all the tools to do this without resorting to busy waiting, polling, or writing scheduling code. The classes you need to know about are &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/ArrayBlockingQueue.html"&gt;ArrayBlockingQueue&lt;/a&gt; and &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html"&gt;ScheduledThreadPoolExecutor&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;ArrayBlockingQueue is a FIFO (First-In-First-Out) queue that supports blocking instead of busy waiting. When you take() an item from an ABQ, the call blocks until an item is available... no polling or sleeping to see if an item is ready to available. Just call take() and your code won't proceed until there is an element found.&lt;br /&gt;&lt;br /&gt;The ScheduledThreadPoolExecutor supports executing both &lt;a href="http://java.sun.com/javase/6/docs/api/java/lang/Runnable.html"&gt;Runnable&lt;/a&gt; and &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/Callable.html"&gt;Callable&lt;/a&gt; objects at a fixed interval. If you're looking to execute the same task every 1 second then STPE is what you need... Timer, for all intents and purposes, has been deprecated.&lt;br /&gt;&lt;br /&gt;So here's the barber that just won't stand to be over-worked... setting it all up we need customers, a barber, and a waiting room:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;class Customer {&lt;br /&gt; String name&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// waiting room can't hold more than 12!&lt;br /&gt;def waitingRoom = new ArrayBlockingQueue(12)&lt;br /&gt;&lt;br /&gt;def barber = Executors.newScheduledThreadPool(1)&lt;br /&gt;barber.scheduleAtFixedRate({&lt;br /&gt;     println 'Barber: Next customer please!'&lt;br /&gt;     Customer customer = waitingRoom.take()&lt;br /&gt;     println "${customer.name} gets a haircut at ${new Date().format('H:m:s')}"&lt;br /&gt; } as Runnable, 0, 15, TimeUnit.MINUTES)&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Customer is a simple bean; nothing interesting here. The waiting room is an ArrayBlockingQueue filled with customers that need a haircut. And the barber is an executor service with a scheduled task to give haircuts. The number of threads in the scheduled thread pool is 1 because there's only one barber. The barber takes customers from the waiting room and cuts their hair once every 15 minutes. The call to waitingRoom.take() is blocking... if there is a customer ready then he is serviced immediately, and if one is not, then the call blocks until someone is available. Once thing to note... the waitingRoom has a size of 12... if a 13th customer is added then the calling code will either block until there is enough room or throw an exception. There is an API to do either case.&lt;br /&gt;&lt;br /&gt;So how do customers get into the waiting room? That's where GPars actors come in. The barber shop is a "reactor" in GPars terminology. Messages can be sent to the barbershop ("Enter" the waiting room), and the reactor adds the customer to the waiting room. A maître d' of sorts. Here it is in action:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def barberShop = new PooledActorGroup().reactor {message -&amp;gt;&lt;br /&gt; switch (message) {&lt;br /&gt;     case Enter:&lt;br /&gt;         println "${message.customer.name} waits for a haircut..."&lt;br /&gt;         waitingRoom.add(message.customer)&lt;br /&gt;         break&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Enter {&lt;br /&gt; Customer customer&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;barberShop &amp;lt;&amp;lt; new Enter(customer: new Customer(name: 'Jerry'))&lt;br /&gt;barberShop &amp;lt;&amp;lt; new Enter(customer: new Customer(name: 'Phil'))&lt;br /&gt;barberShop &amp;lt;&amp;lt; new Enter(customer: new Customer(name: 'Bob'))&lt;br /&gt;barberShop &amp;lt;&amp;lt; new Enter(customer: new Customer(name: 'Ron'))&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The barberShop is a PooledActorGroup, a GPars object, and the "actor framework" just means adding a closure to the reactor() method of that group. The closure, or actor, and responds to Enter messages by adding the customer to the waitingRoom. At the bottom you see the nice &amp;lt;&amp;lt; syntax for posting events to the ActorGroup.&lt;br /&gt;&lt;br /&gt;So there you have it. There are many ways to do this, but I think the Java 5 Concurrency libraries are some of the best options. I'd be interested to hear other ideas too. Now go give those hippies some haircuts!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3970858148545895729?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3970858148545895729/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3970858148545895729' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3970858148545895729'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3970858148545895729'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/12/java-5-gpars-throttling-action.html' title='Java 5 + GPars: Throttling Action Processing'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3797363111518240254</id><published>2009-12-12T09:07:00.002-06:00</published><updated>2009-12-12T09:11:46.399-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy Shell gets some Color</title><content type='html'>Well, well, it looks like &lt;a href="http://groovy.codehaus.org/Groovy+Shell"&gt;Groovy Shell&lt;/a&gt; (groovysh) is starting to catch up to the other IDEs. Yesterday, support for colored output was added!&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://jansi.fusesource.org/"&gt;Jansi library&lt;/a&gt; has added to the Groovy 1.8 snapshot, and now you get color coded output on all platforms, including Windows. Here is an Ubuntu screenshot:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dVhQbe4S9AM/SyOx7rxQqRI/AAAAAAAAAJk/7bV5h8Q3nhQ/s1600-h/colorgroovysh.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 398px;" src="http://4.bp.blogspot.com/_dVhQbe4S9AM/SyOx7rxQqRI/AAAAAAAAAJk/7bV5h8Q3nhQ/s400/colorgroovysh.png" alt="" id="BLOGGER_PHOTO_ID_5414366815949203730" border="0" /&gt;&lt;/a&gt;And here's how to make it work in 3 easy steps:&lt;br /&gt;&lt;br /&gt;1) &lt;a href="http://jansi.fusesource.org/downloads/index.html"&gt;Download Jansi&lt;/a&gt; and put it in your classpath&lt;br /&gt;2) Get the &lt;a href="http://build.canoo.com/groovy/artifacts/"&gt;nightly Groovy install&lt;/a&gt;*&lt;br /&gt;3) Invoke groovysh with the -C parameter!&lt;br /&gt;&lt;br /&gt;* As an alternative, it is incredibly simple to &lt;a href="http://groovy.codehaus.org/Building+Groovy+from+Source"&gt;build Groovy from source&lt;/a&gt;:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;svn co https://svn.codehaus.org/groovy/trunk/groovy/groovy-core&lt;br /&gt;ant install -DskipTests=true&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Happy Evaluating!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3797363111518240254?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3797363111518240254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3797363111518240254' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3797363111518240254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3797363111518240254'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/12/groovy-shell-gets-some-color.html' title='Groovy Shell gets some Color'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_dVhQbe4S9AM/SyOx7rxQqRI/AAAAAAAAAJk/7bV5h8Q3nhQ/s72-c/colorgroovysh.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-7127442018231718774</id><published>2009-12-10T20:07:00.003-06:00</published><updated>2009-12-10T20:27:21.156-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy 2009 Year in Review and 2010 Predictions</title><content type='html'>&lt;span style="font-weight: bold;font-size:180%;" &gt;Groovy in 2009&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Groovy 1.6 Released&lt;/span&gt;&lt;br /&gt;Groovy 1.6 was released at the beginning of the year, and the most exciting new features have turned out to be &lt;a href="http://groovy.codehaus.org/Grape"&gt;Grape&lt;/a&gt; and &lt;a href="http://groovy.codehaus.org/Compile-time+Metaprogramming+-+AST+Transformations"&gt;AST Transformations&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Grape allows a developer to declare dependencies within their Groovy source code and then, at runtime, Groovy will download and install the dependencies using Ivy repositories. Want to ship scripts to your operations team? You no longer need to email or build JARs! It's no Jigsaw, but maybe that's a good thing.&lt;br /&gt;&lt;br /&gt;AST Transformations allow developers to hook into the Groovy compiler and alter the way the code is compiled. This has enabled great work like the &lt;a href="http://groovy.codehaus.org/Bindable+and+Vetoable+transformation"&gt;@Bindable&lt;/a&gt; and &lt;a href="http://groovy.codehaus.org/Delegate+transformation"&gt;@Delegate&lt;/a&gt; annotations, as well as many forward thinking (read: visionary) libraries like the &lt;a href="http://code.google.com/p/spock/"&gt;Spock&lt;/a&gt; testing framework and the &lt;a href="http://codenarc.sourceforge.net/"&gt;CodeNarc&lt;/a&gt; static code analysis tools. Watch for more cool libraries and frameworks to use these features in 2010.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Griffon Released&lt;/span&gt;&lt;br /&gt;While Flex and JavaFX duked it out for developer mindshare in the coveted (and hyped) RIA space, a groovier team quietly forked the Grails codebase and adapted it for Swing desktop applications. &lt;a href="http://griffon.codehaus.org/"&gt;Griffon&lt;/a&gt; is way more than a dynamically typed builder pattern on top of Swing components. Griffon gives you property binding to widgets (you're not the only one Flex), a standard and simple MVC architecture without a &lt;a href="http://puremvc.org/images/stories/puremvc-icon.jpg"&gt;spaghetti monster diagram&lt;/a&gt; (that's you PureMVC), more components than just a TextBox (the complete JavaFX widget set last Winter), a plugin system that allows you to decompose problems into &lt;a href="http://griffon.codehaus.org/Plugins"&gt;reusable addons&lt;/a&gt;, and an easy way to deploy your app via webstart. If the Griffon team can keep the energy they had in 2009 then 2010 should be the year of the lion. Or eagle... or dog. What the hell is a griffon anyway?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Groovy Tooling Explosion&lt;/span&gt;&lt;br /&gt;Looks like &lt;a href="http://www.jetbrains.com/idea/features/groovy_grails.html"&gt;IntelliJ IDEA&lt;/a&gt; has some competition for best Groovy IDE. The &lt;a href="http://groovy.codehaus.org/Eclipse+Plugin"&gt;Groovy Eclipse&lt;/a&gt;  plugin got new life as Andrew Eisenberg revived the project, and SpringSource released better Grails support in &lt;a href="http://www.grails.org/STS+Integration"&gt;SpringSource Tool Suite&lt;/a&gt;. Was the open sourcing of IDEA a response to the new competition? Who cares, it's free now! While IDEA is still the best IDE for Groovy, Groovy users will surely benefit from each IDE maker trying to outdo the other. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VMWare Buys SpringSource&lt;/span&gt;&lt;br /&gt;Seriously, who saw this coming? This week at &lt;a href="http://www.grails-exchange.com"&gt;Groovy/Grails Exchange&lt;/a&gt;, Graeme Rocher demoed deploying to the cloud from his IDE (according to Twitter). Easy cloud deployment is good news... it will end the monthly "who do you use for Java hosting?" questions on user groups. Now if only the price would come down.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;GR8 Conference&lt;/span&gt;&lt;br /&gt;A &lt;a href="http://www.gr8conf.org/"&gt;Groovy conference&lt;/a&gt; created by the community, for the community, and priced for the community. It's great to see not for profit additions to the Groovy conference scene, and next year sees &lt;span style="font-style: italic;"&gt;two&lt;/span&gt; GR8 events: one in Europe and one in North America (Minneapolis!). In other community news, Chicago Groovy Users Group started posting &lt;a href="http://cgug.blip.tv/"&gt;video sessions&lt;/a&gt; to blip.tv. Can we get some other GUGs to do the same?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;A Groovy 2010&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Don't think of these as predictions... think of them more as premature facts.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Gradle&lt;/span&gt;&lt;br /&gt;To be clear: &lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt; is not a Groovy technology. It is an enterprise build system written in Java with Groovy used as a build script. Anyway, the 0.9 release will include "Smart Execution/Incremental Compile" and 1.0 will support multi-threaded builds. These are enterprise level features that would be totally unique to Gradle... and they're sure to intice a lot of unhappy Maven developers. If the Gradle team can hit 1.0 and publish a book(!), then a lot of people will migrate.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;GPars&lt;/span&gt;&lt;br /&gt;I can't find anyone with anything bad to say about either the &lt;a href="http://hamletdarcy.blogspot.com/2008/08/java-forkjoin-groovy.html"&gt;Fork/Join Framework&lt;/a&gt; or BMW Motorcycles... and I just sold my bike to spend more time coding. GParallelizer hasn't been widely adopted to date, in my opinion because it chased the Actor-Model hype a little too strongly. But now it's been rebranded &lt;a href="http://gpars.codehaus.org/"&gt;GPars&lt;/a&gt; and an &lt;a href="http://gpars.codehaus.org/Team"&gt;all-star team&lt;/a&gt; has been assembled to work on it. This isn't a good project to &lt;span style="font-style: italic;"&gt;just&lt;/span&gt; follow, it's a good project to download and play with. Get the bits and join the mailing list. Your opinion counts! It's too bad that they hate cool the &lt;a href="http://gpars.codehaus.org/download/attachments/130777232/gpars_zombie.png"&gt;logo I made for them&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Griffon&lt;/span&gt;&lt;br /&gt;The decision by the Grails team to make almost everything a plugin was genius. It provides a standard mechanism for everyone to modularize their own applications, and provides an easy path for users to push their non-business-critical plugins back into the community. If Griffon users embrace the plugin system, and then push their plugins back to the community, then Griffon could be a real alternative to JavaFX/Flex by the end of the year.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Java Closures&lt;/span&gt;&lt;br /&gt;I wish the JDK team the best of luck meeting their September 2010 release deadline. While I have doubts that JDK 7 will ship in 2010, I do believe the closure syntax will be decided upon. And Groovy will be the first Java language to support that syntax. Whether a version of Groovy containing Java closures actually ships &lt;span style="font-style: italic;"&gt;before&lt;/span&gt; JDK 7 is probably dependent on how the Groovy team wants to address the modularization issues of Jigsaw, which sounds like a much harder problem to solve.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Groovy IDE Support Improves... a little&lt;/span&gt;&lt;br /&gt;IntelliJ IDEA still leads in features by a wide margin, but Eclipse and STS aren't stealing IDEA users, they're stealing TextMate users. People just want to debug without parsing all the files in the world. IDEA will remain the sole provider of Groovy refactorings, intentions, and auto-completions. But Eclipse will finally become a better alternative than a text editor. However, the open sourceing of IDEA should make it easier (and faster) to get IDEA support for newer frameworks, which is a good thing.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Groovy-User Mailing List Shuts Down&lt;/span&gt;&lt;br /&gt;For the entire month of June, all posts to groovy-user will be answered with the same response: "This is covered in Groovy in Action 2nd Edition". By the end of the month admins will simply replace the mailing list home page with an advertisement for &lt;a href="http://www.manning.com/koenig2/"&gt;the book&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:180%;" &gt;What Won't Happen&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;InvokeDynamic&lt;/span&gt;&lt;br /&gt;&lt;a href="http://jcp.org/en/jsr/detail?id=292"&gt;InvokeDynamic&lt;/a&gt; is set to greatly improve implementing and running dynamic languages on the JVM. Only it won't be released until September 2010 at the earliest. Sure you can get the OpenJDK now, but most users won't do that. I predict InvokeDynamic being the story of 2011, not 2010... and even then I bet the JRuby guys beat us to it.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Java Store&lt;/span&gt;&lt;br /&gt;Let me get this straight... you want me to pay US$50 yearly so that I can give my Griffon app away free on the Java Store? You gotta be kidding. Griffon + the Java Store &lt;span style="font-style: italic;"&gt;could&lt;/span&gt; be a match made in heaven: Griffon makes JNLP Webstart simple to configure and the Java Store handles hosting the files. But Sun/Oracle is turning too many hobbiest and small time developers away with their entrance fee. Are you listening Mr Ellison? I said I want... oh wait, you're not listening. How hard would it be to make the Groovy Store?&lt;br /&gt;&lt;br /&gt;This was fun. What are your Groovy 2009 highlights and 2010 predictions?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-7127442018231718774?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/7127442018231718774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=7127442018231718774' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7127442018231718774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/7127442018231718774'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/12/groovy-2009-year-in-review-and-2010.html' title='Groovy 2009 Year in Review and 2010 Predictions'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3967841646524500521</id><published>2009-12-03T17:32:00.001-06:00</published><updated>2009-12-03T17:34:53.581-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><title type='text'>Simple XML Testing from Java</title><content type='html'>2009 is coming to a close and I'm writing a blog post about Java and XML. The blog's called "behind the times" for a reason: no fancy dynamic languages, JSON, or REST. Straight up XML on Java action. &lt;br /&gt;&lt;br /&gt;One of my favorite editions to our enterprise toolset this year was &lt;a href="http://xmlunit.sourceforge.net/"&gt;XMLUnit&lt;/a&gt;. We'd been using Groovy in testing, and multi-line strings led to a ton of &lt;a href="http://hamletdarcy.blogspot.com/2009/07/groovytesting-little-things-big-impact.html"&gt;expressiveness in test cases&lt;/a&gt;... but then we stopped using Groovy. I switched back to Java testing and was left with making String based assertions and doing String#contains() calls. Not ideal; enter XMLUnit. &lt;br /&gt;&lt;br /&gt;XMLUnit supports XML based equality comparisons so that things like these two snippets are equal: &lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;root/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;root&amp;gt;&amp;lt;/root&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;As well as these: &lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;root&amp;gt;data&amp;lt;/root&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;root&amp;gt;&lt;br /&gt;    data&lt;br /&gt;&amp;lt;/root&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In fact, there's a whole gaggle of options around what is a meaningful versus a meaningless difference. For instance, I often consider two dates equal as long as they are formatted correctly (ignoring those pesky timestamp issue is nice). &lt;br /&gt;&lt;br /&gt;The problem with XMLUnit is that the API is not as nice for the simple case as it could be. What I want is a simple &lt;a href="http://xunitpatterns.com/Custom%20Assertion.html"&gt;custom assertion&lt;/a&gt; that asserts two XML snippets as similar. Something like this: &lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;XmlAssertions.assertXmlSimilar(&amp;quot;&amp;lt;root/&amp;gt;&amp;quot;, &amp;quot;&amp;lt;root&amp;gt;&amp;lt;/root&amp;gt;&amp;quot;); &lt;br /&gt;XmlAssertions.assertXmlSimilar(&amp;quot;&amp;lt;root&amp;gt;data&amp;lt;/root&amp;gt;&amp;quot;, &amp;quot;&amp;lt;root&amp;gt;\ndata\n&amp;lt;/root&amp;gt;\n&amp;quot;); &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This was as simple as creating a small utility class and hiding the XMLUnit API behind a nicer custom assertion: &lt;br /&gt;&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;import java.util.List;&lt;br /&gt;import junit.framework.*; &lt;br /&gt;import org.custommonkey.xmlunit.*;&lt;br /&gt;&lt;br /&gt;public class XmlAssertions {&lt;br /&gt;&lt;br /&gt;    private static final String ERROR_MSG = &amp;quot;XML comparison failure. \nExpected: %s\nReceived: %s\n%s&amp;quot;; &lt;br /&gt;&lt;br /&gt;    static {&lt;br /&gt;         XMLUnit.setIgnoreWhitespace(true);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void assertXmlSimilar(String expected, String actual) {&lt;br /&gt;        try {&lt;br /&gt;            Diff diff = new Diff(expected, actual);&lt;br /&gt;            List differences = new DetailedDiff(diff).getAllDifferences();&lt;br /&gt;            Assert.assertTrue(&lt;br /&gt;                String.format(ERROR_MSG, expected, actual, differences), &lt;br /&gt;                diff.similar());&lt;br /&gt;        } catch (Exception ex) {&lt;br /&gt;             Assert.fail(String.format(ERROR_MSG, expected, actual, ex.getMessage())); &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The raw XMLUnit code is clearly not something you want to see within the body of a test method. The custom assertion seems simple, but it's made a real pleasure of writing XML based functional tests around all our web services.  Feel free to steal my code here: &lt;a href="http://svn.assembla.com/svn/SampleCode/xmlunit/XmlAssertions.java"&gt;http://svn.assembla.com/svn/SampleCode/xmlunit/XmlAssertions.java&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3967841646524500521?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3967841646524500521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3967841646524500521' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3967841646524500521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3967841646524500521'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/12/simple-xml-testing-from-java.html' title='Simple XML Testing from Java'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8186302968504789764</id><published>2009-10-25T13:08:00.002-05:00</published><updated>2009-10-25T13:14:03.431-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>The True and False of Groovy's AST Builder</title><content type='html'>Last week saw three(!) conference sessions on Groovy &lt;a href="http://groovy.codehaus.org/Compile-time+Metaprogramming+-+AST+Transformations"&gt; AST Transformations&lt;/a&gt;. At &lt;a href="http://www.springone2gx.com/"&gt;SpringOne2gx&lt;/a&gt; I started with an AST Transform &lt;a href="http://svn.assembla.com/svn/SampleCode/presentations/asttransformations/asttransformations.pdf"&gt;deep dive&lt;/a&gt;, &lt;a href="http://www.agiledeveloper.com/blog/"&gt;Venkat&lt;/a&gt; followed up with a more gentle, and better performed, overview of Transforms, and I finished out with a video taped AST talk at &lt;a href="http://thestrangeloop.com/"&gt;StrangeLoop&lt;/a&gt; (watch infoQ for the video).&lt;br /&gt;&lt;br /&gt;At the sessions there was some confusion about the API of the new AstBuilder in Groovy 1.7 (currently in RC1). Hopefully this post can clear that up.&lt;br /&gt;&lt;br /&gt;The AstBuilder helps you create abstract syntax trees, and the &lt;a href="http://docs.codehaus.org/display/GROOVY/Building+AST+Guide"&gt;User Guide&lt;/a&gt; is the best place to start learning about it. It lets you create the AST for code by simply passing the code into a method:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;List&amp;lt;ASTNode&amp;gt; x = new AstBuilder().buildFromCode { " a constant " }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The big question everyone has is, "What's in the List of ASTNodes?"&lt;br /&gt;&lt;br /&gt;The question is mostly easily answered by looking at GroovyConsole's AST Browser. Just type in "a constant" into GroovyConsole and press Ctrl+T/Cmd+T to view the AST:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dVhQbe4S9AM/SuSUM4u_GAI/AAAAAAAAAJc/DxERWW42SCk/s1600-h/constants.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 262px;" src="http://1.bp.blogspot.com/_dVhQbe4S9AM/SuSUM4u_GAI/AAAAAAAAAJc/DxERWW42SCk/s400/constants.png" alt="" id="BLOGGER_PHOTO_ID_5396601202605496322" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Do you see that there are two root nodes? A BlockStatement and a ClassNode? The reason for this is that all Groovy scripts are compiled into classes of type Script by the compiler. Remember, to the JVM there are no scripts, only classes. If you expand out the AST, you can see that the script (in this case, the ConstantExpression) is in two places in the AST: within the BlockStatement and within the Script#run method:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dVhQbe4S9AM/SuSUMuIMN2I/AAAAAAAAAJU/BpjYo82Pnk0/s1600-h/nodes.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 262px;" src="http://1.bp.blogspot.com/_dVhQbe4S9AM/SuSUMuIMN2I/AAAAAAAAAJU/BpjYo82Pnk0/s400/nodes.png" alt="" id="BLOGGER_PHOTO_ID_5396601199758423906" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;So this is why the AstBuilder returns a List of ASTNodes. You'll be returned both the script BlockStatement and the Script ClassNode. For the most part, you're probably only interested in the script and not the ClassNode. The boolean parameter on the buildFromCode and buildFromString methods exist so that you don't have to see that ClassNode. The default value of this 'statementsOnly' parameter is true, so be default you'll only be given the script BlockStatements.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;List&amp;lt;ASTNode&amp;gt; x = new AstBuilder().buildFromCode { " a constant " }&lt;br /&gt;&lt;br /&gt;assert x[0].class == BlockStatement&lt;br /&gt;assert x[1] == null&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;But when you need it, you can specify 'false', meaning you want the ClassNode as well as the BlockNode:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&lt;br /&gt;List&amp;lt;ASTNode&amp;gt; x = new AstBuilder().buildFromCode(&lt;br /&gt;       CompilePhase.CONVERSION,&lt;br /&gt;       false,  // get the ClassNode&lt;br /&gt;       { " a constant " })&lt;br /&gt;&lt;br /&gt;assert x[0].class == BlockStatement&lt;br /&gt;assert x[1].class == ClassNode&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;For a fun, educational exercise, create multiple classes in GroovyConsole and see what the AST looks like. Hopefully you won't be surprised. But please don't enter an anonymous class because then you'll break the AST Browser! (It's a defect in 1.7 RC1 that I promise to fix soon).&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8186302968504789764?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8186302968504789764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8186302968504789764' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8186302968504789764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8186302968504789764'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/10/true-and-false-of-groovys-ast-builder.html' title='The True and False of Groovy&apos;s AST Builder'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_dVhQbe4S9AM/SuSUM4u_GAI/AAAAAAAAAJc/DxERWW42SCk/s72-c/constants.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-5946335224483126096</id><published>2009-09-04T15:15:00.004-05:00</published><updated>2009-09-04T15:43:25.141-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='recursion'/><category scheme='http://www.blogger.com/atom/ns#' term='functional'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Y-Combinator in Groovy</title><content type='html'>File under uselessly cool (for now at least).&lt;br /&gt;&lt;br /&gt;A &lt;a href="http://en.wikipedia.org/wiki/Y_combinator"&gt;Y-Combinator&lt;/a&gt; in Groovy!&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def Y = { le -&amp;gt; ({ f -&amp;gt; f(f) })({ f -&amp;gt; le { x -&amp;gt; f(f)(x) } }) }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;i&gt;Update: @mrdillon was kind enough to point out that my original Y used recursion. His revision is better. &lt;/i&gt;&lt;br /&gt;&lt;br /&gt;And to prove it works, you can define a recursive factorial function without using recursion in the language.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def factorial = Y { fac -&amp;gt;&lt;br /&gt;    { n -&amp;gt; n &amp;lt;= 2 ? n : n * fac(n - 1) }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;assert 2432902008176640000 == factorial(20G)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The one-liner closure in the middle is the meat of the method definition and is a classic (i.e. horribly inefficient, known deficient) factorial implementation. I wouldn't write code this way but it makes a nice terse example when written in one line.&lt;br /&gt;&lt;br /&gt;So is this useless? Not at all! But getting to an explanation of its use requires just a few examples.&lt;br /&gt;&lt;br /&gt;Consider a recursive function that determines if an element is a member of a list. I guess you should also consider that List#contains(Object) does not exist. Here is a first draft of such function:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def isMember(element, list) {&lt;br /&gt;    if (!list) false&lt;br /&gt;    else&lt;br /&gt;        if (list.head() == element) true&lt;br /&gt;        else isMember(element, list.tail())&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;assert isMember(2, [1, 2, 3])&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Let's just step through it briefly.&lt;br /&gt;&lt;br /&gt; &lt;span style="font-family:arial;"&gt;if (!list) false&lt;/span&gt;&lt;br /&gt;... a simple terminating condition, an empty list never contains the element&lt;br /&gt;&lt;br /&gt; &lt;span style="font-family:arial;"&gt;&lt;/span&gt;if (list.head() == element) true&lt;br /&gt;...if the first item in the list is the element then yes, we found it!&lt;br /&gt;&lt;br /&gt; &lt;span style="font-family:arial;"&gt;&lt;/span&gt;else isMember(element, list.tail())&lt;br /&gt;....otherwise, check all the other items in the list for the same condition&lt;br /&gt;&lt;br /&gt;Over time, the isMember will be recursively applied to each element in the list, and call stacks will build up in memory until the element is found, the list is fully checked, or you run out of stack space.&lt;br /&gt;&lt;br /&gt;The problem with isMember is the redundancy. Notice how 'element' is always passed as a parameter? The value never changes over the life of the function application, so we shouldn't bother passing it every time. We have closures, so why don't we just 'close over' the value of element and remove the redundant data passing?&lt;br /&gt;&lt;br /&gt;We can do it, but because of Groovy's limited recursion support, the implementation is kinda ugly. What I'd like to do is create a recursive closure that captures element once, but Groovy forces me into declaring an inner looping function on one line and defining it on another:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def isMember(element, list) {&lt;br /&gt;    def inner&lt;br /&gt;    inner = { lat -&amp;gt;&lt;br /&gt;        if (!lat) false&lt;br /&gt;        else&lt;br /&gt;            if (lat.head() == element) true&lt;br /&gt;            else inner(lat.tail())&lt;br /&gt;    }&lt;br /&gt;    inner(list)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;assert isMember(2, [1, 2, 3])&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This is where Y comes into play. I want a recursive closure and that is what Y does! Check out how Y allows me to define a recursive function locally within a method. No more split on declaration/definition.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def isMember = { element, list -&gt; {&lt;br /&gt;    def inner = Y { inner -&amp;gt;&lt;br /&gt;        { lat -&amp;gt;&lt;br /&gt;            if (!lat) false&lt;br /&gt;            else&lt;br /&gt;                if (lat.head() == element) true&lt;br /&gt;               else inner(lat.tail())&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    inner(list)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;assert isMember(2, [1, 2, 3])&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;It's not uselessly cool any more is it? Oh wait, without tail call optimization on the JVM you will surely run out of stack space with a nasty StackOverflowException by writing code like this. So don't do it!&lt;br /&gt;&lt;br /&gt;I guess it's pretty useless after all.&lt;br /&gt;&lt;br /&gt;And if you're looking for a fun weekend project, why don't you do a different one of the Rosetta Code challenges&lt;br /&gt;that are missing for Groovy:&lt;a href="http://rosettacode.org/wiki/Tasks_not_implemented_in_Groovy"&gt; http://rosettacode.org/wiki/Tasks_not_implemented_in_Groovy&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Tschüs!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-5946335224483126096?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/5946335224483126096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=5946335224483126096' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5946335224483126096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5946335224483126096'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/09/y-combinator-in-groovy.html' title='Y-Combinator in Groovy'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1846136809065668848</id><published>2009-08-31T07:17:00.003-05:00</published><updated>2009-08-31T07:25:19.664-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>The System Metaphor is Still Lame</title><content type='html'>The eXtreme Programming &lt;a href="http://c2.com/cgi/wiki?SystemMetaphor"&gt;System Metaphor&lt;/a&gt; practice makes a pretty easy target. I've seen large development teams grind to a halt because of persistent broken builds without any continuous integration. I've seen teams' productivity drop to a crawl under the burden of technical debt and lack of test driven development. But what happens when a team lacks a good metaphor for how the system works? Can you really name a reasonable, realistic negative impact from a lack of system metaphor? Just last week I was dismissing it in an internal agility training as an unneeded XP practice. So I was surprised to see Joshua Kerievsky's and Brain Foote's "&lt;a href="http://www.agile2009.com/node/2356"&gt;System Metaphor Revisited&lt;/a&gt;" talk at Agile 2009. Seriously, the guy who wrote Refactoring to Patterns is also hyping the System Metaphor? We'll see...&lt;br /&gt;&lt;br /&gt;The thesis of the talk was that a System Metaphor provides illumination, inspiration, and integrity (...and alliteration). Briefly and in my own words, it illuminates an unfamiliar design by providing a reference point in the familiar. It inspires unexpected design ideas by providing a frame of reference in which to apply your creativity. And it builds integrity by suggesting a single, coherent, and consistent framework and set of names into the system.&lt;br /&gt;&lt;br /&gt;And the &lt;a href="http://www.industriallogic.com/"&gt;Industrial Logic&lt;/a&gt; &lt;a href="https://elearning.industriallogic.com/gh/submit?Action=AlbumContentsAction&amp;amp;album=welcome&amp;amp;devLanguage=Java"&gt;case study&lt;/a&gt; is just so cool. I've loved their marketing since they started with the "Let the Good Designs Roll" idea. I want to be a rock star &lt;span style="font-style: italic;"&gt;and&lt;/span&gt; I want to take their training classes. And now their trainings are all hinged around the ideas of albums, tracks, and playlists. Very cool. I guess it helps to have a great product.&lt;br /&gt;&lt;br /&gt;I have no doubt that the guys presenting have deemed their system metaphor a qualitative success for the project. But I still think the practice is totally lame.&lt;br /&gt;&lt;br /&gt;A metaphor embedded in code is rigid. Having a great marketing metaphor is fine; marketing campaigns sell products. But they're also easy to change and refine, while an IT system is not. How many defects will be introduced if you change your marketing metaphor from a rock and roll concert to a book store? Not many. How many defects are introduced by changing the code to reflect this? Is none really the answer?&lt;br /&gt;&lt;br /&gt;A metaphor is a 2nd ubiquitous language. One universal domain language is of clear benefit to a project. And that language should be the language of your users, domain experts, and programmers. A system metaphor is usually not this same language. For my projects, it's hard enough to try to get all the stakeholders to agree on terms of use. Introducing another layer of abstraction and the associated verbiage isn't going to help things. Ubiquitous language is important; but create it out of your domain not your metaphor.&lt;br /&gt;&lt;br /&gt;A metaphor illuminates in the large, but confuses in the small. A metaphor guides you towards understanding when contemplating projects as a whole. It provides familiar signposts and a framework on which to hang ideas. But a lot of programming involves making small changes to systems you only partially understand. When this is the case, the metaphor becomes accidental complexity in the system. Having postage stamp, postage meter, and postage machine objects in your system helps the original design team, but doesn't help the contractor being asked to figure out why reports aren't printing.&lt;br /&gt;&lt;br /&gt;A metaphor will likely become a mixed metaphor over time: consider a system that treats all data as streams. It's consistent and elegant. But eventually the Enterprise knocks on your door and you develop some sort of messaging service. Now your streams have mailboxes and can be put in message queues. This undermines the benefit of integrity via consistency. We live with this sort of ambiguity every day, but it doesn't mean we should accept it. &lt;br /&gt;&lt;br /&gt;Metaphors do not decompose well. You system will grow, it will take on technical debt, and eventually it will need to be refactored, decomposed, and modularized. This is the natural rhythm of agile systems. When it comes time to break out components, will your modularization boundaries be natural boundaries within your metaphor? At a minimum, you'll probably end up discussing how the two don't line up correctly, and now you're spending time solving a self-created problem... surely a bad process smell. It seems like only the most dependency-obsessed team leads could foresee and prevent this. A YAGNI approach may not be your ally here.&lt;br /&gt;&lt;br /&gt;In the end, I see a metaphor as a set of constraints. Humans can do their best and most creative thinking when provided rigid constraints. But constraints limit design ideas as much as suggest new ones. I'm sure some people have had success with a system metaphor, but I find success &lt;span style="font-style: italic;"&gt;because&lt;/span&gt; of system metaphor a much harder pill to swallow. To all those espousing the use of system metaphor as a useful practice, I quote a famous and apocryphal doctor and say, "Clearly I can see you're nuts".&lt;br /&gt;&lt;br /&gt;And just for fun, I used eight metaphors in this blogpost. There is no prize for finding them all.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1846136809065668848?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1846136809065668848/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1846136809065668848' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1846136809065668848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1846136809065668848'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/08/system-metaphor-is-still-lame.html' title='The System Metaphor is Still Lame'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1362878021832545560</id><published>2009-08-24T19:05:00.002-05:00</published><updated>2009-08-24T19:09:20.060-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>Counter-intuitive Agile Coaching Tips</title><content type='html'>Just finished the "What Do Agile Coaches Do?" session from Rachel Davies and Liz Sedley at Agile 2009. It was a great workshop based on their &lt;a href="http://www.pragprog.com/titles/sdcoach/agile-coaching"&gt;new book&lt;/a&gt; and J. Richard Hackman's "&lt;a href="http://www.people.fas.harvard.edu/%7Ehackman/leading_teams.html"&gt;Leading Teams&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;Hackman defines three types of coaching intervention:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Motivational - intended to improve team or team member's effort&lt;/li&gt;&lt;li&gt;Consultative - intended to improve a team's process&lt;/li&gt;&lt;li&gt;Educational - intended to improve a team's understanding&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Today's first insight is that I personally focus on educational and consultative interventions, to the almost complete exclusion of motivational intervention. I'm not interested in giving people pep talks, so clearly I'm lacking some motivational skills and techniques. Anyway, Hackman defines three key times when these interventions should be used within a project:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Beginning - focus on motivational intervention&lt;/li&gt;&lt;li&gt;Midpoint - focus on consultative intervention&lt;/li&gt;&lt;li&gt;End - focus on educational intervention&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Delaying education until the end of a project sounds ludicrous. Wouldn't the begining be better, when people need it? The answer is to think of a project as an iteration, not a full release. Iteration start is when the team needs energy to commit to work and kick off the sprint. Makes sense that the "sprint" start is when you want to get a good start out of the blocks, huh? So the beginning &lt;i&gt;is&lt;/i&gt; a good time for motivation after all. The iteration midpoint is when the team is neck deep in implementation and sees that not all their practices are working in their best interest. What's the solution? A small process tweak via consultative intervention. The end is the retrospective is where the whole team has a forum and opportunity to make big changes to how they work. That's the time where education on a new and unknown practice can make the biggest impact, because the team can commit to it and take action immediately. Hackman's description of when the interventions are most effective sounded fishy at first, but when viewed against an iterative process it makes sense!&lt;br /&gt;&lt;br /&gt;But non of this is counter-intuitive coaching. The most interesting part of the workshop was our group's breakout session where we discussed coaching in the context of some manufactured scenarios from the speakers. We came up with these &lt;i&gt;unique&lt;/i&gt; coaching strategies:&lt;br /&gt;&lt;br /&gt;1) Coaching Through Absurdity&lt;br /&gt;In my group was &lt;a href="http://twitter.com/alexbachin"&gt;Alex Chin&lt;/a&gt;, and in order to get his team to estimate at the task level he added huge estimates to each task. These grossly absurd estimates &lt;strong&gt;forced&lt;/strong&gt; the team to come back and add better estimates. Awesome idea. Next time my team won't make a decision I'm going to make an absurd one for them and wait for a reaction.&lt;br /&gt;2) Letting People Fail&lt;br /&gt;We spent a lot of time discussing how to &lt;i&gt;guide&lt;/i&gt; a team down the correct path. If your team insists on walking precariously close to a metaphorical cliff, then don't waste your time each week shepherding them off it. Let them fall of the cliff once. Surely that will teach them to avoid it next time. Right?&lt;br /&gt;3) Doing Nothing is Doing Something&lt;br /&gt;You can lead a horse to water but you can't make him drink. Likewise, you can't force a feedback loop. Coaching is not just about knowing when to intervene, but when not to. If there is a team issue that needs resolving, sometimes you just need to get the people together and wait. Do nothing and let the team decide. The most effective way to coach is to set the stage for team emergence and then get out of the way! Agile isn't about the coach solving your problems, it's about the coach getting you to solve your own.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1362878021832545560?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1362878021832545560/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1362878021832545560' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1362878021832545560'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1362878021832545560'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/08/counter-intuitive-agile-coaching-tips.html' title='Counter-intuitive Agile Coaching Tips'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3529573567356875160</id><published>2009-08-24T09:28:00.004-05:00</published><updated>2009-08-24T09:38:08.587-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Agile 2009 Day 0: Kanban Bag Stuffing</title><content type='html'>Spent about 4 hours today packing 1500 conference bags for &lt;a href="http://agile2009.com/"&gt;Agile 2009&lt;/a&gt;. Luckily, several guys from the Kanban-Dev mailing list showed up to turn a scene from &lt;a href="http://www.imdb.com/title/tt0027977/"&gt;Modern Times&lt;/a&gt; into an unique exercise in Lean production.&lt;br /&gt;&lt;br /&gt;I won't explain much about the "Pull" system or queuing theory backing &lt;a href="http://en.wikipedia.org/wiki/Lean_software_development"&gt;Lean production&lt;/a&gt;; rather, I'll just explain what we did.&lt;br /&gt;&lt;br /&gt;We had about 1500 bags to pack with more than 25 items each: a lot of flyers, several books (including past volunteer Ahmed Sidky's &lt;a href="http://www.manning.com/smith/"&gt;Becoming Agile&lt;/a&gt;), and even some agile hand lotion (wtf, right? But it beats the face creme I got at a triathlon called, I kid you not, "every manjack"). Anyway, it all needed to be bagged, carted, and trolleyed to the reception area. Uff da.&lt;br /&gt;&lt;br /&gt;The group split into two teams. Our goal was obviously to get the bags packed as quickly as possible. The Kanban experiment was used to create a system of flow, in which each group had a steady stream of product through their production line. Bottlenecks meant the upstream production unit should slow down and not having work to do meant the upstream unit had to speed up. But it wasn't about working more or working less to achieve flow. It was about tweaking the process so that everyone working hard would result in the flow. The group had to self organize and evolve so that this steady state existed. Over two shifts of people this did all happen to a certain extent. We didn't have measurements to see who was fastest, but each process did improve over time. Here are some observations, along with how they might apply to software teams:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Having no leader meant that every team member contributed new ideas to process improvement. &lt;span style="font-style: italic;"&gt;Does the leader of your software team sometimes stifle innovation?&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Having two teams meant that competition fueled more frequent improvements. &lt;span style="font-style: italic;"&gt;What external forces are driving your software team to evolve?&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Having no roles created a system where shouting "We're out of Agile Hand Lotion" meant that the person most capable of grabbing more lotion at that point in time immediately pitched in to do the job. &lt;span style="font-style: italic;"&gt;Are the roles in your organization lightweight enough to allow the right person to contribute?&lt;/span&gt; &lt;/li&gt;&lt;li&gt;Having one set of workers out-of-sight (running trolleys through elevators and hotels) meant that it was more difficult for the group to self correct their entire process. Finished bags did pile up and we were at a loss as to how to make the trolley's move faster. &lt;span style="font-style: italic;"&gt;What parts of your SDLC are out-of-sight and out-of-mind? &lt;/span&gt;&lt;/li&gt;&lt;li&gt;Not producing a &lt;a href="http://en.wikipedia.org/wiki/Value_stream_mapping"&gt;Value Stream Map&lt;/a&gt; meant it was difficult to see the whole and fix the real problem, which was slow elevators. VSMs are much lower ceremony than most people realize, and we &lt;i&gt;could&lt;/i&gt; have done one. &lt;span style="font-style: italic;"&gt;Can your team truly see the whole?&lt;/span&gt; &lt;/li&gt;&lt;li&gt;Many improvements were small and non-obvious in retrospect - "Why don't we pack the books last because they are heaviest?" and "Open the bags more quickly by pulling the handle like this." &lt;span style="font-style: italic;"&gt;Does your company have a process group that focuses on the macro view to the exclusion of the micro view? &lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;At the end of the day, pro facilitator &lt;a href="http://twitter.com/jeantabaka"&gt;Jean Tabaka&lt;/a&gt; of &lt;a href="http://www.pearsonhighered.com/educator/product/Collaboration-Explained-Facilitation-Skills-for-Software-Project-Leaders/9780321268778.page"&gt;Collaboration Explained&lt;/a&gt; fame hosted our retrospective for us. The format was ORID:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;    &lt;strong&gt;O&lt;/strong&gt;bjective – Focus on the facts, hard evidence data&lt;strong&gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;eflective – Focus on how that made people feel or other associations&lt;/li&gt;&lt;li&gt;&lt;strong&gt;I&lt;/strong&gt;nterpretive – Focus on the impact and significance&lt;/li&gt;&lt;li&gt;&lt;strong&gt;D&lt;/strong&gt;ecisive – Focus on next steps&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;It was a typical retrospective in that we gathered data and created a shared understanding of the event in the Objective phase, talked about our feelings and personal experiences in the Reflective phase, generated insights in the Interpretive phase, and voted with dots in the Decisive phase to create a list of action items for next year. She and the rest of the team did a great job, and both Kanban and the retrospective were superb ways to kick off the volunteer sessions! &lt;br /&gt;&lt;br /&gt;And just because I get a kick out of having foreign characters in my posts: 看板 is the symbol for Kanban. Whee!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3529573567356875160?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3529573567356875160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3529573567356875160' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3529573567356875160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3529573567356875160'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/08/agile-2009-day-0-kanban-bag-stuffing.html' title='Agile 2009 Day 0: Kanban Bag Stuffing'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6342790710705830977</id><published>2009-08-23T17:25:00.001-05:00</published><updated>2009-08-23T17:26:35.269-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Exploring Immutability</title><content type='html'>When did immutable objects become idiomatic Java? I suppose it depends on your frame of reference and what your experience brings to coding. It may not be idiomatic Java to you. In fact, Java Beans and fluent interfaces seem to rely on in-place side effects and mutability to function properly. Exactly what place &lt;i&gt;do&lt;/i&gt; immutable objects have in the Java world?&lt;br /&gt;&lt;br /&gt;The immutability of String surprised me when I was learning Java. One of the first programs I wrote assumed String#replace did an in-place edit of the String, one of the first debugger sessions I conducted clearly showed me that String#replace was &lt;strong&gt;not&lt;/strong&gt; editing the String, and one of the first Sun Forum questions I posted was about String#replace being broken in Java. BROKEN, I say! This represents the one time when an answer to a Sun Forum question clearly solved the poster's problem without a lengthy chain of "please post your code" responses. The point is that immutability has been with Java forever. And now that the days of Object Pools and persistent performance concerns are behind us, it's time to embrace immutability in our own code.&lt;br /&gt;&lt;br /&gt;The benefits of immutability are many and well-documented. Effective Java (either edition) is a good start. I'll touch the highlights with the example of a Person object:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;class Person {&lt;br /&gt; def firstName&lt;br /&gt; def lastName&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;HA! Tricked you, it's Groovy. In the Groovy compiler, the Person class gains two methods for each property defined:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public void setFirstName(Object)&lt;br /&gt;public Object getFirstName()&lt;br /&gt;...&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The problem with the &lt;i&gt;Class&lt;/i&gt; (as the JVM sees it), is that many threads may access Person and see the same instance in different states. It is difficult to share this object correctly across threads. The problem with the &lt;i&gt;Java source&lt;/i&gt; is the cruft of writing getters and setters. The problem with the &lt;i&gt;API&lt;/i&gt; of Person is that working effectively with the object requires many calls to setX and setY mutators just to get simple interactions working. The problem with &lt;i&gt;maintaining&lt;/i&gt; this code is that the object is somewhat non-deterministic and difficult to reason about. Groovy uniquely solves only one of these issues: the source level cruft. Sure, you don't have to write out getters and setters, but that is the least important problem to solve.&lt;br /&gt;&lt;br /&gt;Fluent APIs solve the issue of having to munge up the source code with repetitive calls to setX and setY. Instead of following the Bean pattern of setters being void methods, instead have all your setters return a 'this' reference:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;class Person {&lt;br /&gt;&lt;br /&gt; def firstName&lt;br /&gt; def lastName&lt;br /&gt;&lt;br /&gt; def setFirstName(firstName) {&lt;br /&gt;   this.firstName = firstName&lt;br /&gt;   this&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; def setLastName(lastName) {&lt;br /&gt;   this.lastName = lastName&lt;br /&gt;   this&lt;br /&gt; }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Now you have a nicer API to work with at the expense of not having a standard Java bean. Remember the Java language change proposal to make void methods always implicitly return a 'this' reference? I feel like I'm the only guy wanting that in Project Coin. Oh well. Here is what consuming the API now looks like:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def person = new Person()&lt;br /&gt;   .setFirstName('hamlet')&lt;br /&gt;   .setLastName('darcy')&lt;br /&gt;assert 'hamlet darcy' ==  "$person.firstName $person.lastName"&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Groovy has a solution to this same problem: the with block. All object have a with method, and when inside the closure parameter, all method and field references are resolved back to the object having with invoked. Visual Basic had this feature and I always missed it in Java:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def person = new Person()&lt;br /&gt;person.with {&lt;br /&gt;   firstName = 'hamlet'&lt;br /&gt;   lastName = 'darcy'&lt;br /&gt;}&lt;br /&gt;assert 'hamlet darcy' ==  "$person.firstName $person.lastName"&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;So both Groovy and Java have an answer for the boilerplate involved with writing and consuming APIs. But again, these aren't the big issue with mutable objects: non-determinism and thread safety are. To help solve that you can use immutable objects.&lt;br /&gt;&lt;br /&gt;Can we get nice, fluent interfaces in Java without sacrificing mutability? The go-to solution in Java is the Builder idiom. Make your Person object immutable (all final fields), and the constructor private. Then define a mutable Builder class that wraps the constructor in a better API. In the end, creating Person instances looks like this:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def person = new PersonBuilder()&lt;br /&gt;       .setFirstName('hamlet')&lt;br /&gt;       .setLastName('darcy')&lt;br /&gt;       .build()&lt;br /&gt;assert 'hamlet darcy' ==  "$person.firstName $person.lastName"&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;You instantiate the Builder and the builder instantiates the Person. This is nice... I guess maybe. Remember the idea of a "&lt;a href="http://hamletdarcy.blogspot.com/2009/07/when-testability-and-readability.html"&gt;meaningless abstraction&lt;/a&gt;"? PersonBuilder is definitely a meaningless abstraction. It does not exist to solve any of the problems the system was designed to do. It exists solely to solve a problem in the implementation. Suspect. Very suspect.&lt;br /&gt;&lt;br /&gt;The Builder has by far the longest implementation, and the DRY principle is glaringly violated in the duplicate fields:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;class Person {&lt;br /&gt;   private final def firstName&lt;br /&gt;   private final def lastName&lt;br /&gt;&lt;br /&gt;   Person(firstName, lastName) {&lt;br /&gt;       this.firstName = firstName&lt;br /&gt;       this.lastName = lastName&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class PersonBuilder {&lt;br /&gt;   def firstName&lt;br /&gt;   def lastName&lt;br /&gt;&lt;br /&gt;   def build() {&lt;br /&gt;       new Person(firstName, lastName)&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   def setFirstName(firstName) {&lt;br /&gt;     this.firstName = firstName&lt;br /&gt;     this&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   def setLastName(lastName) {&lt;br /&gt;     this.lastName = lastName&lt;br /&gt;     this&lt;br /&gt;   }   &lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;It should be said, though, that this idiom &lt;strong&gt;does&lt;/strong&gt; address the determinism and concurrency issues with mutability. Person can now be shared freely across threads, cached safely, and behaves in a more deterministic manner.&lt;br /&gt;&lt;br /&gt;The best approach has not yet been mentioned. Simply create an immutable object without a builder, and also provide a nice fluent API around it. The calling code can look exactly the same as the previous fluent API example:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def person = new Person()&lt;br /&gt;       .setFirstName('hamlet')&lt;br /&gt;       .setLastName('darcy')&lt;br /&gt;assert 'hamlet darcy' ==  "$person.firstName $person.lastName"&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;You can do this by slightly tweaking the fluent API example. Don't return a 'this' reference from setters, just return an entirely new object. And don't worry about all those little objects you're creating and tossing away.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;class Person {&lt;br /&gt;&lt;br /&gt;   private final def firstName&lt;br /&gt;   private final def lastName&lt;br /&gt;&lt;br /&gt;   Person() { }&lt;br /&gt;&lt;br /&gt;   Person(firstName, lastName) {&lt;br /&gt;       this.firstName = firstName&lt;br /&gt;       this.lastName = lastName&lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;   def setFirstName(firstName) {&lt;br /&gt;       new Person(firstName, lastName)&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   def setLastName(lastName) {&lt;br /&gt;       new Person(firstName, lastName)&lt;br /&gt;   }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Is a Person instance threadsafe? Yes. It is immutable.&lt;br /&gt;Is a Person instance deterministic? Yes. No race conditions here.&lt;br /&gt;Is a Person instance API easy to consume? Yup, it has a fluent API.&lt;br /&gt;Does the Person class introduce a meaningless abstraction? Nope, and good thing!&lt;br /&gt;Does the Person class require an &lt;i&gt;exotic&lt;/i&gt; programming language to implement? No, this works fine in Java.&lt;br /&gt;Does the Person implementation require tons of boilerplate? Maybe. The good part is that every implementation of a setter is exactly the same. The bad part is that every implementation of a setter is exactly the same. Not very DRY, but it could be automated in Groovy at runtime with a little metaprogramming.&lt;br /&gt;&lt;br /&gt;That's it, immutable exploration over. And what place should immutability have in the Java world? It should be front and center. I hope I've shown that immutability and good APIs do not need to conflict with each other. You can get both with a tiny bit of extra work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6342790710705830977?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6342790710705830977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6342790710705830977' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6342790710705830977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6342790710705830977'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/08/exploring-immutability.html' title='Exploring Immutability'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6054333422522979822</id><published>2009-08-22T08:47:00.005-05:00</published><updated>2009-08-22T08:53:53.220-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='functional'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><title type='text'>How to Tell Your Co-Workers Have Discovered Functional Programming</title><content type='html'>Three ways to tell that your co-workers are learning a Functional Programming language at home:&lt;br /&gt;&lt;br /&gt;1. You've found the number of .class file in your project quadrupled in the last month.&lt;br /&gt;&lt;br /&gt;Here is an output directory with 17 .class files, only 2 of which are not inner classes, most of which are anonymous.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dVhQbe4S9AM/So_3fTGHjPI/AAAAAAAAAJM/j4Mfelz_ZW8/s1600-h/screenshot.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 376px;" src="http://2.bp.blogspot.com/_dVhQbe4S9AM/So_3fTGHjPI/AAAAAAAAAJM/j4Mfelz_ZW8/s400/screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5372784997550230770" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;See all those dollar signs indicating inner/anonymous classes? Uh oh, looks like someone discovered &lt;a href="http://www.reddit.com/r/programming/comments/63mw9/mr_yegge_meets_mr_brooks/c02q5wj"&gt;shitty lambdas&lt;/a&gt;. Your chaos meter should be increasing... will your project be maintainable of it's not idiomatic Java?&lt;br /&gt;&lt;br /&gt;2. You've found a class named Pair&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public class Pair&amp;lt;T, U&amp;gt; {&lt;br /&gt;&lt;br /&gt;   private final T left;&lt;br /&gt;   private final U right;&lt;br /&gt;&lt;br /&gt;   public Pair(T left, U right) {&lt;br /&gt;       this.left = left;&lt;br /&gt;       this.right = right;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   T getLeft() { return left; }&lt;br /&gt;   U getRight() { return right; }&lt;br /&gt;&lt;br /&gt;   static &amp;lt;T, U&amp;gt; Pair from(T left, U right) {&lt;br /&gt;       return new Pair&amp;lt;T, U&amp;gt;(left, right);&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;It's not a tuple, but it's about 2/3 of the way there! There's already jfun.util.Pair in JFun and gnu.lists.Pair in Gnu Lists, and now you've got your own too. Hooray. But wait, how will you maintain your code base if the declared name of your data structures don't tell you how it's meant to be used? Chaos... level... rising...&lt;br /&gt;&lt;br /&gt;3. You've found a widely implemented one-method highly generic interface&lt;br /&gt;&lt;br /&gt;An interface like this has over 100 implementations, many of which are anonymous:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public interface Transformer&amp;lt;T, U&amp;gt; {&lt;br /&gt;   U transform(T input);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This is equivalent to &lt;a href="http://functionaljava.googlecode.com/svn/artifacts/2.20/javadoc/fj/F.html"&gt;F&lt;/a&gt; in &lt;a href="http://functionaljava.org/"&gt;Functional Java&lt;/a&gt; and &lt;a href="http://smokejumperit.com/jconch/1.1/jconch/functor/Transformer5.html"&gt;Transformer5&lt;/a&gt; in &lt;a href="http://code.google.com/p/jconch/"&gt;JConch&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;At this point your chaos meter should be off the chart. These functional programmers are surely ruining your system and livelihood. So, I'm hesitant to mention what happens when you combine all of them together:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Transformer identityfunction =&lt;br /&gt;   new Transformer&amp;lt;Pair&amp;lt;String, String&amp;gt;, Pair&amp;lt;String, String&amp;gt;&amp;gt;() {&lt;br /&gt;       public Pair&amp;lt;String, String&amp;gt; transform(Pair&amp;lt;String, String&amp;gt; input&amp;gt;) {&lt;br /&gt;           return input;&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Voila, an anonymous function object that uses the Pair class to make a 1-arity method into a 2-arity method, returning multiple values.&lt;br /&gt;&lt;br /&gt;These are the trials and tribulations of finding the &lt;i&gt;appropriate&lt;/i&gt; use of new programming paradigms in old languages. Looking at version control history, the person that committed all these sins was... me. Will this be the Java code I write in two years time? Certainly not. But which of these example is the growing pains of learning FP and which of these will still be with me in the future?&lt;br /&gt;&lt;br /&gt;Comments are open!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6054333422522979822?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6054333422522979822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6054333422522979822' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6054333422522979822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6054333422522979822'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/08/how-to-tell-your-co-workers-have.html' title='How to Tell Your Co-Workers Have Discovered Functional Programming'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_dVhQbe4S9AM/So_3fTGHjPI/AAAAAAAAAJM/j4Mfelz_ZW8/s72-c/screenshot.png' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1032500851979891249</id><published>2009-08-15T16:07:00.003-05:00</published><updated>2009-08-15T16:14:38.125-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Testing OSGi Bundles with Pax Exam, Groovy and Gradle</title><content type='html'>You can't be an expert on everything. There are a few topics in life I've given up on, forever to be ignorant:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Botany - Don't ask me the name of any plant or tree. I won't know.&lt;/li&gt;&lt;li&gt;Hardware Specs - Telling me the model number and speed on your new laptop just makes me confused. I stopped reading the Computer Shopper years ago.&lt;/li&gt;&lt;li&gt;Maven - I'm happy to use it IF SOMEONE ELSE CREATES THE POM. Life's too short for that much XML.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;So what was I to do with &lt;a href="http://wiki.ops4j.org/display/paxexam/Pax+Exam"&gt;Pax Exam&lt;/a&gt;? This framework allows you to write JUnit or TestNG tests and then executes them in the OSGi container of your choosing. It's a cool framework but much of the documentation assumes a willingness to scroll through &lt;a href="http://www.jroller.com/habuma/entry/putting_osgi_to_the_test"&gt;lines&lt;/a&gt; and &lt;a href="http://wiki.ops4j.org/display/paxexam/Quick+Start"&gt;lines&lt;/a&gt; of &lt;a href="http://wiki.ops4j.org/display/paxexam/Configuration+using+Maven+Plugin"&gt;Maven XML&lt;/a&gt;. Ugh. Life's too short to grapple with build systems.&lt;br /&gt;&lt;br /&gt;So the nut is cracked. I've got &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt; unit tests running across &lt;a href="http://www.eclipse.org/equinox/"&gt;Equinox&lt;/a&gt;, &lt;a href="http://felix.apache.org/site/index.html"&gt;Felix&lt;/a&gt;, and &lt;a href="http://www.knopflerfish.org/"&gt;Knopflerfish&lt;/a&gt; from both &lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt; and &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt;. No Maven in sight.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Writing Pax Exam Tests in Groovy&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Once it was all configured, writing Pax Exam tests were simple. Start with a plain old JUnit 4 test and do two things:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Annotate it to run with the Pax Exam JUnit runner&lt;/li&gt;&lt;li&gt;Configure it to provision the Groovy-all JAR&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Here it is, complete with imports and ready for a little copy-paste action.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;import org.junit.runner.RunWith&lt;br /&gt;import org.ops4j.pax.exam.junit.JUnit4TestRunner&lt;br /&gt;import org.junit.Test&lt;br /&gt;import org.ops4j.pax.exam.junit.Configuration&lt;br /&gt;import org.ops4j.pax.exam.Option&lt;br /&gt;import static org.ops4j.pax.exam.CoreOptions.*&lt;br /&gt;&lt;br /&gt;@RunWith (JUnit4TestRunner)&lt;br /&gt;class GroovyIntegrationTest {&lt;br /&gt;&lt;br /&gt;  @Configuration&lt;br /&gt;  public Option[] configure() {&lt;br /&gt;      [&lt;br /&gt;          provision(&lt;br /&gt;              mavenBundle().groupId('org.codehaus.groovy').artifactId('groovy-all').version('1.6.4')&lt;br /&gt;          )&lt;br /&gt;      ] as Option[]&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Test&lt;br /&gt;  public void testFramework() {&lt;br /&gt;      println 'Hello from Pax-Groovy!'&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;A few things to notice... CoreOptions was statically imported, so the methods provision() and mavenBundle() are resolved. The configure() method returns an Array of Option objects, so the "as Option[]" cast is needed. And by default, the tests are going to run on Felix 1.8 (or thereabouts).&lt;br /&gt;&lt;br /&gt;Before Pax Exam becomes useful you're going to want to provision your bundle as the system under test, get access to the BundleContext it was loaded with, and specify more containers to run on.&lt;br /&gt;&lt;br /&gt;Provisioning your bundle and running on multiple containers is a matter of configuring the test differently:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;@Configuration&lt;br /&gt;public Option[] configure() {&lt;br /&gt;  [equinox(),&lt;br /&gt;  felix(),&lt;br /&gt;  knopflerfish(),&lt;br /&gt;  provision(&lt;br /&gt;      bundle(new File('./../out/production/Filter4osgi.jar').toURI().toString()),&lt;br /&gt;      mavenBundle().groupId('org.codehaus.groovy').artifactId('groovy-all').version('1.6.4')&lt;br /&gt;  )] as Option[]&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Here I'm specifying Equinox, Felix, and Knopflerfish. There's also options for allEquinoxVersions, allFelixVersions, and allKnopflerfishVersions, as well as allFrameworks and allFrameworksVersions to test on the world. That options takes a few minutes to execute! Provisioning my own bundle can be done by loading it as a file URL. This example isn't very robust but it proves the concept.&lt;br /&gt;&lt;br /&gt;The BundleContext is available as an injectable bean from Pax Exam. If you want the BundleContext in your unit test, to perhaps test that services were registered correctly, then add this as a field:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;@Inject&lt;br /&gt;BundleContext bundleContext&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;And here is a simple test to make sure that my &lt;a href="http://code.google.com/p/filter4osgi/"&gt;filter4osgi&lt;/a&gt; library was correctly installed:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;@Test&lt;br /&gt;public void test_BundleIsLoaded() {&lt;br /&gt;&lt;br /&gt;  def found = bundleContext.bundles.find {&lt;br /&gt;      'filter4osgi' == it.symbolicName&lt;br /&gt;  }&lt;br /&gt;  Assert.assertNotNull('filter4osgi bundle not loaded!', found)&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Running Pax Exam Tests from Gradle&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Gradle build was slick. Tell Gradle to load your bundle as a file URL and the rest is just boilerplate dependency management:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;usePlugin 'groovy'&lt;br /&gt;&lt;br /&gt;repositories {&lt;br /&gt;  mavenCentral()&lt;br /&gt;  flatDir dirs: [&lt;br /&gt;      './../out/production',   // filter4osgi jar built earlier&lt;br /&gt;  ]&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dependencies {&lt;br /&gt;  groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.6.4'&lt;br /&gt;  compile(&lt;br /&gt;      'org.ops4j.pax.exam:pax-exam:1.0.0',&lt;br /&gt;      'org.ops4j.pax.exam:pax-exam-container-default:1.0.0',&lt;br /&gt;      'org.ops4j.pax.exam:pax-exam-junit:1.0.0',&lt;br /&gt;      'junit:junit:4.5',&lt;br /&gt;      'org.osgi:org.osgi.core:4.0.1',&lt;br /&gt;      ':filter4osgi:',&lt;br /&gt;  )&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;"gradle test" is the only target you'll ever need.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Running Pax Exam Tests from IntelliJ IDEA&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Your unit tests will show up once for each container you're targeting. So my two tests run against 3 containers shows up as 6 tests in the test runner window, plus a sweet ASCII art logo:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dVhQbe4S9AM/Socjs21zkSI/AAAAAAAAAJE/NsYrdvVJ9XQ/s1600-h/paxexam.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 173px;" src="http://4.bp.blogspot.com/_dVhQbe4S9AM/Socjs21zkSI/AAAAAAAAAJE/NsYrdvVJ9XQ/s400/paxexam.png" alt="" id="BLOGGER_PHOTO_ID_5370300334205014306" border="0" /&gt;&lt;/a&gt;One nice side effect of Maven is that IDEA can generate files off it, so you don't need to worry about the transative dependencies in the IDE, it's all configured for you. When using Gradle you do need to set up the IDE manually. I added the following JARs as dependencies and it all worked fine (with one exception):&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;commons-discovery-0.4.jar&lt;br /&gt;commons-logging-1.1.jar&lt;br /&gt;easymock-2.4.jar&lt;br /&gt;junit-4.4.jar&lt;br /&gt;log4j-1.2.12.jar&lt;br /&gt;ops4j-base-lang-1.0.0.jar&lt;br /&gt;ops4j-base-monitors-1.0.0.jar&lt;br /&gt;ops4j-base-net-1.0.0.jar&lt;br /&gt;org.osgi.core-4.0.1.jar&lt;br /&gt;osgi-3.4.0.jar&lt;br /&gt;pax-exam-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-exam-container-default-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-exam-container-rbc-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-exam-container-rbc-client-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-exam-junit-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-exam-junit-extender-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-exam-junit-extender-impl-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-exam-runtime-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-exam-spi-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-exam-testng-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-exam-tutorial-1.1.0-SNAPSHOT.jar&lt;br /&gt;pax-runner-no-jcl-1.1.0.jar&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;You can surely discard a lot of these JARs. But I added the list of completeness. It's just the IDE setup. I did have one issue with running the tests in the IDEA. Between runs I needed to manually delete my $TEMP_DIR/paxexam_runner_[user] folder. It sounds like no one else is experiencing this issue and I'm using a snapshot I built myself from source. The mailing list has been pretty responsive but it's a mystery error for now.&lt;br /&gt;&lt;br /&gt;That's the end of it, folks. I'm going to the back yard to sit in the kiddie pool with my daughter. It's hot as a mutha in my office.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1032500851979891249?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1032500851979891249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1032500851979891249' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1032500851979891249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1032500851979891249'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/08/testing-osgi-bundles-with-pax-exam.html' title='Testing OSGi Bundles with Pax Exam, Groovy and Gradle'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_dVhQbe4S9AM/Socjs21zkSI/AAAAAAAAAJE/NsYrdvVJ9XQ/s72-c/paxexam.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-444043344492741684</id><published>2009-08-12T22:34:00.004-05:00</published><updated>2009-08-12T22:46:10.144-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy + OSGi: Gradle Makes it Easy</title><content type='html'>I'm exploring the tooling around Groovy and OSGi for the September &lt;a href="http://groovy.mn/"&gt;Groovy.MN&lt;/a&gt; meeting, where I'm presenting &lt;a href="http://www.springone2gx.com/conference/new_orleans/2009/10/speakers/hamlet_d%27archy"&gt;Groovy+OSGi Jumpstart&lt;/a&gt; (and then on to &lt;a href="http://www.springone2gx.com/"&gt;2GX&lt;/a&gt;!).&lt;br /&gt;&lt;br /&gt;In the end, creating OSGi bundles from Groovy classes was pretty darn easy with &lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt;. The User Guide documentation wasn't exactly clear, and the current 0.7 sample project didn't do much of anything... so here's the goods while you wait for the updates to released.&lt;br /&gt;&lt;br /&gt;A good background on using Groovy and OSGi is the &lt;a href="http://hamletdarcy.blogspot.com/2008/12/beginners-guide-to-osgi-on-desktop.html"&gt;Beginner's Guide to OSGi on the Desktop&lt;/a&gt;. It explains bundles and Activators are, and what the Import-Package and Export-Package metadata specifies. In a nutshell: an OSGi bundle is a JAR file with extra data in the MANIFEST.MF. It's dependencies are specified in the Import-Package attribute and it's exported API is specified in the Export-Package attribute. On bundle startup, a method called Activator.start() is called, and on shutdown Activator.shutdown() is called. The bundle replaces the JAR as a unit of deployment, the dependency management metadata replaces JAR Hell, and the Activator replaces "public static void main".&lt;br /&gt;&lt;br /&gt;This post will show you a few things:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;how to implement an Activator in Groovy&lt;/li&gt;&lt;li&gt;how valid bundle metadata looks&lt;/li&gt;&lt;li&gt;how to create the bundle from Gradle&lt;/li&gt;&lt;li&gt;how to load and execute the bundle in Eclipse Equinox&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;A Groovy Activator&lt;/span&gt;&lt;br /&gt;This couldn't be much simpler. Implement the org.osgi.framework.BundleActivator interface in Groovy. You now have knowledge of 4% of the OSGi API (it's only 27 classes, you know).&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;package org.gradle&lt;br /&gt;&lt;br /&gt;import org.osgi.framework.BundleActivator&lt;br /&gt;import org.osgi.framework.BundleContext&lt;br /&gt;&lt;br /&gt;public class GradleActivator implements BundleActivator {&lt;br /&gt;&lt;br /&gt; public void start(BundleContext context) {&lt;br /&gt;     println "Hello from a Groovy Gradle Activator"&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void stop(BundleContext context) {&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Notice, I put this in the org.gradle package (it's important later). Now think for a moment about all the public methods on this object... can you name all 16 methods Groovy adds?.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Valid Bundle Metadata&lt;/span&gt;&lt;br /&gt;The bundle metadata in the JAR's MANIFEST.MF file needs to specify, at a minimum, a unique SymbolicName, all the ImportPackages that the class will need to run, and all the ExportPackages that other classes will need to run it.&lt;br /&gt;&lt;br /&gt;What does this activator need for ImportPackage? It needs to import org.gradle (itself), and it needs to import org.osgi.framework (the interface). You also need to import groovy.lang and a few other Groovy packages so that Groovy method dispatch works correctly.&lt;br /&gt;&lt;br /&gt;What does the activator need for ExportPackage? Certainly org.gradle, so that the container can invoke the Activator. What else? This hidden dependencies are in the silent API of Groovy objects. All Groovy objects have a get/setMetaClass that operates on type groovy.lang.MetaClass. So to use the Activator you need to export groovy.lang and a few other packages, even if you don't invoke those methods!&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;A Gradle Generated MANIFEST.MF&lt;/span&gt;&lt;br /&gt;Luckily, the Gradle OSGi plugin handles all of the ImportPackage and ExportPackage dependencies for you. Here is the full MANIFEST that Gradle generates:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Manifest-Version: 1.0&lt;br /&gt;Ant-Version: Apache Ant 1.7.0&lt;br /&gt;Created-By: 1.6.0_04 (Sun Microsystems Inc.)&lt;br /&gt;Export-Package: org.gradle;uses:="groovy.lang,org.codehaus.groovy.refl&lt;br /&gt; ection,org.codehaus.groovy.runtime,org.osgi.framework,org.codehaus.gr&lt;br /&gt; oovy.runtime.callsite";version="1.0"&lt;br /&gt;Bundle-Version: 1.0&lt;br /&gt;Tool: Bnd-0.0.255&lt;br /&gt;Bnd-LastModified: 1250128067203&lt;br /&gt;Bundle-Name: Example Gradle Activator&lt;br /&gt;Bundle-ManifestVersion: 2&lt;br /&gt;Bundle-Activator: org.gradle.GradleActivator&lt;br /&gt;Import-Package: groovy.lang;version="1.6",org.codehaus.groovy.reflecti&lt;br /&gt; on;version="1.6",org.codehaus.groovy.runtime;version="1.6",org.codeha&lt;br /&gt; us.groovy.runtime.callsite;version="1.6",org.gradle;version="1.0",org&lt;br /&gt; .osgi.framework;version="1.4"&lt;br /&gt;Bundle-SymbolicName: gradle_tooling.osgi&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;It's a mouthful! Gotta love the wrapping rules on manifest files. Did you know the wrapping is defined not on the number of characters in a line but the number of bytes? Ugh.&lt;br /&gt;&lt;br /&gt;Anway, as you can see, the Export-Package and Import-Package are correct. Groovy was discovered and specified. You can also see in the Tool attribute that &lt;a href="http://www.aqute.biz/Code/Bnd"&gt;bnd&lt;/a&gt; is used under the covers.&lt;br /&gt;&lt;br /&gt;In Gradle, you use the OSGi plugin to simplify the generation of the manifest. The following build file specifies the &lt;a href="http://www.eclipse.org/equinox/"&gt;Equinox&lt;/a&gt; dependency (to resolve the OSGi classes) and the Groovy dependency (to compile the Groovy). The "&lt;span style="font-family:courier new;"&gt;configure(jar.osgi)&lt;/span&gt;" begins the OSGi configuration. By specifying the * for import and export packages, bnd is invoked to determine the dependencies. 22 lines of build script gives you a "gradle jar" target that creates a valid bundle:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;group = 'gradle_tooling'&lt;br /&gt;version = '1.0'&lt;br /&gt;&lt;br /&gt;usePlugin 'groovy'&lt;br /&gt;usePlugin 'osgi'&lt;br /&gt;&lt;br /&gt;repositories {&lt;br /&gt;  mavenRepo(urls: 'http://repository.jboss.org/maven2/')&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dependencies {&lt;br /&gt;  groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.6.0'&lt;br /&gt;  compile( 'org.eclipse:osgi:3.4.3.R34x_v20081215-1030' )&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;configure(jar.osgi) {&lt;br /&gt;  version = '1.0'&lt;br /&gt;  name = 'Example Gradle Activator'&lt;br /&gt;  instruction 'Bundle-Activator', 'org.gradle.GradleActivator'&lt;br /&gt;  instruction 'Import-Package', '*'&lt;br /&gt;  instruction 'Export-Package', '*'&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Proof Positive&lt;/span&gt;&lt;br /&gt;It's a hello world bundle, right? So let's run it!&lt;br /&gt;&lt;br /&gt;Invoke the OSGi container in console mode:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;java -jar %osgi_jar% -console&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The Gradle script will stick the OSGi jar in the .gradle cache. Mine is at $home/.gradle/cache/org.eclipse/osgi/jars/osgi-3.4.3.R34x_v20081215-1030.jar&lt;br /&gt;&lt;br /&gt;Now just install and start the bundle:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;osgi&amp;gt; ss&lt;br /&gt;&lt;br /&gt;Framework is launched.&lt;br /&gt;&lt;br /&gt;id      State       Bundle&lt;br /&gt;0       ACTIVE      org.eclipse.osgi_3.4.0.v20080605-1900&lt;br /&gt;&lt;br /&gt;osgi&amp;gt; install file:/d:/libs/groovy-all-1.6-beta-2.jar&lt;br /&gt;Bundle id is 27&lt;br /&gt;&lt;br /&gt;osgi&amp;gt; install file:/d:/libs/osgi-1.0.jar&lt;br /&gt;Bundle id is 28&lt;br /&gt;&lt;br /&gt;osgi&amp;gt; ss&lt;br /&gt;&lt;br /&gt;Framework is launched.&lt;br /&gt;&lt;br /&gt;id      State       Bundle&lt;br /&gt;0       ACTIVE      org.eclipse.osgi_3.4.0.v20080605-1900&lt;br /&gt;27      INSTALLED   groovy-all_1.6.0.beta-2&lt;br /&gt;28      INSTALLED   gradle_tooling.osgi_1.0.0&lt;br /&gt;&lt;br /&gt;osgi&amp;gt; start 28&lt;br /&gt;Hello from a Groovy Gradle Activator&lt;br /&gt;&lt;br /&gt;osgi&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Wheee! It works; hooray for Gradle, Groovy and OSGi... a trifecta of un-suck.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-444043344492741684?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/444043344492741684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=444043344492741684' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/444043344492741684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/444043344492741684'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/08/groovy-osgi-gradle-makes-it-easy.html' title='Groovy + OSGi: Gradle Makes it Easy'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4429623059271638113</id><published>2009-08-06T20:33:00.011-05:00</published><updated>2009-08-06T20:55:02.216-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>30 Days Locked in a Team Room</title><content type='html'>Spent the last 30 days in a conference room converted into a shared work area for me and four of my (now) closest co-workers. We had asked to be moved to a shared space but none of us actually expected it to happen. After a month of it, all I can say is:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;I do not want work in a cubicle ever again for as long as I live. Ever. Period.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One dude whistles. One dude crunches mini carrots all day long. One person is negotiating a house sale on the phone. And I pop my gum incessantly (if I don't I get an overwhelming urge for tobacco products). Yet it is the best work environment I've had in years.&lt;br /&gt;&lt;br /&gt;Today I had to write up a summary of the team's past 8 retrospectives. Almost every single action item from the retrospectives over 4 months had to do with improving communication in some form, talking to each other more frequently, or getting better feedback. Until we got the team room. After moving to a shared space, the action items had nothing to do with communication. Empirically speaking, the team room unequivocally solved our project's biggest problems.&lt;br /&gt;&lt;br /&gt;A team room has absolutely not lead to more interruptions. Side conversations are very easy to ignore. And any question you have is usually answered within seconds. Compare that to sending someone an IM seeing if they are available and then wandering over to talk. Speaking of, it's been wonderful not having to run some stupid instant messenger program in the background all day.&lt;br /&gt;&lt;br /&gt;Cubicles are inhumane. Solitary confinement is punishment under most systems. Closing ourselves off from human contact and than holding a meeting to discuss ways to improve collaboration is laughable if we didn't actually hold those meetings every few months.&lt;br /&gt;&lt;br /&gt;The insanity ended for me 30 days ago. I never, ever want to go back to working in a cubicle.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-4429623059271638113?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/4429623059271638113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=4429623059271638113' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4429623059271638113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/4429623059271638113'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/08/30-days-locked-in-team-room.html' title='30 Days Locked in a Team Room'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-5337532924089604516</id><published>2009-08-04T20:44:00.000-05:00</published><updated>2009-08-04T20:44:45.352-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='OSGi'/><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><title type='text'>IntelliJ IDEA 9 OSGi Support Explored</title><content type='html'>&lt;a href="http://www.jetbrains.net/confluence/display/IDEADEV/Maia+EAP"&gt;IntelliJ IDEA 9 (Maia)&lt;/a&gt; purports to support OSGi bundles... so I dug in the weekend to find out just what this means.&lt;br /&gt;&lt;br /&gt;This blog posts provides a quick start guide for two things: 1) getting the IDEA 9 EAP to publish your library as an OSGi bundle, and 2) getting a second bundle published and running to test your library.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;General Impressions&lt;/strong&gt;&lt;br /&gt;The IDEA 9 OSGi support is a port/conversion of the &lt;a href="http://osmorc.org/"&gt;Osmorc plugin&lt;/a&gt; which was available in version 8. In general, the functionality seems stable but sparsely documented. I could find neither a discussion group nor documentation for Osmorc. A lot of the configuration was a process of trial and error. But it does all seem to work, and after investing a few hours it has started to seem straight-forward in hindsight. You'll have to judge for yourself how it compares to Eclipse (that's next on my list!). Osmorc tries to do a lot of auto-magic generation for you, and when I stepped outside the norm (like including Groovy as a test-only dependency) I was confronted with hard to fix failures. However, this may not be a fair criticism. For any serious project, you will want to write a bnd script, not simply use an IDE, and IDEA lets you use a bnd script to drive the OSGi configuration. So at points where the config wizard started to get difficult, I really should have stepped back and created a bnd script.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Getting a Bundle Published&lt;/strong&gt;&lt;br /&gt;While Eclipse seems to be focused on creating a Plugin (ie Bundle) from scratch using a wizard, IDEA is more focused on including OSGi support on one of your existing libraries using an OSGi facet. There is no "Create OSGi Project" wizard. You simply need to add an OSGi facet to one of your projects. I find this approach more reasonable. But let's not get too far before describing the basics of publishing a bundle:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. Installing IntelliJ IDEA 9 and OSGi&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;   Download and install the &lt;a href="http://www.jetbrains.net/confluence/display/IDEADEV/Maia+EAP"&gt;Maia EAP&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Download and install an OSGi SDK (not just the framework jar). I had trouble with Eclipse Equinox, but &lt;a href="http://www.knopflerfish.org/download.html"&gt;KnopplerFish&lt;/a&gt; worked just fine&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;2. Configuring IntelliJ IDEA for OSGi&lt;/span&gt;&lt;br /&gt;The next step is to tell IDEA about your OSGi SDK. In Settings (Ctrl+Alt+S), go to OSGi-&gt;IDE Settings-&gt;Framework Definitions and add your framework:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dVhQbe4S9AM/SniPWusd4fI/AAAAAAAAAIE/bj_VUldDyLE/s1600-h/1FrameworkDefinitions.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 281px;" src="http://2.bp.blogspot.com/_dVhQbe4S9AM/SniPWusd4fI/AAAAAAAAAIE/bj_VUldDyLE/s400/1FrameworkDefinitions.png" alt="" id="BLOGGER_PHOTO_ID_5366196576666378738" border="0" /&gt;&lt;/a&gt;  Now tell IDEA to use the framework you just registered. In Settings (Ctrl+Alt+S), go to OSGi-&gt;Project Settings and select your framework in the dropdown:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dVhQbe4S9AM/SniPW0UA31I/AAAAAAAAAIM/K0U8oG3YGPU/s1600-h/2ProjectSettings.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 203px;" src="http://2.bp.blogspot.com/_dVhQbe4S9AM/SniPW0UA31I/AAAAAAAAAIM/K0U8oG3YGPU/s400/2ProjectSettings.png" alt="" id="BLOGGER_PHOTO_ID_5366196578174426962" border="0" /&gt;&lt;/a&gt;  Done!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3. Publishing Your Library&lt;/span&gt;&lt;br /&gt;Now let's publish your Java library as an OSGi bundle. In this example, I'm using my &lt;a href="http://code.google.com/p/filter4osgi/"&gt;filter4osgi&lt;/a&gt; library that provides a nice API for LDAP style filters (shameless plug: I'll &lt;a href="http://code.google.com/p/filter4osgi/wiki/PaidBugReports"&gt;pay you for bug reports&lt;/a&gt;). This step will create the OSGi .jar file and required manifests.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;  Open an existing IDEA project... the fewer dependencies the easier it will be to publish&lt;/li&gt;&lt;li&gt;Add the OSGi facet to the project module. Clicking the little plus sign and picking OSGi should do the trick.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dVhQbe4S9AM/SniPXHggCFI/AAAAAAAAAIU/Gch6N66l8JY/s1600-h/3FacetBundleJar.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 298px;" src="http://3.bp.blogspot.com/_dVhQbe4S9AM/SniPXHggCFI/AAAAAAAAAIU/Gch6N66l8JY/s400/3FacetBundleJar.png" alt="" id="BLOGGER_PHOTO_ID_5366196583327074386" border="0" /&gt;&lt;/a&gt;  A note about the OSGi facet... currently, you're not able to add more than one OSGi facet to a module. For me, this forced me to create a multi-module project in order to produce several OSGi bundles from the same codebase. This seems like a considerable limitation to me but maybe my projects are structured strangely.&lt;br /&gt;&lt;br /&gt;The Manifest Generation tab allows you to specify the exported packages for the bundle. I needed to manually add the package I wanted to export, Osmorc did not seem to discover this for me. Again, using bnd is probably the best option here.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dVhQbe4S9AM/SniPXns-5oI/AAAAAAAAAIc/_pgb9XicwAA/s1600-h/4FacetManifestGeneration.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 298px;" src="http://3.bp.blogspot.com/_dVhQbe4S9AM/SniPXns-5oI/AAAAAAAAAIc/_pgb9XicwAA/s400/4FacetManifestGeneration.png" alt="" id="BLOGGER_PHOTO_ID_5366196591969363586" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;There are plenty of other options, but they aren't as important right now. And note, I didn't add an Activator, because my bundle is just a library.&lt;br /&gt;&lt;br /&gt;To verify that you published your library correctly, rebuild the application. The jar file should be written to disk. The manifest file with the OSGi headers is pretty simple:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Manifest-Version: 1.0&lt;br /&gt;Export-Package: org.filter4osgi.builder;version="0.0.1"&lt;br /&gt;Bundle-Version: 0.0.1&lt;br /&gt;Tool: Bnd-0.0.337&lt;br /&gt;Bnd-LastModified: 1249412068156&lt;br /&gt;Bundle-Name: filter4osgi&lt;br /&gt;Bundle-ManifestVersion: 2&lt;br /&gt;Created-By: 1.6.0_12 (Sun Microsystems Inc.)&lt;br /&gt;Import-Package: org.filter4osgi.builder;version="0.0"&lt;br /&gt;Bundle-SymbolicName: filter4osgi&lt;br /&gt;Include-Resource: ..\Filter4osgi&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;4. Running Your Bundle&lt;/span&gt;&lt;br /&gt;Running the bundle is simple. Create a new Run/Debug Configuration using the little plus sign:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dVhQbe4S9AM/SniPYKHY0II/AAAAAAAAAIk/-Cu8PtGyCo4/s1600-h/5RunBundles.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 305px;" src="http://3.bp.blogspot.com/_dVhQbe4S9AM/SniPYKHY0II/AAAAAAAAAIk/-Cu8PtGyCo4/s400/5RunBundles.png" alt="" id="BLOGGER_PHOTO_ID_5366196601206919298" border="0" /&gt;&lt;/a&gt;  Just use the Add button to specify your bundle. You can also specify dependent bundles too.&lt;br /&gt;On the Parameters tab, you'll need to specify the OSGi framework to run within:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dVhQbe4S9AM/SniPrBDW9BI/AAAAAAAAAIs/CdGyg4LFodw/s1600-h/6RunParameters.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 325px;" src="http://1.bp.blogspot.com/_dVhQbe4S9AM/SniPrBDW9BI/AAAAAAAAAIs/CdGyg4LFodw/s400/6RunParameters.png" alt="" id="BLOGGER_PHOTO_ID_5366196925191615506" border="0" /&gt;&lt;/a&gt;  Now just click Run, and your console output window should have something like this written to it:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Knopflerfish OSGi framework, version 4.1.7&lt;br /&gt;Copyright 2003-2009 Knopflerfish. All Rights Reserved.&lt;br /&gt;&lt;br /&gt;See http://www.knopflerfish.org for more information.&lt;br /&gt;Failed to remove existing fwdir C:\Documents and Settings\hdarcy\.IntelliJIdea90\system\osmorc\runtmp1249413066328&lt;br /&gt;Framework launched&lt;br /&gt;Installed: file:///D:/dev/filter4osgi/out/production/Filter4osgi.jar (id#1)&lt;br /&gt;Started: file:///D:/dev/filter4osgi/out/production/Filter4osgi.jar (id#1)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;    It worked! (Although I have no idea why there is a failure removing "fwdir", whatever that means). Alternately, you can load the jar file into any other container and interact with it that way. One feature that is missing is the ability to interact with the container from IDEA. You cannot issue the stop or uninstall commands. In fact, the only way I found to stop the container is with the big red Stop button. It would be better if you could issue text commands to the container. This doesn't seem like it would be difficult to add.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5. Testing Your Bundle with an OSGi Test Harness&lt;/span&gt;&lt;br /&gt;There are a few test utilities for OSGi, such as &lt;a href="http://wiki.ops4j.org/display/paxexam/Pax+Exam"&gt;Pax Exam&lt;/a&gt; and the &lt;a href="https://www.knopflerfish.org/svn/knopflerfish.org/trunk/osgi/bundles_opt/junit/readme.txt"&gt;Knopflerfish Junit Support&lt;/a&gt;, but all I wanted to do was write a bundle that imported filter4osgi and made sure the classes were available. So I simply added a new module to my project called "filter4osgiIntegrationTest". To this I added the Knopflerfish framework.jar since I needed to create an Activator. Take note, the prior example of exposing a library as a bundle required zero design or runtime dependencies on any OSGi implementation.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Without&lt;/i&gt; adding the OSGi facet, I created a new Java class that implemented BundleActivator. IDEA flagged me with a missing facet error and asked if I'd like to create a facet, which I did. Nice!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dVhQbe4S9AM/SniPrpuPJAI/AAAAAAAAAI0/Gr_tYZSTMPU/s1600-h/7FacetManifestGeneration.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 292px;" src="http://4.bp.blogspot.com/_dVhQbe4S9AM/SniPrpuPJAI/AAAAAAAAAI0/Gr_tYZSTMPU/s400/7FacetManifestGeneration.png" alt="" id="BLOGGER_PHOTO_ID_5366196936108876802" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;  The Manifest Generation tab was mostly filled in, but again I needed to hand edit the MANIFEST.MF data so that it imported the package from the original filter4osgi bundle and added the root '.' to the bundle classpath (otherwise there were ClassNotFound exceptions).&lt;br /&gt;&lt;br /&gt;Now I just implemented the activator to construct a new filter object:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public class ActivatorForTesting implements BundleActivator {&lt;br /&gt; @Override&lt;br /&gt; public void start(BundleContext context) throws Exception {&lt;br /&gt;   FilterBuilder filter = or(&lt;br /&gt;     and(&lt;br /&gt;       eq("mailbox", "default"),&lt;br /&gt;       eq("lang", "EN_US")&lt;br /&gt;     ),&lt;br /&gt;     and(&lt;br /&gt;       eq("mailbox", "dflt"),&lt;br /&gt;       eq("lang", "EN_CA")&lt;br /&gt;     )&lt;br /&gt;   );&lt;br /&gt;   assert filter.toString().equals("(|(&amp;amp;(mailbox=default) (lang=EN_US)) (&amp;amp;(mailbox=dflt) (lang=EN_CA)))");&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public void stop(BundleContext context) throws Exception { }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Hey, that's not a bad API for working with LDAP filters, is it?&lt;br /&gt;&lt;br /&gt;And now it's time to create the Run/Debug Configuration, which was probably the hardest step in all this. In the Run Config, I needed to specify that both the filter4osgi and filter4osgiIntegrationTest need to be started up, and that the filter4osgi must be started first. You do this in the Bundles tab, and ordering is done by indicating a Start Level:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dVhQbe4S9AM/SniPrz78F7I/AAAAAAAAAI8/FvZiXzRA9X0/s1600-h/8RunBundles.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 306px;" src="http://2.bp.blogspot.com/_dVhQbe4S9AM/SniPrz78F7I/AAAAAAAAAI8/FvZiXzRA9X0/s400/8RunBundles.png" alt="" id="BLOGGER_PHOTO_ID_5366196938850703282" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Now, when I run the config, I should see that both bundles were started. And if I don't get a ClassNotFound error then I know that the filter4osgi exports lined up correctly with the filter4osgiIntegrationTest imports. Which they do:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Knopflerfish OSGi framework, version 4.1.7&lt;br /&gt;Copyright 2003-2009 Knopflerfish. All Rights Reserved.&lt;br /&gt;&lt;br /&gt;See http://www.knopflerfish.org for more information.&lt;br /&gt;Failed to remove existing fwdir C:\Documents and Settings\hdarcy\.IntelliJIdea90\system\osmorc\runtmp1249414635312&lt;br /&gt;Framework launched&lt;br /&gt;Installed: file:///D:/dev/filter4osgi/out/production/Filter4osgi.jar (id#1)&lt;br /&gt;Started: file:///D:/dev/filter4osgi/out/production/Filter4osgi.jar (id#1)&lt;br /&gt;Installed: file:///D:/dev/filter4osgi/out/production/filter4osgiIntegrationTest.jar (id#2)&lt;br /&gt;Started: file:///D:/dev/filter4osgi/out/production/filter4osgiIntegrationTest.jar (id#2)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Perfect!&lt;br /&gt;&lt;br /&gt;All in all, the support was quite usable. I think starting with a bnd file would have made things easier for me, as well as if IDEA had let me interact directly with the container.Definitely looking forward to the official release!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-5337532924089604516?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/5337532924089604516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=5337532924089604516' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5337532924089604516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5337532924089604516'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/08/intellij-idea-9-osgi-support-explored.html' title='IntelliJ IDEA 9 OSGi Support Explored'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_dVhQbe4S9AM/SniPWusd4fI/AAAAAAAAAIE/bj_VUldDyLE/s72-c/1FrameworkDefinitions.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-5817994100007495920</id><published>2009-07-29T22:31:00.001-05:00</published><updated>2009-07-29T22:32:28.639-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='craft'/><title type='text'>10 Second Code Review</title><content type='html'>Weighing in on code reviews are &lt;a href="http://marioaquino.blogspot.com/2009/07/my-code-review-criteria_26.html"&gt;all&lt;/a&gt; &lt;a href="http://codetojoy.blogspot.com/2009/07/more-on-code-reviews.html"&gt;the&lt;/a&gt; &lt;a href="http://stuffthathappens.com/blog/2009/07/29/code-reviews/"&gt;rage&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Along the lines of getting a group to start having code reviews... when I hear that code reviews are too time consuming my reply is, "Hogwash! I can do a code review in 10 seconds without even scrolling down the source file."&lt;br /&gt;&lt;br /&gt;Just look at the import list in this worst case example:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;import com.mycompany.services.UserService;&lt;br /&gt;import com.mycompany.services.UserServiceImpl;&lt;br /&gt;import javax.persistence.EntityManager;&lt;br /&gt;import javax.swing.JFrame;&lt;br /&gt;import com.thirdcompany.COMBridge;&lt;br /&gt;import javax.swing.JLabel;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Dependency Inversion Principle - The presence of a service interface and a service implementation (UserService and UserServiceImpl) means the developer is probably instantiating the concrete dependency somewhere. Reject the code on grounds of not using the IoC container.&lt;br /&gt;&lt;br /&gt;Separation of Concerns - The presence of EntityManager (persistence) and a JFrame (user interface) means that code working with the database is intermingled with user interface display. Reject the code on grounds of poor separation of concerns.&lt;br /&gt;&lt;br /&gt;Programming to Interfaces - The COMBridge import from a 3rd party package indicates that risk-laden dependencies have not been abstracted out of the core business logic. Reject the code on grounds of no programming to interfaces.&lt;br /&gt;&lt;br /&gt;Broken Windows - Imagine that the JLabel import is gray in the IDE because it is unused. Code should compile with no warnings, and all warnings should be cleaned before the code review begins. Reject the code on grounds of sloppiness.&lt;br /&gt;&lt;br /&gt;OK, so this is a little facetious. I don't really do code reviews in 10 seconds. The point is that there's a wealth of information available with little effort on the reader's part. Code reviews are not a big commitment. Hopefully, you'll have more than 10 seconds budgeted for this. Maybe you have as many as 30 seconds! In that case all you'll need to do is look at the type signatures within the class.Easy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-5817994100007495920?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/5817994100007495920/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=5817994100007495920' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5817994100007495920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/5817994100007495920'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/07/10-second-code-review.html' title='10 Second Code Review'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3515170102895161849</id><published>2009-07-29T21:18:00.000-05:00</published><updated>2009-07-29T21:20:28.779-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDEA'/><title type='text'>IntelliJ IDEA 8 - The Good Parts</title><content type='html'>I keep getting asked if the upgrade from IDEA 7 to IDEA 8 is worth the cost.&lt;br /&gt;&lt;br /&gt;While all the new features are &lt;a href="http://www.jetbrains.com/idea/features/index.html"&gt;listed on the IDEA site&lt;/a&gt;, these are my favorite 5 features of IDEA 8, listed in the order I like 'em best.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Database Support&lt;/strong&gt;&lt;br /&gt;The new &lt;a href="http://www.jetbrains.com/idea/features/sql.html"&gt;SQL Console&lt;/a&gt; means you now get code completion, syntax highlighting, and error highlighting in your SQL scripts. Plus, no more launching a 2nd application to run queries. Very useful, but does seem to work better in MySQL than MS-SQL.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;7 new Java Refactorings&lt;/strong&gt;&lt;br /&gt;The most useful of the &lt;a href="http://www.jetbrains.com/idea/features/features.html#New_Java_Refactorings"&gt;new rafactorings&lt;/a&gt; are Extract Method Object, which allows you to extract method on blocks with more than one result type, and "Introduce Parameter Object" to compact long parameter lists. Use with care, you may not end up with a &lt;a href="http://hamletdarcy.blogspot.com/2009/07/when-testability-and-readability.html"&gt;meaningless abstraction&lt;/a&gt; in your object model. Also, Introduce Constant got a big upgrade that lets you extract just parts of big static strings. Nice!&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;UML Diagrams&lt;/strong&gt;&lt;br /&gt;You can &lt;a href="http://www.jetbrains.com/idea/features/features.html#UML_Class_Diagrams"&gt;create diagrams&lt;/a&gt; right in the IDE now. I think there were some plugins in the past that allowed this, but now a nice version of the feature is available in IDEA. You can generate diagrams, and can also create new entities, refactor, and navigate directly to source code. The diagrams &lt;a href="http://2.bp.blogspot.com/_dVhQbe4S9AM/SmfNej06TcI/AAAAAAAAAH0/xL7MidQdvdg/s1600/graph_img.png"&gt;look great&lt;/a&gt;; I've used them in some presentation already.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Groovy &amp;amp; Grails Support&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://www.jetbrains.com/idea/features/features.html#Groovy_and_Grails"&gt;Improved Groovy support&lt;/a&gt; adds a couple notable improvements: better code completion, more inspections, two new refactorings including "Convert method parameter to map-parameter entry", debugger support for Gant(!), and a whole bunch of Grails stuff.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Debugger for Flex (and Javascript)&lt;/strong&gt;&lt;br /&gt;We're using FlexBuilder for official Flex development at work, but for me, who does mostly Java, I've found it useful to use the IDEA &lt;a href="http://www.jetbrains.com/idea/features/features.html#1#Debuggers_for_JavaScript_and_Flex"&gt;Flex debugger&lt;/a&gt; when I don't feel like launching a 2nd huge application on my workstation. We evaluated IDEA 8 as a replacement for FlexBuilder and decided not to, but we'll take another look at IDEA 9 Flex support and maybe switch then. There's also a Javascript debugger but I haven't touched that language in a year or so.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Honorable Mentions&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.jetbrains.com/idea/features/features.html#Dataflow_To_This_Command"&gt;Dataflow to This&lt;/a&gt; - Shows you how a certain variable got the value it did. Think of it as a better call stack window.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.jetbrains.com/idea/features/features.html#Thread_dump_analyzer"&gt;Thread Dump Analyzer&lt;/a&gt; - The new window is way easier on the eyes than scanning through text thread dumps. Nice.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.jetbrains.com/idea/features/features.html#Spring_25"&gt;Spring 2.5 support&lt;/a&gt; - Use it every day so that some of the new Spring annotations are recognizable and navigable.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.jetbrains.com/idea/features/settings_sync.html"&gt;IDE Settings Synchronization&lt;/a&gt; - Share all your IDE settings between several workstations.&lt;br /&gt;&lt;br /&gt;Those are the things I use the most... there is, of course, way more new than that. If you know me and want a 60 day trial license (normally they are only 30) then drop me an email!&lt;br /&gt;&lt;br /&gt;Or check out the &lt;a href="http://www.jetbrains.net/confluence/display/IDEADEV/Maia+EAP"&gt;IDEA 9 EAP&lt;/a&gt;.&lt;/href="http:&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3515170102895161849?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3515170102895161849/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3515170102895161849' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3515170102895161849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3515170102895161849'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/07/intellij-idea-8-good-parts.html' title='IntelliJ IDEA 8 - The Good Parts'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-1903969275706571908</id><published>2009-07-29T20:26:00.003-05:00</published><updated>2009-07-29T20:37:33.302-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='event'/><title type='text'>GUM, OTUG, 2GX, and Strange Loop, oh my!</title><content type='html'>I'm going to be out on the road September and October, talking about programming and testing and maybe trying to make people laugh a little. Here's my schedule so far:&lt;br /&gt;&lt;br /&gt;September 8th - Minneapolis, MN - &lt;a href="http://groovy.mn"&gt;Groovy Users of MN&lt;/a&gt; - Groovy+OSGi Jumpstart&lt;br /&gt;September 15th - St. Paul, MN - &lt;a href="http://otug.org/"&gt;Object Technology User Group&lt;/a&gt; - Thinking in Functions&lt;br /&gt;October 19th - 22 - New Orleans, LA - &lt;a href="http://www.springone2gx.com"&gt;2GX Groovy/Grails Conference&lt;/a&gt; - All 4 talks for 1 low price!&lt;br /&gt;October 23rd - St. Louis, MO - &lt;a href="http://thestrangeloop.com/"&gt;Strange Loop&lt;/a&gt; - Groovy Compiler Metaprogramming for Fun and Profit&lt;br /&gt;&lt;br /&gt;If you haven't registered for 2GX, get on the stick... early bird pricing ends soon. And if you haven't heard of Strange Loop, then be sure to check out this super affordable unique and esoteric event.&lt;br /&gt;&lt;br /&gt;I'm definitely interested in practicing these talks as much as possible, so if you need a speaker for a JUG or work group just let me know. The legacy code talk has turned out to be a really fun event, and it can have as little or as much Groovy as you want. Southwest has super cheap airfare right now... all I need is an invite. &lt;br /&gt;&lt;br /&gt;Here are the summaries for the talks:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Groovy Compiler Metaprogramming and AST Transformations (aka Groovy Compiler Metaprogramming for Fun and Profit) &lt;/span&gt;&lt;br /&gt;'A language should have access to its own abstract syntax' John McCarthy, Father of Lisp. Well, now Groovy 1.6 does! This talk is about why AST transformations are important, what you can do with them, and where the language world is headed. We'll dive into some of the useful Groovy annotations and libraries being written that harness AST transformations, see how to write our own, and work with the AST tools coming out with the next version. At the end we'll prognosticate about the future of programming languages in general, and hypothesize about where the Groovy features fit into the history of languages. Fun!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Functional Groovy (aka Thinking in Functions)&lt;/span&gt;&lt;br /&gt;For many, learning Groovy made you think differently about Java. Now it's time to think differently about Groovy. Although Groovy is not a functional language by many measures, it does support many of the common functional idioms and patterns. Come explore both how far functional programming can be pushed in Groovy, where functional programming can't currently go, and where functional programming is headed in future releases of both the language and the JVM. Learn about morphisms, option types, tail call optimization, pattern matching, and functional composition in the context of solving classic CS problems side-by-side with a more traditional functional language, and decide for yourself how terms like elegance and simplicity should drive your coding.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;OSGi and Groovy Jump Start&lt;/span&gt;&lt;br /&gt;OSGi, Jigsaw, modularity, service lifecycles, bundles... where do you start? This talk covers the basics of using OSGi and Groovy together. You'll be introduced to the OSGi framework by building a Groovy based application that introduces the core concepts of OSGi such as the module system, service registry, and service life cycles. We'll also cover common pitfalls encountered by mixing Groovy and OSGi, as well the latest OSGi tools available.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Legacy Code, Groovy, and You&lt;/span&gt;&lt;br /&gt;Thinking about writing Groovy unit tests for your legacy Java code? This session is an honest discussion about what Groovy will gain youand what it won't. Come learn the engineering practices and tools that you can use to battle tight coupling, monolithic projects, and tangled dependencies, and then decide for yourself whether Groovy is the answer for your project. Plan on returning to work with a vision of what your team can do to write better software.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-1903969275706571908?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/1903969275706571908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=1903969275706571908' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1903969275706571908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/1903969275706571908'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/07/gum-otug-2gx-and-strange-loop-oh-my.html' title='GUM, OTUG, 2GX, and Strange Loop, oh my!'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-6850322586476642459</id><published>2009-07-23T23:05:00.004-05:00</published><updated>2009-07-23T23:14:25.075-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Is ignoring private access in Groovy evil?</title><content type='html'>The world's worst kept secret has got to be that Groovy ignores the private access modifier in code. You're free to access and invoke private methods, fields, and classes. A &lt;a href="http://github.com/nealford/presentations/tree/master"&gt;well known speaker&lt;/a&gt; called this "feature" insanely useful for unit testing.&lt;br /&gt;&lt;br /&gt;I'm adding that it's also insanely evil. But it's not &lt;i&gt;both&lt;/i&gt; insanely useful &lt;i&gt;and&lt;/i&gt; insanely evil... it's &lt;i&gt;either&lt;/i&gt;, depending on how you use it. I've spend all night in &lt;a href="http://www.gimp.org/"&gt;Gimp&lt;/a&gt; making a freakin' sweet graph showing the continuum, but before the big reveal we need to review some vocabulary.&lt;br /&gt;&lt;br /&gt;The most useful addition from &lt;a href="http://xunitpatterns.com/"&gt;xUnit Patterns&lt;/a&gt; to the testing community is the classification of input and output as either direct or indirect. The easiest methods to test accept direction input (a method parameter) and return direct output (a return value). Think about testing Math#min(int, int). Damnably  easy. Indirect &lt;span style="font-style: italic;"&gt;input &lt;/span&gt;is when your system under test can't be fed input that it uses directly but can be fed an object that can locate that input. Thank about testing a class that uses EntityManager.find(Class, Object) to look up a row on the database. You can provide a mock entity manager that indirectly gives the system input. It's not too difficult but a lot harder than testing Math#min(int, int). Indirect &lt;span style="font-style: italic;"&gt;output &lt;/span&gt;is when you &lt;span style="font-style: italic;"&gt;cannot&lt;/span&gt; make assertions about the return value of the method to verify that it worked correctly. Instead you have to look at what side effects the method performed. Any time you are verifying mock method calls, or looking up that correct values were set back on the input values, then you are dealing with indirect output. This is the hardest to test.&lt;br /&gt;&lt;br /&gt;So here is testing continuum for using Groovy to ignore private access modifiers:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dVhQbe4S9AM/SmkzEASvs5I/AAAAAAAAAH8/pNxfAzWYVOA/s1600-h/diagram.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 253px; height: 400px;" src="http://3.bp.blogspot.com/_dVhQbe4S9AM/SmkzEASvs5I/AAAAAAAAAH8/pNxfAzWYVOA/s400/diagram.png" alt="" id="BLOGGER_PHOTO_ID_5361872975252403090" border="0" /&gt;&lt;/a&gt;This image took me like 4 hours to make so don't you dare laugh. Here's a useful key:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Not Using&lt;/strong&gt; - Clearly, it is best not to use this feature. It's how Jesus would code. Yes, I'm serious. Jesus.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Indirect input in 3rd party library&lt;/strong&gt; - So you're using a library that is hyper encapsulated and difficult to mock (like the JDK?). The library is unlikely to change frequently and you control when it changes. Sure, setting private values to provide your test with indirect input is useful. It'd be nice if there were more testable options, but at some point you have to wash your hands, stop trying to do the right thing, and just make a decision. A little like Pontius Pilate.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Indirect input in you own objects&lt;/strong&gt; - Ignoring private in your own libraries can be insanely useful for getting some tests written quickly and out the door. But you're just creating tight coupling to the implementation of other objects... and you control those objects! Clearly there is a better option, and you have the control to perform that option. On an evil scale, it's a little like Saint Paul. Huh? A saint? That's not evil? Let me remind you: Paul killed a dude. With a rock. KILLED HIM. Yeah, go look up how Saint Stephen died. So, like Paul, you are clearly violating your principles in this scenario, but the situation is redeemable. Use private access cautiously, but then come back later and do the right thing. Bad decisions now won't stop you from being canonized later.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Indirect output in 3rd party library&lt;/strong&gt; - The iteration is late, your test coverage is low, and you're stuck integrating with a shoddy 3rd party API where every method returns void. Slam some tests together and violate private access to write a fragile test coupled to implementation that looks freakishly similar to the production code. Did I just reimplement the system under test in mocks? Yup. What am I really testing? Nothing. Like Judas Iscariot, you've sacrificed your design principles for thirty pieces of silver. In 3 months, when maintenance is a nightmare, deny 3 times that you had anything to do with the code. If that fails, blame it all all on a contractor and move on.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Indirect output in your own objects&lt;/strong&gt; - Dude c'mon. The only way to test your system that &lt;span style="font-style: italic;"&gt;you &lt;/span&gt;wrote is to access private fields of objects &lt;span style="font-style: italic;"&gt;you &lt;/span&gt;own? I don't buy it. This is where the difference between TDD and Test Always shows itself. I challenge anyone to evolve a system using test &lt;i&gt;first&lt;/i&gt; that requires this sort of shenanigan. I just don't see how focusing on behaviors and testability would ever leave you like this. Whereas, trying to write tests for code after the fact might. Cain killed his brother and then denied it. That's pretty evil, just like accessing private fields on objects you own. You're given a great tool like Groovy for testing and this is how you choose to wield it? Like Abel, Groovy deserves better. When we catch you doing this, don't try to deny it. We'll know you're lying and we won't forget.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Indirect output in system under test&lt;/strong&gt; - Old school Satan bad. This is just unjustifiable and with no benefits. What can your test possibly assert? That the code you wrote performs the way you wrote it? On a continuum of useless tests, that's like Pet Rock useless. And before you say, "I'm just laying down some unit tests so that I can refactor later," let me add that almost any refactoring you perform is bound to break the tests. Have fun with that. This usage just seems evil to me.&lt;br /&gt;&lt;br /&gt;I don't often ask myself "What would Jesus do?" I try to live my live more like Pilate. I try my best but, hey man, sometimes stuff happens. Don't get hung up on it. Although, I'll admit to doing some pretty nasty stuff in the past, so a poll of my co-workers might reveal I'm more in the Paul range than I'd like to admit. How about you?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-6850322586476642459?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/6850322586476642459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=6850322586476642459' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6850322586476642459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/6850322586476642459'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/07/worlds-worst-kept-secret-has-got-to-be.html' title='Is ignoring private access in Groovy evil?'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dVhQbe4S9AM/SmkzEASvs5I/AAAAAAAAAH8/pNxfAzWYVOA/s72-c/diagram.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8141864610118926770</id><published>2009-07-23T19:59:00.003-05:00</published><updated>2009-07-23T20:07:30.955-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy+Testing: Little Things, Big Impact</title><content type='html'>When it comes to unit testing, it's the little things that drive me nuts. Or maybe it's the little things that make testing enjoyable. Optimism is better, I suppose. Now I don't buy into all that &lt;a href="http://en.wikipedia.org/wiki/The_Tipping_Point"&gt;tipping point garbage&lt;/a&gt;, but there are two Groovy features that I miss immediately when returning to Java. Almost every other rising language has them, they seem like trivialities to add to a language, and they aren't likely to be in &lt;a href="http://openjdk.java.net/projects/coin/"&gt;Project Coin&lt;/a&gt;. (Beware, all 3 of the previous statements are suppositions). And these two features are... &lt;a href="http://groovy.codehaus.org/Strings+and+GString"&gt;multi-line strings&lt;/a&gt; and &lt;a href="http://groovy.codehaus.org/Extended+Guide+to+Method+Signatures"&gt;default parameter values&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;As ridiculous as it sounds, I'm going to spend several paragraphs extolling the virtues of two language features that are so simple they can be explained in a single sentence each.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Multiline Strings&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Why am I constantly testing with XML snippets? This is a question I don't often ask myself in Groovy because XML snippets look really nice embedded in a test method:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;def garage = new Garage(&lt;br /&gt; new Car(CAR_NAME1, CAR_MAKE1),&lt;br /&gt; new Car(CAR_NAME2, CAR_MAKE2),&lt;br /&gt; new Car(CAR_NAME3, CAR_MAKE3)&lt;br /&gt;)&lt;br /&gt;  &lt;br /&gt;def actual = serialize(garage, Garage)&lt;br /&gt;  &lt;br /&gt;def expected = """&lt;br /&gt; &amp;lt;garage&amp;gt;&lt;br /&gt;   &amp;lt;car name="$CAR_NAME1" make="$CAR_MAKE1"  /&amp;gt;&lt;br /&gt;   &amp;lt;car name="$CAR_NAME2" make="$CAR_MAKE2"  /&amp;gt;&lt;br /&gt;   &amp;lt;car name="$CAR_NAME3" make="$CAR_MAKE3"  /&amp;gt;&lt;br /&gt; &amp;lt;/garage&amp;gt;"""&lt;br /&gt;  &lt;br /&gt;assertXmlEqual(expected, actual)  &lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This test method clearly shows a garage full of cars being created and a garage full of cars being expected. There is symmetry and conciseness, and I find it pretty easy to see how the input relates to the expected output. Compare the Java version:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Garage garage = new Garage(&lt;br /&gt; new Car(CAR_NAME1, CAR_MAKE1),&lt;br /&gt; new Car(CAR_NAME2, CAR_MAKE2),&lt;br /&gt; new Car(CAR_NAME3, CAR_MAKE3)&lt;br /&gt;);&lt;br /&gt;  &lt;br /&gt;String actual = serialize(garage, Garage.class);&lt;br /&gt;  &lt;br /&gt;String expected =&lt;br /&gt; "&amp;lt;garage&amp;gt;" +&lt;br /&gt; "  &amp;lt;car name=\"" + CAR_NAME1 + "\" make=\"" + CAR_MAKE1 + "\" /&amp;gt; " +&lt;br /&gt; "  &amp;lt;car name=\"" + CAR_NAME2 + "\" make=\"" + CAR_MAKE2 + "\" /&amp;gt; " +     &lt;br /&gt; "  &amp;lt;car name=\"" + CAR_NAME3 + "\" make=\"" + CAR_MAKE3 + "\" /&amp;gt; " +&lt;br /&gt; "&amp;lt;/garage&amp;gt;";&lt;br /&gt;  &lt;br /&gt;assertXmlEqual(expected, actual); &lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Whee! Escaping quote characters is fun! I can't see how the expected block lines up with the input anymore, it's lost in a sea of accidental complexity, back slashes, and quotes. Yuck. And this is some pretty simple XML. The tests as documentation idea starts to suffer without multiline strings because the only thing that finds this format easy to read is the compiler. Speaking of documentation, how about copy and pasting the XML snippet into a user document or email? Or heaven forbid generating user documentation off the test case! You're just not going to do that with the Java version. In fact, I'd say most the time I don't even write the Java version like this... the escapes and quotes bring so much clutter that I just store XML snippets in separate XML files and read them in during each test:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;Garage garage = new Garage(&lt;br /&gt; new Car(CAR_NAME1, CAR_MAKE1),&lt;br /&gt; new Car(CAR_NAME2, CAR_MAKE2),&lt;br /&gt; new Car(CAR_NAME3, CAR_MAKE3)&lt;br /&gt;);&lt;br /&gt;  &lt;br /&gt;String actual = serialize(garage, Garage.class);&lt;br /&gt;  &lt;br /&gt;String expected = readFromFile("MyTest.sample.xml");&lt;br /&gt;  &lt;br /&gt;assertXmlEqual(expected, actual);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;It's no longer abrasive on the eye, but you also completely lose the ability to see the relationship between the input and the output. You aren't helping the tests document the system by hiding all the input from the reader!&lt;br /&gt;&lt;br /&gt;Such a small thing and I find it so valuable, and it's nothing more than a notational convenience, a little syntactical sugar.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Default Parameter Values&lt;/strong&gt;&lt;br /&gt;Tiny feature; big effect on unit testing.&lt;br /&gt;&lt;br /&gt;Unit testing is about building tons of data, all in different configurations or states of construction, and then throwing that data at the system under test, observing and verifying the results. Unit tests look a lot different from production code. In production code, subroutines exist to perform smaller pieces of a larger, decomposed problem. In test code, subroutines exist to build objects. The design principles between production and test are different, and it makes sense that some language features might be very useful in test but of more limited value in production. I find default parameter values fit within this category. Consider a set of test methods that need to build a login form (username, password fields) in different states:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;JFrame frame1 = makeLoginWindow()&lt;br /&gt;JFrame frame2 = makeLoginWindow("some username")&lt;br /&gt;JFrame frame3 = makeLoginWindow("some username", "some password")&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Making a function to build a Login Window in these various states can be done within a single function in Groovy, you just have to use default parameters.&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;private JFrame makeLoginWindow(String username = null, String password = null) {&lt;br /&gt;&lt;br /&gt; JTextField userField = new JTextField()&lt;br /&gt; JTextField passwordField = new JTextField()&lt;br /&gt; if (username != null) userField.text = username&lt;br /&gt; if (password != null) passwordField.text = password&lt;br /&gt;&lt;br /&gt; JFrame frame = new JFrame()&lt;br /&gt; frame.contentPane.add(userField)&lt;br /&gt; frame.contentPane.add(passwordField)&lt;br /&gt; return frame&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Under the covers, this is still an overloaded method to the JVM. But that's alright. There is a single source for all the test data configuration, and navigating (ie reading) the test case is made easier by having a single source.&lt;br /&gt;&lt;br /&gt;In a Java test case, you're stuck defining at least 3 methods. The real rock star programmers are going to chain the method calls together... ohhh:&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;private JFrame makeLoginWindow() {&lt;br /&gt; makeLoginWindow(null, null);&lt;br /&gt;}&lt;br /&gt;private JFrame makeLoginWindow(String username) {&lt;br /&gt; makeLoginWindow(username, null);&lt;br /&gt;}   &lt;br /&gt;private JFrame makeLoginWindow(String username, String password) {&lt;br /&gt;&lt;br /&gt; JTextField userField = new JTextField();&lt;br /&gt; JTextField passwordField = new JTextField();&lt;br /&gt; if (username != null) userField.setText(username);&lt;br /&gt; if (password != null) passwordField.setText(password); &lt;br /&gt;&lt;br /&gt; JFrame frame = new JFrame();&lt;br /&gt; frame.contentPane.add(userField);&lt;br /&gt; frame.contentPane.add(passwordField);&lt;br /&gt; return frame;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Conceptually, we've just added 3 entities to the test case that didn't exist before. Navigating around labyrinths of production code is a necessary evil. There are other design constraints at play and stuffing everything into one place isn't always the right thing to do. But in the test tree, labyrinths of chained code are just evil, nothing necessary about it. Having to chase down dependencies undermines one the chief principles of testing: show clearly and simply how input is transformed to output. Default Parameters for the win.&lt;br /&gt;&lt;br /&gt;Sadly, when advocating using Groovy as a testing language, these two features are unconvincing evidence of Groovy's superiority. They just don't seem like much. They aren't very exciting. So why are they the first things I miss when creating new Java test cases?&lt;br /&gt;&lt;br /&gt;By the way: PHP has both these features. Ha!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8141864610118926770?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8141864610118926770/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8141864610118926770' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8141864610118926770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8141864610118926770'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/07/groovytesting-little-things-big-impact.html' title='Groovy+Testing: Little Things, Big Impact'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-8373374776098053087</id><published>2009-07-22T21:39:00.004-05:00</published><updated>2009-07-22T21:45:20.452-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><title type='text'>When Testability and Readability Collide</title><content type='html'>&lt;a href="http://ignorancecompounded.blogspot.com/"&gt;Walter Harley&lt;/a&gt; was kind enough to leave a comment on my last post about &lt;a href="http://hamletdarcy.blogspot.com/2009/07/busy-constructors-are-no-problem-to.html"&gt;testing busy constructors&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;"...some of the attributes that support good testability also make for poor readability. For example, loosely coupled objects make it easy to supply mocks for testing; but they also make it hard to see what's going on in the production code." &lt;/blockquote&gt;I like any man who knows how to properly use a semi-colon. Grammar aside, this is a fair statement for a lot of projects. Why do so many programmers learn to loath dependency injection and IoC container configuration? Is it perhaps, that our default object model looks something like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dVhQbe4S9AM/SmfNej06TcI/AAAAAAAAAH0/xL7MidQdvdg/s1600-h/graph_img.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 385px; height: 233px;" src="http://2.bp.blogspot.com/_dVhQbe4S9AM/SmfNej06TcI/AAAAAAAAAH0/xL7MidQdvdg/s400/graph_img.png" alt="" id="BLOGGER_PHOTO_ID_5361479806304800194" border="0" /&gt;&lt;/a&gt;In words, for each simple object (a user service in this example), you'll usually have an interface, a concrete class, a unit test, and a mock implementation. So we've created 4 entities, 3 of which are nonessential to solving the problem at hand. Oh, you're using a mocking framework so have one less than the diagram? A synthesized subclass is still kinda a subclass, isn't it? Whatever.&lt;br /&gt;&lt;br /&gt;In my experience, this quad or triad of objects repeats itself fractal like across a Java project. It's uncommon to see an interface with multiple useful implementations and it's downright rare to see suites of components that operate on those abstractions. Names seem to spread out horizontally in my projects. &lt;a href="http://java.sun.com/javase/6/docs/api/java/lang/Runnable.html"&gt;Runnable&lt;/a&gt;, &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/concurrent/Callable.html"&gt;Callable&lt;/a&gt;, &lt;a href="http://java.sun.com/javase/6/docs/api/java/awt/event/ActionListener.html"&gt;ActionListener&lt;/a&gt;, &lt;a href="http://smokejumperit.com/jconch/1.1/jconch/functor/Transformer5.html"&gt;Transformer5&lt;/a&gt;, &lt;a href="http://functionaljava.googlecode.com/svn/artifacts/2.20/javadoc/fj/F.html"&gt;F&lt;/a&gt;, &lt;a href="http://commons.apache.org/collections/api-release/org/apache/commons/collections/Predicate.html"&gt;Predicate&lt;/a&gt;... aren't these all the same thing? Why are there so many names in the world?&lt;br /&gt;&lt;br /&gt;In Java we write in names and think in names. There is no such thing as a function that accepts something and returns something. You always have to give it a name (Callable, Runnable, Transformer). And you write your APIs to those names. In Groovy you have closures to solve this problem, and you end up seeing a lot of code that works on that one unit of abstraction. But don't be fooled, it's not a problem with types. In F# and other functional languages it is entirely natural to reason about features by type instead of name. It's easy to write general algorithms that accept something with a certain signature as a parameter rather than a specific named. So my first assertion about readability and testability is that readability suffers in Java because of our culture of naming things, and we write our abstractions based on name instead of type.&lt;br /&gt;&lt;br /&gt;Another factor to consider is the difference between a meaning&lt;i&gt;ful&lt;/i&gt; abstraction and a meaning&lt;i&gt;less&lt;/i&gt; abstraction. Writing OO software is, on some level, about building models, whether it be of the problem domain, or the solution space, or the real world. An abstraction allows you to hide details that aren't needed. It allows you to write a general purpose algorithm or component that operate at a higher level than it's dependency. What possible complexity is the above UserService interface hiding from the programmer? None: it is an absolutely meaningless abstraction. And a system riddled with meaningless abstractions is just arbitrarily and needlessly complex. The problem might be in our perceived best practices...&lt;br /&gt;&lt;br /&gt;Test Driver Development pushes you to use dependency injection as a way to vary the behavior of dependencies at test time. Fine. Using mock object frameworks guides you towards declaring interfaces for objects. Now the namespace starts to get cluttered, but modern IDEs easily support navigating hundreds, even thousands of classes, so it is no real problem to have a cluttered namespace. However, long-term TDD and mocking are creating a readability beast that results in a frustrating game of "find the dependencies" when changes need to be made. And the IDE masks the problem well into the days in which your codebase undeniably becomes "legacy code". Now the code is unreadable and retrofitting the legacy code with any modicum of meaningful abstraction makes those sections of the code look alien and feel out of place. We lost the battle and testability as a technique to plug the sinking ship rather than to guide an elegant design. So my second assertion about readability and testability is that readability suffers in Java because we have become supremely efficient and versed at producing meaningless abstractions.&lt;br /&gt;&lt;br /&gt;Long term readability depends on finding type based abstractions, rather than name based ones, and then being diligent and intentional about coding to those abstractions. I don't know of any way to do this other than to think, and think hard, about the code we write every day. Sadly, some days I just don't feel up to the task.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-8373374776098053087?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/8373374776098053087/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=8373374776098053087' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8373374776098053087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/8373374776098053087'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/07/when-testability-and-readability.html' title='When Testability and Readability Collide'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_dVhQbe4S9AM/SmfNej06TcI/AAAAAAAAAH0/xL7MidQdvdg/s72-c/graph_img.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-3236497432592621109</id><published>2009-07-20T21:51:00.002-05:00</published><updated>2009-07-20T21:54:22.182-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><title type='text'>Busy Constructors (are no problem to test)</title><content type='html'>For whatever &lt;a href="http://googletesting.blogspot.com/2009/07/why-are-we-embarrassed-to-admit-that-we.html"&gt;reason&lt;/a&gt;, I was browsing &lt;a href="http://misko.hevery.com/"&gt;Miško Hevery's&lt;/a&gt; old testability blog entries and found a nice &lt;a href="http://misko.hevery.com/2008/07/30/top-10-things-which-make-your-code-hard-to-test/"&gt;top 10 list&lt;/a&gt; of developer practices that make code hard to test.&lt;br /&gt;&lt;br /&gt;Too bad I totally disagree with Item #3: Doing work in constructor. There's nothing untestable about big long constructors. No, really. Consider this horrorshow constructor, in which a global DataSource is retrieved from a &lt;a href="http://code.google.com/p/google-singleton-detector/wiki/Mingleton"&gt;mingleton&lt;/a&gt; and a concrete class is instantiated: &lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;import javax.sql.DataSource;&lt;br /&gt;&lt;br /&gt;public class UserService {&lt;br /&gt;&lt;br /&gt;   private final DataSource dataSource;&lt;br /&gt;   private final UserSettings settings;&lt;br /&gt;&lt;br /&gt;   public UserService() {&lt;br /&gt;       dataSource = DatasourceFactory.getDefault();&lt;br /&gt;       settings = new UserSettingsImpl();&lt;br /&gt;   }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Don't get me wrong, this is a horrible design. For one, retrieving the data source from a global static method is an example of a mingleton, which is global state by any other name: near impossible to inject any sort of variable behavior or polymorphism into. And instantiating a concrete implementation class (new UserSettingsImpl()) tightly couples this service to that class, another undesirable trait. This service is incredibly tightly coupled to the dependencies it requires. You'll never be able to reuse this service in another context where the datasource and user settings are different. And writing a test would be reusing this service... so what possibly makes this easy to test?&lt;br /&gt;&lt;br /&gt;Package local constructors mixed with an &lt;a href="http://www.industriallogic.com/xp/refactoring/extractParamter.html"&gt;Extract Parameter&lt;/a&gt; refactoring is what makes this easy to test. Simply create a new constructor for the object and leave out a visibility modifier. This makes the method only visible to objects in the same package (like your unit test)! Then add all the fields created in the original constructor to the parameter list. Final fields are your friend here because then the compiler will check to make sure you did this correctly. If you want to get fancy, chain the original constructor call into the new one: &lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public class UserService {&lt;br /&gt;&lt;br /&gt;   private final DataSource dataSource;&lt;br /&gt;   private final UserSettings settings;&lt;br /&gt;&lt;br /&gt;   public UserService() {&lt;br /&gt;       this(DatasourceFactory.getDefault(), new UserSettingsImpl());&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   UserService(DataSource dataSource, UserSettings settings) {&lt;br /&gt;       this.dataSource = dataSource;&lt;br /&gt;       this.settings = settings;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This transformation preserves all the type signatures that were previously in the class, so all the clients that were compiled against the original code will continue to work just fine without recompiling. So even if the class you need to refactor is depended upon from everywhere, this is still a local refactoring. None of your refactor fearing coworkers even needs to know; it'll just be between us.&lt;br /&gt;&lt;br /&gt;Did this buy us anything? Yes. All the dependencies of the class are now exposed for mocking and stubbing, without requiring changes to any calling code. Of course, your original constructor can't be tested, so if you have behavior or logic in the constructor that you need to test, then a little more creative refactoring is needed and it may not be supported with &lt;i&gt;just&lt;/i&gt; automated IDE refactorings. Some might complain that we've modified the production code simply to enable testability... but to them I ask for alternatives. When weighing time commitments and code impacts, I find this "expose local constructor" refactoring to be of real benefit and frequently used.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7290642316743338665-3236497432592621109?l=hamletdarcy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hamletdarcy.blogspot.com/feeds/3236497432592621109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7290642316743338665&amp;postID=3236497432592621109' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3236497432592621109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7290642316743338665/posts/default/3236497432592621109'/><link rel='alternate' type='text/html' href='http://hamletdarcy.blogspot.com/2009/07/busy-constructors-are-no-problem-to.html' title='Busy Constructors (are no problem to test)'/><author><name>Hamlet D'Arcy</name><uri>http://www.blogger.com/profile/04008870357169725586</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://www.hamletdarcy.com/images/china5.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7290642316743338665.post-4684080845444005078</id><published>2009-07-16T21:53:00.002-05:00</published><updated>2009-07-16T21:59:22.786-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Big Flat Test Cases Suck (and what to do about it)</title><content type='html'>It seems like all 900 pages of &lt;a href="http://xunitpatterns.com/"&gt;xUnit Patterns&lt;/a&gt; was just published a little while ago... my how things have changed since May of 2007. Back then, when it came to organizing test methods, we only had three options. Beginners always created a &lt;a href="http://xunitpatterns.com/Testcase%20Class%20per%20Class.html"&gt;test case per class&lt;/a&gt;; there was a one to one mapping between production classes and test classes, and I'd guess most people are still doing this. The enlightened testers were creating one &lt;a href="http://www.blogger.com/Test%20case%20Class%20per%20Fixture%20-%20http://xunitpatterns.com/Testcase%20Class%20per%20Fixture.html"&gt;test case per fixture&lt;/a&gt;, in which test methods were all in the same test class if they shared the same setUp() method. This was a response to the problem with test case per class, which was complexity. As the number of test methods increased the cohesion of the test case decreased. As more and more fields are added to the test to support different scenarios of testing, then each test method starts to use only a fraction of the fields available within the test case. Test case per fixture solves the problem by breaking out test methods into a new test case when new fixture and setUp() data is added. This was an improvement and was the recommended approach in Astel's &lt;a href="http://www.pearsonhighered.com/educator/product/TestDriven-Development-A-Practical-Guide/9780131016491.page"&gt;Test Driven Development&lt;/a&gt; book. The really cool kids, however, were doing &lt;a href="http://xunitpatterns.com/Testcase%20Class%20per%20Feature.html"&gt;test case per feature&lt;/a&gt;. This entails grouping test methods together based on what feature or user story they implement. Kinda sounds like an easyb story, huh? Yeah, but it hadn't really caught on yet back then.&lt;br /&gt;&lt;br /&gt;But don't be fooled! All three of these test organization methods are essentially the same: tests are going to be written as methods and enclosed in a class. How 2007... how xUnit-ish. See, all three approaches share the same deficiency.&lt;br /&gt;&lt;br /&gt;Test cases grow. They grow really long. And they all grow in one direction: down the screen. Navigation isn't too bad an issue... any IDE test runner is going to navigate you right to the correct line number when a test fails. And you'll have a naming convention for tests, so keyboarding around the file isn't too tough. It's not simple though, and some &lt;a href="http://github.com/nealford/presentations/tree/master"&gt;speakers&lt;/a&gt; are suggesting it's better to use hugely long test names and add underscores to test methods to tell them apart easier. So this: &lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public void testInitialPositionSetCorrectlyUponInstantiation()&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Is better as: &lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;public void test_initial_position_set_correctly_upon_instantiation()&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Sure, I guess that's nicer. But exactly what problem is this solving? For that matter, what is the problem with big, long test cases?&lt;br /&gt;&lt;br /&gt;Pretend we do have tests grouped by feature and that we have to make a change to that feature. How many tests are going to fail? Is there any way to tell beyond scrolling through the file and reading all the tests? It would be much easier if you could clearly see how the tests all relate to one another. But a flat list doesn't show relationships. Maybe there is a naming convention for test methods that might help, but you're still reading all the method signatures and making a decision based on name.&lt;br /&gt;&lt;br /&gt;A hierarchical test case would let you do this, though. Test dependencies would be self-evident if you could define a test scenario and then make test methods or other scenarios children to as many levels deep as you want. You could still have the ease of grouping test methods by class, because you'd get a nice one-to-one mapping between test classes and production classes. And you'd also get test case per feature because the tests for each feature could just be child scenarios under the main scenario. And you'd also get test case per fixture because each scenario could have setUp() data that is shared with all children scenarios. Can you say best of all possible worlds? An easyb example it is then! &lt;pre style="border: 1px dashed rgb(153, 153, 153); pa
