<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" version="2.0">
  <channel>
    <title>No Fluff Just Stuff</title>
    <link>http://www.therichwebexperience.com</link>
    <description>The best value in the Java/Open Source conferencing space hands down</description>
    <item>
      <title>Compass 2.0.2 Released</title>
      <link>http://www.therichwebexperience.com/blog/shay_banon/2008/08/compass_2_0_2_released.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;&lt;a href="http://www.compass-project.org"&gt;Compass&lt;/a&gt; version 2.0.2 released. This is a bug fix released for Compass 2.0 and is recommended for all Compass users. Full change log can be found &lt;a href="http://issues.compass-project.org/secure/ReleaseNote.jspa?projectId=10000&amp;#038;styleName=Html&amp;#038;version=10134"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/kimchyblog/~4/369289695" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 19 Aug 2008 16:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://www.kimchy.org/compass-202-released/</guid>
      <dc:creator>Shay Banon</dc:creator>
    </item>
    <item>
      <title>How Buildings Learn</title>
      <link>http://www.therichwebexperience.com/blog/michael_nygard/2008/08/how_buildings_learn.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;Stewart Brand's famous book &lt;a href="http://www.amazon.com/gp/product/0140139966?ie=UTF8&amp;tag=michaelnygard-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0140139966"&gt;How Buildings Learn&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=michaelnygard-20&amp;l=as2&amp;o=1&amp;a=0140139966" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt; has been on my reading queue for a while, possibly a few years. Now that I've begun reading it, I wish I had gotten it sooner. Listen to this:&lt;/p&gt;

&lt;blockquote&gt;The finished-looking model and visually obsessive renderings dominate the let's-do-it meeting, so that shallow guesses are frozen as deep decisions. All the design intelligence gets forced to the earliest part of the building process, when everyone knows the least about what is really needed.&lt;/blockquote&gt;

&lt;p&gt;Wow. It's hard to tell what industry he's talking about there. It could easily apply to software development. No wonder Brand is so well-regarded in the Agile community!&lt;/p&gt;

&lt;p&gt;Another wonderful parallel is between what Brand calls &amp;quot;Low Road&amp;quot; and &amp;quot;High Road&amp;quot; buildings. A Low Road building is one that is flexible, cheap, and easy to modify. It's hackable. Lofts, garages, old factory floors, warehouses, and so on. Each new owner can gut and modify it without qualms. A building where you can drill holes through the walls, run your own cabling, and rip out every interior wall is a Low Road building.&lt;/p&gt;

&lt;p&gt;High Road buildings evolve gradually over time, through persistent care and love. There doesn't necessarily have to be a consistent--or even coherent--vision, but each own does need to feel a strong sense of preservation. High Road buildings become monuments, but they aren't &lt;i&gt;made&lt;/i&gt; that way. They just evolve in that direction as each generation adds their own character.&lt;/p&gt;

&lt;p&gt;Then there are the buildings that aren't High or Low Road. Too static to be Low Road, but not valued enough to be High Road. Resistant to change, bureaucratic in management. Diffuse responsibility produces static (i.e., dead) buildings. Deliberately setting out to design a work of art, paradoxically, prevents you from creating a living, livable building.&lt;/p&gt;

&lt;p&gt;Again, I see some clear parallels to software architecture here. On the one hand, we've got Low Road architecture. Easy to glue together, easy to rip apart. Nobody gets bent out of shape if you blow up a hodge-podge of shoestring batch jobs and quick-and-dirty web apps. CGI scripts written in perl are classic Low Road architecture. It doesn't mean they're bad, but they're probably not going to go a long time without being changed in some massive ways.&lt;/p&gt;

&lt;p&gt;High Road architecture would express a conservativism that we don't often see. High Road is &lt;i&gt;not&lt;/i&gt; &amp;quot;big&amp;quot; architecture. Rather, High Road means cohesive systems lovingly tended. Emacs strikes me as a good example of High Road architecture. Yes, it's accumulated a lot of bits and oddments over the years, but it's quite conservative in its architecture.&lt;/p&gt;

&lt;p&gt;Enterprise SOA projects, to me, seem like dead buildings. They're overspecified and too focused on the moment of rollout. They're the grand facades with leaky roofs. They're the corporate office buildings that get gerrymandered into paralysis. They preach change, but produce stasis.&lt;/p&gt;</description>
      <pubDate>Tue, 19 Aug 2008 13:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://www.michaelnygard.com/blog/2008/08/how_buildings_learn.html</guid>
      <dc:creator>Michael Nygard</dc:creator>
    </item>
    <item>
      <title>Does Your Team Have STDs?</title>
      <link>http://www.therichwebexperience.com/blog/jared_richardson/2008/08/does_your_team_have_stds_.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>Last week I was talking with a friend about a common ailment on development teams today. And it seems to be getting worse. 
&lt;br/&gt;&lt;br/&gt;
Perhaps you've seen it already in your shop. Once one person catches an STD, it seems to spread quickly.
&lt;br/&gt;&lt;br/&gt;
STD, of course, stands for Shiny Things Development. 
&lt;br/&gt;&lt;br/&gt;
Oh cool! Check that out... it's new and cool. Let's include it in the product! Why? Umm... it solves some problem. And didn't I just say it's shiny and new?
&lt;br/&gt;&lt;br/&gt;
How many shops have you met that have insane development infrastructures "just in case" things get crazy? Anytime the shop has a list of tools and libraries where every single one requires a specific version for anything to work, someone there has STD.
&lt;br/&gt;&lt;br/&gt;
What's the problem with STD? It generally indicates a lack of discretion and promiscuous use of technology. Rather than saving yourself for something that actually works, you're chasing down every new product and technology. Sure, it might be fun to try out new stuff</description>
      <pubDate>Tue, 19 Aug 2008 11:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://agileartisans.com/main/blog/125</guid>
      <dc:creator>Jared Richardson</dc:creator>
    </item>
    <item>
      <title>Need Help with BackUpWordPress</title>
      <link>http://www.therichwebexperience.com/blog/johanna_rothman/2008/08/need_help_with_backupwordpress.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;I&amp;#8217;ve been using BackUpWordPress to backup my blogs. I successfully upgraded &lt;a href="http://www.jrothman.com/blog/htp" target="_blank"&gt;Hiring Technical People&lt;/a&gt; to a newer version of WP and of BackUpWordPress. I upgraded this blog, Managing Product Development, to the newer version of WP, but now my newer version of BackUpWordPress is not working. I&amp;#8217;m pretty sure it&amp;#8217;s all about file permissions.&lt;/p&gt;
&lt;p&gt;If you have experience with this and insight, please email me, jr at jrothman dot com. I can&amp;#8217;t figure out what I&amp;#8217;m doing wrong and want to keep backing up! Thanks.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=86EkxK"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=86EkxK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=S2BulK"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=S2BulK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=Vb7mnk"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=Vb7mnk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=ctOSYk"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=ctOSYk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=XgP9lK"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=XgP9lK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=LkYCuK"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=LkYCuK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ManagingProductDevelopment/~4/368422634" height="1" width="1"/&gt;</description>
      <pubDate>Tue, 19 Aug 2008 08:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://jrothman.com/blog/mpd/?p=8475</guid>
      <dc:creator>Johanna Rothman</dc:creator>
    </item>
    <item>
      <title>Name Soup</title>
      <link>http://www.therichwebexperience.com/blog/alex_russell/2008/08/name_soup.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;There still seems to be &lt;a href="http://tech.slashdot.org/article.pl?sid=08/08/16/1552227&amp;#038;from=rss"&gt;an amazing amount of FUD&lt;/a&gt; going around regarding the Harmony announcement. There is clearly a very different perspective from those who have been sitting inside the WG for the past year (as &lt;a href="http://www.json.com/"&gt;Kris Zyp&lt;/a&gt; and I have been lucky to). Inside the WG, the change seems a welcome way to break a logjam of reasonably held opinions of people who are all acting in good faith. From the outside, it all looks like confusion and game-playing.&lt;/p&gt;
&lt;p&gt;One of the things, though, that keeps getting me frustrated as I read the &amp;#8220;coverage&amp;#8221; is that the names people use are confused. Probably because the names are &lt;em&gt;confusing&lt;/em&gt;. Here&amp;#8217;s a quick glossary:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;ECMAScript 3&lt;/dt&gt;
&lt;dd&gt;Aka: JavaScript, ES3, ECMAScript 262-3, and JScript.&lt;/p&gt;
&lt;p&gt;The current JavaScript that every browser implements (more or less). This is the current ratified standard and represents the 3rd edition of the ECMAScript spec. It is very old. Nothing else in this list is (yet) a ratified standard of any sort.&lt;/dd&gt;
&lt;dt&gt;ECMAScript 4&lt;/dt&gt;
&lt;dd&gt;Aka: ES4, &amp;#8220;JavaScript 2&amp;#8243;. &lt;/p&gt;
&lt;p&gt;A new language which was to be mostly backwards compatible but add optional (gradual) typing and class-based inheritance. Based loosely on Adobe&amp;#8217;s ActionScript 3. This is the language effort which died as a result of Harmony.&lt;/dd&gt;
&lt;dt&gt;ECMAScript 3.1&lt;/dt&gt;
&lt;dd&gt;Aka: ES3.1. A set of small additions to ES3.&lt;/p&gt;
&lt;p&gt;Planning for this edition was started at Microsoft and Yahoo&amp;#8217;s behest late last year, causing the split in the working group which has been healed by the Harmony announcement.&lt;/dd&gt;
&lt;dt&gt;ActionScript 3&lt;/dt&gt;
&lt;dd&gt;Aka: AS3&lt;/p&gt;
&lt;p&gt;Adobe&amp;#8217;s current JavaScript-like language, only with many features lifted from languages like Java which also enforce types and class-based semantics. This was the starting point for much of the work which became known as ES4.&lt;/dd&gt;
&lt;dt&gt;Tamarin&lt;/dt&gt;
&lt;dd&gt;A JIT-ing byte-code virtual machine (VM) which is at the core of the Flash Player and was donated by Adobe to the Mozilla Foundation. This is the VM that runs ActionScript 3 code today but will likely run &amp;#8220;real&amp;#8221; JavaScript for Mozilla in the future. It is not a full implementation of ES3 or ES4, but instead implements its own byte-code and needs to be wedded to a &amp;#8220;front end&amp;#8221; (like the ActionScript 3&lt;br /&gt;
compiler from Adobe) in order to be usable by programmers.&lt;/dd&gt;
&lt;dt&gt;Tamarin-tracing&lt;/dt&gt;
&lt;dd&gt;A VM which implements the same byte-code language as Tamarin (known as &amp;#8220;ABC&amp;#8221;) but which is designed for use in mobile devices and other scenarios where code size and VM footprint are important. It implements trace-tree JIT-ing as a way to speed up hot-spots. Also donated to Mozilla by Adobe.&lt;/dd&gt;
&lt;dt&gt;TC39&lt;/dt&gt;
&lt;dd&gt;The name of the &lt;a href="http://www.ecma-international.org/memento/TC39.htm"&gt;ECMA technical committee&lt;/a&gt; which is chartered to evolve the JavaScript language.&lt;/dd&gt;
&lt;dt&gt;Harmony&lt;/dt&gt;
&lt;dd&gt;A new code-name for a language which is to come after ES3.1. It will feature many of the things ES4 was trying to accomplish, but may attempt them from different directions and will&lt;br /&gt;
focus much more on incremental, step-wise evolution of the language.
&lt;/dd&gt;
&lt;dt&gt;JavaScript 2&lt;/dt&gt;
&lt;dd&gt;A now-defunct name. This name was originally given to Waldemar Horwat&amp;#8217;s first proposal at a large-scale evolution of the JavaScript language in 1999. That effort did not succeed (although Microsoft implemented some of it in JScript.NET) and subsequent work via the current TC39 charter to build ES4 has sometimes been given the name &amp;#8220;JavaScript 2&amp;#8243;, but it never really stuck. Not a name that describes any ratified standard or current proposal.
&lt;/dd&gt;
&lt;dt&gt;ECMAScript&lt;/dt&gt;
&lt;dt&gt;
&lt;dd&gt;The formalized name of the JavaScript language. Since Sun Microsystems owns the name JavaScript and has no idea what to do with the trademark (but has been benevolent thus far), the ECMA committee which standardized the language was forced to adopt a different name.&lt;/dd&gt;
&lt;/dt&gt;
&lt;/dl&gt;</description>
      <pubDate>Mon, 18 Aug 2008 16:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://alex.dojotoolkit.org/?p=736</guid>
      <dc:creator>Alex Russell</dc:creator>
    </item>
    <item>
      <title>Cloud-Oriented Architecture (COA)</title>
      <link>http://www.therichwebexperience.com/blog/scott_leberknight/2008/08/cloud_oriented_architecture_coa_.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;With all the hype this year about cloud computing and things like Amazon EC2/S3 as well as Google App Engine and Bigtable, you can feel it coming. Soon vendors will be peddling &lt;strong&gt;COA&lt;/strong&gt; (Cloud-Oriented Architecture) solutions, probably combining them with their SOA solution and somehow probably getting their ESB solution into the mix as well. This past weekend at the Enterprise Architecture BOF at the &lt;a href="http://www.nofluffjuststuff.com/conference/cincinnati/2008/08/index.html"&gt;Southern Ohio Software Symposium&lt;/a&gt;, we had a discussion about cloud computing among other things. &lt;a href="http://blogs.tedneward.com/"&gt;Ted Neward&lt;/a&gt; even coined the term "Enterprise Service Cloud" and I came up with "Cloud Service Bus," surely the next Big Thing. Any vulture (I mean, venture) capitalists out there want to invest in my new Cloud Service Bus company? I have a pretty brochure ready to go!&lt;/p&gt;

&lt;p&gt;The big difference I see with regard to cloud computing is the fact that, unlike your typical ESB/SOA peddling vendors, companies like Amazon and Google &lt;emphasis&gt;already have cloud or cloud-like solutions in place&lt;/emphasis&gt; a la Amazon &lt;a href="http://aws.amazon.com/ec2"&gt;EC2&lt;/a&gt;/&lt;a href="http://aws.amazon.com/s3"&gt;S3&lt;/a&gt; and &lt;a href="http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html"Dynamo&lt;/a&gt;, and &lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt; and &lt;a href="http://labs.google.com/papers/bigtable.html"&gt;Bigtable&lt;/a&gt;. Now all of those things just mentioned are not "the cloud" (whatever "the cloud" actually is defined to be), but it doesn't matter because the point is these companies have designed, implemented, and most importantly, run their critical business operations on these platforms. That in and of itself is more important than all the vaporware and marketing hype any other vendor comes up with. Rather than having to get customers to believe that a solution works via marketing and then force it down their IT staff's throats, Google and Amazon are basically saying "Hey why not use stuff that we use and have proven can scale up to handle huge loads and huge amounts of data?"&lt;/p&gt;

&lt;p&gt;To me as a developer this is a much more appealing approach for several reasons. First, it means there won't be (or shouldn't need to be) any "golf-course deals" where the vendor sales guys and customer CIOs/CTOs/CEOs meet up and decide on the technology stack independent of any real technical analysis, investigation, or input of the people who will be charged with implementing the vendor stack (and they better do it well else it's their job on the line to boot).&lt;/p&gt;

&lt;p&gt;Second, I can base my decision to use a Google or Amazon service based on  their actual track record in delivering these services and eating their own dog food, since they are trying to monetize their existing investment in proven highly distributed and scalable infrastructures. Yes, there have been Amazon outages this year and whenever it happens it is big news because it is right there out in the public, as opposed to a company whose IT operations are totally in-house and which isn't going to publicize their downtime statistics. I'd wager on Amazon and Google's availability over probably most other companies. Of course I have no way to prove that last statement, but the mere fact that I can get objective statistics on their services helps in my decision making process and planning.&lt;/p&gt;

&lt;p&gt;Last, I can decide how much or how little to outsource to the Amazon or Google infrastructure; for example some organizations might choose to keep their most sensitive data (e.g. customer information, credit card numbers, etc.) in-house but outsource everything else to, say, an Amazon EC2/S3 infrastructure. There is still some level of vendor lock-in here, but there is with anything else short of you implementing your own solution from scratch. And if, by leveraging proven solutions by companies like Amazon and Google, you are able to deliver real value to your customers faster and are able to scale up, out, and beyond without needing to build that infrastructure yourself, then I'd say that could potentially equate to a big win.&lt;/p&gt;

&lt;p&gt;So when that vendor comes calling with their shiny new COA solution, be very afraid, and make sure you know your options and present them objectively. We as an industry have more buzzwords and hype (at least from my perspective) than almost any other, and this causes more money than I can possibly imagine to be wasted every year on solutions that don't (and never will) work as advertised. Developers often have a feeling that the VDD (vendor-driven development) solutions just won't work, but cannot convince their managers or their managers' managers of this fact, which is why communications skills are critical in today's world. I don't know about you, but I don't want to be the person who becomes responsible for implementing a solution I don't believe in.&lt;/p&gt;

&lt;p&gt;"The Cloud" and cloud computing are definitely here to stay forever, and as Amazon and Google have proven, can add huge amounts of value to businesses. I am sure there will be other companies perhaps trying to implement similar strategies and monetizing their investment in their own infrastructure, and that will be mostly a good thing to have different options and competition to further push the Cloud Service Providers (CSPs) to continually improve their offerings. Get ready, because our toolboxes have just become a &lt;strong&gt;lot bigger&lt;/strong&gt;.&lt;/p&gt;</description>
      <pubDate>Mon, 18 Aug 2008 13:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://www.sleberknight.com/blog/sleberkn/entry/cloud_oriented_architecture_coa</guid>
      <dc:creator>Scott Leberknight</dc:creator>
    </item>
    <item>
      <title>jSilhouette update</title>
      <link>http://www.therichwebexperience.com/blog/andres_almiray/2008/08/jsilhouette_update.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>A couple of days ago there was an announcement on this blog about &lt;a href="http://code.google.com/p/jsilhouette/"&gt;jSilhouette&lt;/a&gt;'s &lt;a href="http://www.jroller.com/aalmiray/entry/announcing_jsilhouette"&gt;0.1 release&lt;/a&gt;, followed by a &lt;a href="http://www.jroller.com/aalmiray/entry/jsilhuette_demo_screenshots_and_code"&gt;comparison&lt;/a&gt; between the geom, scene and jfx demos (regular Java, Project SceneGraph and JavaFx Script each).&lt;br/&gt;&lt;br/&gt;Things have changed a bit. Jacek Furmankiewicz brought to my attention that Project SceneGraph is licensed under GPLv2 (no classpath extension) which means both jsilhouette-scene and jsilhouette-jfx &lt;b&gt;must&lt;/b&gt; use the same licensing scheme. But jsilhouette-geom does not, in fact it has been re-licensed to ASL 2.0, this means that starting with the next release commercial use of jsilhouette-geom is no longer a problem. The commercial usefulness of the remaining modules lies in Sun's will to re-license Project SceneGraph to GPLv2 with classpath extension.&lt;br/&gt;&lt;br/&gt;Some other updates&lt;ul&gt;
&lt;li&gt;Donut shape has been added to all modules. Donuts may be circular or polygonal.&lt;/li&gt;
&lt;li&gt;Default values have been added to some attributes in the jfx module, alleviating the pain of setting each attribute.&lt;/li&gt;
&lt;li&gt;Groovy demo (GraphicsBuilder based) available!&lt;/li&gt;
&lt;/ul&gt;Here is an screenshot on the latest demo app&lt;br/&gt;&lt;br/&gt;&lt;center&gt;&lt;img src="http://www.jroller.com/aalmiray/resource/jsilhouette-demo-groovy.png"/&gt;&lt;/center&gt;&lt;br/&gt;&lt;br/&gt;Nice Nimbus look &amp;amp;feel, you may be thinking that this is the new version of the jfx demo, but it is not! this is the Groovy version (&lt;a href="http://code.google.com/p/jsilhouette/source/browse/trunk/jsilhouette-groovy/src/demo/groovy/org/kordamp/jsilhouette/ShapesDemoGroovy.groovy"&gt;ShapesDemoGroovy.groovy&lt;/a&gt;) &lt;img src="http://www.jroller.com/images/smileys/wink.gif" class="smiley" alt=";-)" title=";-)" /&gt; , the green color is darker in jfx, remember? let's revisit the stats, shall we? &lt;br/&gt;&lt;br/&gt;&lt;center&gt;
&lt;table border="1"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&amp;nbsp;&lt;/th&gt;
&lt;th&gt;geom&lt;/th&gt;
&lt;th&gt;scene&lt;/th&gt;
&lt;th&gt;jfx&lt;/th&gt;
&lt;th&gt;groovy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;&lt;b&gt;LoC&lt;/b&gt;&lt;/td&gt;
&lt;td valign="top"&gt;369&lt;/td&gt;
&lt;td valign="top"&gt;505&lt;/td&gt;
&lt;td valign="top"&gt;619&lt;/td&gt;
&lt;td valign="top"&gt;369&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;&lt;b&gt;Tokens&lt;/b&gt;&lt;/td&gt;
&lt;td valign="top"&gt;1486&lt;/td&gt;
&lt;td valign="top"&gt;1855&lt;/td&gt;
&lt;td valign="top"&gt;2644&lt;/td&gt;
&lt;td valign="top"&gt;2194&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;&lt;b&gt;Source file size (bytes)&lt;/b&gt;&lt;/td&gt;
&lt;td valign="top"&gt;16412&lt;/td&gt;
&lt;td valign="top"&gt;21000&lt;/td&gt;
&lt;td valign="top"&gt;20626&lt;/td&gt;
&lt;td valign="top"&gt;15311&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td valign="top"&gt;&lt;b&gt;Compiled code size (bytes)&lt;/b&gt;&lt;/td&gt;
&lt;td valign="top"&gt;104K&lt;/td&gt;
&lt;td valign="top"&gt;60K&lt;/td&gt;
&lt;td valign="top"&gt;76K&lt;/td&gt;
&lt;td valign="top"&gt;92K&lt;/td&gt;
&lt;/tr&gt;

&lt;/tbody&gt;
&lt;/table&gt;&lt;/center&gt;&lt;br/&gt;The Groovy version beats the JavaFx Script version in almost all categories (the source file is even shorter than the Java2D version) but these numbers do not reflect how small the code can be in each version. For example I discovered that the jfx version has some commas (,) between attribute declaration (which bump the char and file size), I was surprisewd to find out JavaFx Script was happy with them as not even a slight warning is given by the compiler, nice!; the Groovy version harnesses the power of native syntax for Lists and Maps to reduce variable declaration; defaults values are not really used that much in all versions.&lt;br/&gt;&lt;br/&gt;I also mentioned previously that making the second and third demo was quicker once the first one was done, in this case it was no different. The jfx version was copied almost verbatim, added some Groovy sugar here and there (even had to add a MetaClass hack due to how SwingBuilder handles look&amp;amp;feel in the 1.5.6 version (the new one is slicker &lt;img src="http://www.jroller.com/images/smileys/grin.gif" class="smiley" alt=":-D" title=":-D" /&gt; thank &lt;a href="http://twitter.com/shemnon"&gt;@shemnon&lt;/a&gt; for that)). Quick comparison between how the jfx and groovy versions initialize the frame, first the jfx one&lt;br/&gt;&lt;textarea name="srccode" class="jfx:nocontrols:nogutter" cols="80" rows="26"&gt;SwingFrame {
   title: "jSilhouette Shapes (JavaFX)"
   visible: true
   closeAction: function() { System.exit(0); }
   width: 500
   height: 400
   content: BorderPanel {
      center: canvas /*an instance of Canvas*/
      left: GridPanel {
         columns: 1
         rows: 10
         content: [
            SwingButton { text: "Arrow"    action: drawArrows },
            SwingButton { text: "Balloon"  action: drawBalloons },
            SwingButton { text: "Cross"    action: drawCrosses },
            SwingButton { text: "Donut"    action: drawDonuts },
            SwingButton { text: "MultiRoundRectangle" action: drawMultiRoundRectangles },
            SwingButton { text: "Rays"     action: drawRays },
            SwingButton { text: "RegularPolygon" action: drawRegularPolygons },
            SwingButton { text: "RoundPin" action: drawRoundPins },
            SwingButton { text: "Star2"    action: drawStars },
            SwingButton { text: "Triangle" action: drawTriangles }
         ]
      }
   }
}&lt;/textarea&gt;&lt;br/&gt;Where each &lt;code&gt;draw*&lt;/code&gt; function is of the form&lt;br/&gt;&lt;textarea name="srccode" class="jfx:nocontrols:nogutter" cols="80" rows="11"&gt;var canvas: Canvas = Canvas { }

var drawArrows = function():Void {
   canvas.content = [
      Arrow {
         x: 20 y: 20 width: 100 height: 60 rise: 0.5 depth: 0.5 
         fill: Color.RED stroke: Color.BLACK
      },
      ...
   ]
}&lt;/textarea&gt;&lt;br/&gt;Here I'd like to take the opportunity to mention that the function signature must have &lt;code&gt;Void&lt;/code&gt; as its return type otherwise a compilation error will be thrown. If the return type is not specified then it will be the same type of the last evaluated expression, in this case &lt;code&gt;Node[]&lt;/code&gt;, SwingButton expects its &lt;code&gt;action&lt;/code&gt; function to return &lt;code&gt;Void&lt;/code&gt;. I'm sure a tool (like NetBeans' jfx plugin) would have drawn a red underline/popped an error/whatever under the offending code before attempting a full compile on the code by myself, but I went with the "manual" way: Vim + command line compiler, so there, had to be more careful &lt;img src="http://www.jroller.com/images/smileys/tongue.gif" class="smiley" alt=":-P" title=":-P" /&gt;&lt;br/&gt;&lt;br/&gt;Here is the Groovy version&lt;br/&gt;&lt;textarea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="28"&gt;/* Groovy 1.5.6- hack */
SwingBuilder.metaClass.lookAndFeel = { List lafs -&gt;
   for( laf in lafs ) {
      try{ delegate.lookAndFeel(laf); break }
      catch( ex ) {/* ignore */}
   }
}

SwingBuilder.build {
  lookAndFeel( ['nimbus', 'mac', 'gtk', 'metal'] )
  frame( title: 'jSilhouette Shapes (Groovy)', size: [500,400],
         defaultCloseOperation: JFrame.EXIT_ON_CLOSE, show: true,
         locationRelativeTo: null ) {
    borderLayout()
    panel( new GraphicsPanel(), id: 'canvas', constraints: BL.CENTER )
    panel( constraints: BL.WEST) {
      gridLayout( columns: 1, rows: shapes.size() )
      shapes.each { shape, graphicsOperation -&gt;
        button( shape, actionPerformed: { evt -&gt;
          def group = gb.group( borderColor: 'black' )
          group &lt;&lt; gb.antialias(true)           group &lt;&lt; graphicsOperation           canvas.graphicsOperation = group         })       }     }   } }&lt;/textarea&gt;&lt;br/&gt;Where &lt;code&gt;shapes&lt;/code&gt; is a Map initialized like&lt;br/&gt;&lt;textarea name="srccode" class="groovy:nocontrols:nogutter" cols="80" rows="9"&gt;def gb = new GraphicsBuilder()

def shapes = [
   'Arrow': gb.group {
      arrow( x: 20, y: 20, width: 100, height: 60, rise: 0.5, depth: 0.5,
             fill: 'red' )
    },
    ...
]&lt;/textarea&gt;&lt;br/&gt;The Groovy version requires some 'blumbing'&lt;ul&gt;
&lt;li&gt;Fix &lt;code&gt;SwingBuilder.lookAndFeel&lt;/code&gt; to accept a List of L&amp;amp;F identifiers (available in Groovy 1.6.x).&lt;/li&gt;
&lt;li&gt;Set the preferred L&amp;amp;F.&lt;/li&gt;
&lt;li&gt;Tell the frame where it should be located by default (locationRelativeTo: null)&lt;/li&gt;
&lt;/ul&gt;The native syntax for Lists and Maps comes in our aid here. Iterating each entry (String,GraphicsOperation) it is a matter of hooking up the proper values on the button's text and action. Notice that each time a button is clicked a new GraphicsOperation is created (a group) that has a 'global' property applied to all its children (borderColor: 'black') and antialias is turned on. GraphicsPanel is smart enough to know when it should repaint itself (similar to JSGPanel and Canvas). Of course some would say you may iterate over a sequence in the jfx version in order to build the buttons in a loop, sure you can. You could also create a java.util.Map that holds each label and related function, but the code is not as concise as the Groovy one. Assuming hypothetical classes javafx.util.LinkedHashMap and javafx.util.MapEntry&lt;br/&gt;&lt;textarea name="srccode" class="jfx:nocontrols:nogutter" cols="80" rows="17"&gt;var shapes = LinkedHashMap {
   content: [
      MapEntry { key: 'Arrow'
         value : [
            Arrow { ... }, ...
         ]
      },
      ...
   ]
}
...
shapes.eachEntry ( function(key:Object,value:Object):Void {
   var label = key as String;
   var actionFunc = value as Function; // (???)
   var button = SwingButton { text: label, action: actionFunc }
   // insert button in its proper place
})&lt;/textarea&gt;Yup, hypothetical is more like it (my code that is, still have to learn more about JavaFx Script) but you get the idea. Back to jSilhouette, I'd like to have proper javadocs/javafxdocs in place before releasing the next version, so it will take a couple of days more.&lt;br/&gt;&lt;br/&gt;Feedback is always appreciated.</description>
      <pubDate>Mon, 18 Aug 2008 11:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://www.jroller.com/aalmiray/entry/jsilhouette_update</guid>
      <dc:creator>Andres Almiray</dc:creator>
    </item>
    <item>
      <title>Testing Anti-Patterns: Invisible Code</title>
      <link>http://www.therichwebexperience.com/blog/jason_rudolph/2008/08/testing_anti_patterns_invisible_code.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;As we&amp;#8217;ve seen over the last several weeks, it&amp;#8217;s remarkably easy for code to earn the badge of 100% &lt;a href="http://jasonrudolph.com/blog/2008/06/10/a-brief-discussion-of-code-coverage-types/" title="jasonrudolph.com/blog - A Brief Discussion of Code Coverage Types"&gt;test coverage&lt;/a&gt; &lt;em&gt;without&lt;/em&gt; necessarily having a strong test suite.  In &lt;a href="http://jasonrudolph.com/blog/tag/testing-anti-patterns/" title="jasonrudolph.com/blog - Testing Anti-Patterns"&gt;each of those examples&lt;/a&gt;, the coverage analysis tool performed its task flawlessly: it reported exactly which portions of our code were executed as a result of running the tests.  The all-green coverage report showed us that the tests indeed touched all of our code, but it was up to us to acknowledge that simply touching a line of code doesn&amp;#8217;t mean that you&amp;#8217;ve exercised and verified that line of code in a meaningful way.  Some folks interpret this acknowledgement to mean that coverage analysis is meaningless, but that unfortunate conclusion overlooks the real benefit of a coverage report: it&amp;#8217;s not about getting to 100% test coverage and assuming victory, it&amp;#8217;s about highlighting any areas of our codebase that we&amp;#8217;ve forgotten to test entirely.&lt;/p&gt;

&lt;p&gt;As with any tool, to make effective use of coverage analysis, we need to understand its purpose, its capabilities, and its limitations.  In all of the previous examples, we looked at code that was already in the coverage report.  In other words, the coverage tool knew about this code and was able to watch the code and assess its coverage upon completion of the test suite.  But if we&amp;#8217;re using the coverage report to help us find untested code, how do we deal with code that the coverage tool might not be aware of in the first place?&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s start with a sample Rails app that represents the beginnings of an online store.  The project currently contains the following files (as well as some others that I&amp;#8217;ve omitted for the sake of brevity).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[store]$ tree
...
|-- app
|   |-- controllers
|   |   |-- application.rb
|   |   `-- products_controller.rb
|   |-- helpers
|   |   |-- application_helper.rb
|   |   `-- products_helper.rb
|   |-- models
|   |   `-- product.rb
|   `-- views
|       |-- layouts
|       |   `-- products.html.erb
|       `-- products
|           |-- edit.html.erb
|           |-- index.html.erb
|           |-- new.html.erb
|           `-- show.html.erb
|-- config
|   |-- boot.rb
|   |-- database.yml
|   |-- environment.rb
|   |-- environments
|   |   ...
|   |-- initializers
|   |   |-- inflections.rb
|   |   |-- mime_types.rb
|   |   `-- new_rails_defaults.rb
|   `-- routes.rb
|-- db
|   |-- migrate
|   |   `-- 20080810220638_create_products.rb
|   `-- schema.rb
...
|-- lib
|   |-- product_ftp_importer.rb
|   `-- tasks
|   |   |-- data_load.rake
...
|-- test
|   |-- fixtures
|   |   `-- products.yml
|   |-- functional
|   |   `-- products_controller_test.rb
|   |-- integration
|   |-- test_helper.rb
|   `-- unit
|       `-- product_test.rb
...

37 directories, 63 files
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After installing the &lt;a href="http://agilewebdevelopment.com/plugins/rails_rcov" title="Plugins - Rails rcov - Agile Web Development"&gt;rails_rcov plugin&lt;/a&gt;, we can easily produce a coverage report to see where we currently stand.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://jasonrudolph.com/blog/wp-content/uploads/20080819_invisible_code_coverage_report_1.png"&gt;&lt;img src="http://jasonrudolph.com/blog/wp-content/uploads/20080819_invisible_code_coverage_report_1_thumb.png" alt="100% Test Coverage" title="100% Test Coverage - The Whole Story?" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to the coverage report, we&amp;#8217;re not aware of any code that isn&amp;#8217;t touched by at least one test.  But is that really the whole story?  The number of test-related files sure accounts for a small proportion of the overall app.  We can see that we have &lt;code&gt;test/unit/product_test.rb&lt;/code&gt; and &lt;code&gt;test/functional/products_controller_test.rb&lt;/code&gt;, but do those two files really encompass all the developer testing needed for this application?&lt;/p&gt;

&lt;h2&gt;Out of Sight, Out of Mind?&lt;/h2&gt;

&lt;p&gt;What about that mysterious file hanging out in the &lt;code&gt;lib&lt;/code&gt; directory?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[store]$ tree
...
|-- lib
|   |-- product_ftp_importer.rb
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Just judging by the name of the file, that sure &lt;em&gt;sounds&lt;/em&gt; like functionality that deserves testing, but for some reason it&amp;#8217;s not listed in the coverage report.  And if we take another look at the test files listed above, there are no test files that obviously correlate to &lt;code&gt;product_ftp_importer.rb&lt;/code&gt;.  So, how is it that we have 100% coverage?&lt;/p&gt;

&lt;p&gt;In order for code to show up in a coverage report, we need to instruct the coverage tool to assess that file.  The approach for doing so tends to vary from tool to tool.  With &lt;a href="http://eigenclass.org/hiki.rb?rcov" title="eigenclass - rcov: code coverage for Ruby"&gt;rcov&lt;/a&gt;, we first have to tell it which files constitute our test suite (i.e., the files we want rcov to run).  But that alone is not sufficient; we also have to ensure that application files (i.e., the files whose test coverage we want to measure) get &lt;em&gt;loaded&lt;/em&gt; as part of the test suite.  Adding this &lt;code&gt;require&lt;/code&gt; statement anywhere in our test suite is enough to shed some light on the elusive code in &lt;code&gt;product_ftp_importer.rb&lt;/code&gt;.&lt;/p&gt;

&lt;div class="dean_ch" style="white-space: wrap;"&gt;&lt;ol&gt;&lt;li class="li1"&gt;&lt;div class="de1"&gt;&lt;span class="kw3"&gt;require&lt;/span&gt; &lt;span class="kw4"&gt;File&lt;/span&gt;.&lt;span class="me1"&gt;expand_path&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw4"&gt;File&lt;/span&gt;.&lt;span class="me1"&gt;dirname&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="kw2"&gt;__FILE__&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; + &lt;span class="st0"&gt;&amp;quot;/../lib/product_ftp_importer&amp;quot;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;

&lt;p&gt;&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://jasonrudolph.com/blog/wp-content/uploads/20080819_invisible_code_coverage_report_2.png"&gt;&lt;img src="http://jasonrudolph.com/blog/wp-content/uploads/20080819_invisible_code_coverage_report_2_thumb.png" alt="71.7% Test Coverage" title="71.7% Test Coverage - The Whole Story" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s hard to feel good about 45 lines of untested FTP-processing voodoo, so how can we unearth this &lt;strong&gt;invisible code&lt;/strong&gt; as soon as it tries to sneak its way into our app?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensure that your coverage task knows where to find your tests, always place new tests where the coverage task can find them, and use a consistent naming scheme so that a simple file-matching pattern can distinguish test files from non-test files.&lt;/li&gt;
&lt;li&gt;If you&amp;#8217;re using rcov, add a quick script that will crawl your project tree and &lt;code&gt;require&lt;/code&gt; all application files.  Adding individual &lt;code&gt;require&lt;/code&gt; statements one-by-one is not a reasonable solution.  If someone&amp;#8217;s not going to write the test in the first place, they&amp;#8217;re sure as heck not gonna take the time to tell the coverage report about that misdeed.  So, walk the tree and require any Ruby file that you encounter in places where application code is likely to turn up.  At the very least, in a Rails app you should include all subdirectories under &lt;code&gt;app&lt;/code&gt; (being aggressive enough to catch any &lt;em&gt;new&lt;/em&gt; directories that might get added there) and the &lt;code&gt;lib&lt;/code&gt; directory.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;(Not So) Scenic View Ahead&lt;/h2&gt;

&lt;p&gt;View templates have long been a favorite dumping ground for misplaced application logic.  This problem can often go undetected, because view templates fly under the radar of the coverage report.  Most developers know they should minimize the application logic included in the view, but when a deadline&amp;#8217;s looming, the lure of throwing some code in the view &amp;#8220;just this once&amp;#8221; is often hard to resist.  For example, what&amp;#8217;s so wrong with having the view decide whether to display a particular product in the list?&lt;/p&gt;

&lt;div class="dean_ch" style="white-space: wrap;"&gt;&lt;ol&gt;&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;lt;% &lt;span class="kw1"&gt;for&lt;/span&gt; product &lt;span class="kw1"&gt;in&lt;/span&gt; &lt;span class="re1"&gt;@products&lt;/span&gt; %&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;lt;% &lt;span class="kw1"&gt;if&lt;/span&gt; product.&lt;span class="me1"&gt;quantity_in_stock&lt;/span&gt; &amp;gt; &lt;span class="nu0"&gt;0&lt;/span&gt; &amp;amp;&amp;amp; product.&lt;span class="me1"&gt;quantity_in_stock&lt;/span&gt; &amp;gt; product.&lt;span class="me1"&gt;pending_backorder_count&lt;/span&gt; %&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;!&amp;#8211; display purchasable product here &amp;#8211;&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;!&amp;#8211; &amp;#8230; &amp;#8211;&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li2"&gt;&lt;div class="de2"&gt;&amp;nbsp; &amp;lt;% &lt;span class="kw1"&gt;end&lt;/span&gt; %&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;lt;% &lt;span class="kw1"&gt;end&lt;/span&gt; %&amp;gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;

&lt;p&gt;&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;Well, how exactly will we verify that the view is indeed displaying the right products and suppressing the others?  We could manually test each scenario by visually inspecting the resulting UI, and that might be good enough for us to have confidence that the app is doing the right thing as of this moment.  But code has a life of its own, and it will grow and change over time, and we want automated tests to make sure that this page continues to display the correct data even after those inevitable changes.&lt;/p&gt;

&lt;p&gt;So we decide to write tests to verify that we&amp;#8217;re displaying only the right products.  And since this logic is inside our view template, we need to write tests that will render our view template and then dissect the resulting HTML to verify that it contains the products that should be present and that it does not contain the products that should not be present.  But in order to render the HTML, we need to invoke some controller action.  And because that lone &lt;code&gt;if&lt;/code&gt; statement needs at least four different test cases to check the various conditions, we get the joy of doing all that setup and dissection at least four times.  That&amp;#8217;s a big enough pain that it quickly becomes very tempting to let this bit of logic remain untested, remain out of sight of the coverage report, and remain &amp;#8220;good enough.&amp;#8221;&lt;/p&gt;

&lt;p&gt;We can do better than that.  When something&amp;#8217;s too hard to test, we should refactor it until it&amp;#8217;s easy to test. [1]&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re going to need this logic outside of the view anyway, so the sooner we get it into the model the better.  Sure, the view will only display those products that are available for purchase, but we need that logic for server-side validation as well.  Before we process an order, we need to make sure that we still have the product in stock.  If we leave the logic in the view as is, then we&amp;#8217;ll be forced to duplicate that logic elsewhere inside our order-processing code.  There&amp;#8217;s clearly no justification at all for leaving this logic in the view.  &lt;/p&gt;

&lt;div class="dean_ch" style="white-space: wrap;"&gt;&lt;ol&gt;&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;lt;% &lt;span class="kw1"&gt;for&lt;/span&gt; product &lt;span class="kw1"&gt;in&lt;/span&gt; &lt;span class="re1"&gt;@products&lt;/span&gt; %&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;lt;% &lt;span class="kw1"&gt;if&lt;/span&gt; product.&lt;span class="me1"&gt;available_for_purchase&lt;/span&gt;? %&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;!&amp;#8211; display purchasable product here &amp;#8211;&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;!&amp;#8211; &amp;#8230; &amp;#8211;&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li2"&gt;&lt;div class="de2"&gt;&amp;nbsp; &amp;lt;% &lt;span class="kw1"&gt;end&lt;/span&gt; %&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;lt;% &lt;span class="kw1"&gt;end&lt;/span&gt; %&amp;gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;

&lt;p&gt;&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;When we encapsulate this logic in the &lt;code&gt;Product&lt;/code&gt; class itself, we can test that logic in &lt;em&gt;isolation&lt;/em&gt;, without any dependencies on controllers, and without the need for fragile HTML-parsing to verify the result.  Once we perform this refactoring, unit testing the &lt;code&gt;#available_for_purchase?&lt;/code&gt; method becomes trivial, &lt;em&gt;and&lt;/em&gt; we can refer to that method wherever necessary without unnecessary duplication.&lt;/p&gt;

&lt;p&gt;Better still, if we know that we only want to display the products that are available for purchase, we can ensure that our controller provides &lt;em&gt;only&lt;/em&gt; those products to the view in the first place.  With this approach, our view then enjoys the pleasant simplicity of just displaying the list of products.&lt;/p&gt;

&lt;div class="dean_ch" style="white-space: wrap;"&gt;&lt;ol&gt;&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;lt;% &lt;span class="kw1"&gt;for&lt;/span&gt; product &lt;span class="kw1"&gt;in&lt;/span&gt; &lt;span class="re1"&gt;@products&lt;/span&gt; %&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;lt;!&amp;#8211; display purchasable product here &amp;#8211;&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;lt;!&amp;#8211; &amp;#8230; &amp;#8211;&amp;gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;lt;% &lt;span class="kw1"&gt;end&lt;/span&gt; %&amp;gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;

&lt;p&gt;&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;The coverage report isn&amp;#8217;t going to alert us to business logic lurking in our view templates.  It&amp;#8217;s up to us to keep our views from becoming &lt;a href="http://www.youtube.com/watch?v=ku3QkWcPSEw" title="YouTube - RailsEnvy MVC Public Service Announcement #3 - Keeping Views Stupid"&gt;too smart for their own good&lt;/a&gt;, and it&amp;#8217;s up to peer code reviews to keep us honest.&lt;/p&gt;

&lt;h2&gt;Raking for Buried Treasure&lt;/h2&gt;

&lt;p&gt;While it&amp;#8217;s tempting to let our views acquire too much business logic, there&amp;#8217;s usually an obvious place to &lt;em&gt;move&lt;/em&gt; that logic once we realize the error of our ways.  (In Rails, you&amp;#8217;ll typically relocate that logic to a model class or to a helper, either of which are easily tested in isolation.)  But what about the other parts of our application where untested code tends to hide out and germinate?&lt;/p&gt;

&lt;p&gt;Perhaps we have some code that only needs to run at application start-up.  In Rails, we&amp;#8217;re talking about code in &lt;code&gt;environment.rb&lt;/code&gt; or &lt;code&gt;config/initializers&lt;/code&gt;.  In Grails, &lt;code&gt;BootStrap.groovy&lt;/code&gt; is home to this logic.  In either case (or in most any other framework), we&amp;#8217;re not likely to see those start-up &amp;#8220;scripts&amp;#8221; included in the coverage report, nor is there a natural and obvious place for testing any complex code that we may need to include in the start-up process.  We&amp;#8217;re used to testing models and controllers and helpers and mailers, but where does this start-up logic fit into the mix?&lt;/p&gt;

&lt;p&gt;Data migration suffers from a similar problem.  Rails migrations are great for creating and dropping tables, adding and removing columns, etc., but sometimes we need to do more than just alter the schema; sometimes we want to push &lt;em&gt;data&lt;/em&gt; around as well.  Schema transformations are essentially declarative code, and really don&amp;#8217;t warrant anything beyond visual verification of the results.  But when it comes time to migrate 10 million records from some legacy database into our hip new application, chances are we&amp;#8217;re not just talking about simple declarations anymore.  What&amp;#8217;s the worst that could happen though?  This code only has to run once.  And who wants to write a bunch of tests for code that we&amp;#8217;re only gonna run once and then throw away?  And once again, there&amp;#8217;s no obvious place for us to add tests for this kind of data conversion functionality in the first place.  Surely a simple Rake task will suffice.&lt;/p&gt;

&lt;div class="dean_ch" style="white-space: wrap;"&gt;&lt;ol&gt;&lt;li class="li1"&gt;&lt;div class="de1"&gt;namespace &lt;span class="re3"&gt;:db&lt;/span&gt; &lt;span class="kw1"&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; namespace &lt;span class="re3"&gt;:load&lt;/span&gt; &lt;span class="kw1"&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; desc &lt;span class="st0"&gt;&amp;#8216;Load products from csv&amp;#8217;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; task &lt;span class="re3"&gt;:products&lt;/span&gt; &lt;span class="kw1"&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li2"&gt;&lt;div class="de2"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw3"&gt;require&lt;/span&gt; &lt;span class="st0"&gt;&amp;#8216;csv&amp;#8217;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw3"&gt;require&lt;/span&gt; &lt;span class="st0"&gt;&amp;#8216;environment&amp;#8217;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; CSV.&lt;span class="kw3"&gt;open&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;&amp;quot;#{RAILS_ROOT}/db/input/csv/product-catalog/products.csv&amp;quot;&lt;/span&gt;, &lt;span class="st0"&gt;&amp;#8216;r&amp;#8217;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;.&lt;span class="me1"&gt;each_with_index&lt;/span&gt; &lt;span class="kw1"&gt;do&lt;/span&gt; |row, idx|&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw1"&gt;next&lt;/span&gt; &lt;span class="kw1"&gt;if&lt;/span&gt; row&lt;span class="br0"&gt;&amp;#91;&lt;/span&gt;&lt;span class="nu0"&gt;0&lt;/span&gt;&lt;span class="br0"&gt;&amp;#93;&lt;/span&gt; == &lt;span class="st0"&gt;&amp;quot;Product&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw3"&gt;p&lt;/span&gt; = Product.&lt;span class="me1"&gt;find_or_create_by_name&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;row&lt;span class="br0"&gt;&amp;#91;&lt;/span&gt;&lt;span class="nu0"&gt;0&lt;/span&gt;&lt;span class="br0"&gt;&amp;#93;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li2"&gt;&lt;div class="de2"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw3"&gt;p&lt;/span&gt;.&lt;span class="me1"&gt;description&lt;/span&gt; = e.&lt;span class="me1"&gt;purpose&lt;/span&gt; = row&lt;span class="br0"&gt;&amp;#91;&lt;/span&gt;&lt;span class="nu0"&gt;5&lt;/span&gt;&lt;span class="br0"&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw3"&gt;p&lt;/span&gt;.&lt;span class="me1"&gt;sku&lt;/span&gt; = row&lt;span class="br0"&gt;&amp;#91;&lt;/span&gt;&lt;span class="nu0"&gt;3&lt;/span&gt;&lt;span class="br0"&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw3"&gt;p&lt;/span&gt;.&lt;span class="me1"&gt;price&lt;/span&gt; = row&lt;span class="br0"&gt;&amp;#91;&lt;/span&gt;&lt;span class="nu0"&gt;4&lt;/span&gt;&lt;span class="br0"&gt;&amp;#93;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw3"&gt;p&lt;/span&gt;.&lt;span class="me1"&gt;save&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; shipping_options = row&lt;span class="br0"&gt;&amp;#91;&lt;/span&gt;&lt;span class="nu0"&gt;1&lt;/span&gt;&lt;span class="br0"&gt;&amp;#93;&lt;/span&gt;.&lt;span class="kw3"&gt;split&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;&amp;quot;|&amp;quot;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li2"&gt;&lt;div class="de2"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; shipping_options.&lt;span class="me1"&gt;each&lt;/span&gt; &lt;span class="kw1"&gt;do&lt;/span&gt; |o|&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw3"&gt;p&lt;/span&gt;.&lt;span class="me1"&gt;shipping_options&lt;/span&gt; &amp;lt;&amp;lt; ShippingOption.&lt;span class="me1"&gt;find_by_name&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;o&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw1"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; vendors = row&lt;span class="br0"&gt;&amp;#91;&lt;/span&gt;&lt;span class="nu0"&gt;2&lt;/span&gt;&lt;span class="br0"&gt;&amp;#93;&lt;/span&gt;.&lt;span class="kw3"&gt;split&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;&amp;quot;|&amp;quot;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li2"&gt;&lt;div class="de2"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; vendors.&lt;span class="me1"&gt;each&lt;/span&gt; &lt;span class="kw1"&gt;do&lt;/span&gt; |v|&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw3"&gt;p&lt;/span&gt;.&lt;span class="me1"&gt;vendors&lt;/span&gt; &amp;lt;&amp;lt; Vendor.&lt;span class="me1"&gt;find_by_number&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;v&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt; &lt;span class="kw1"&gt;unless&lt;/span&gt; v.&lt;span class="me1"&gt;downcase&lt;/span&gt; == &lt;span class="st0"&gt;&amp;#8216;none&amp;#8217;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw1"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw1"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &lt;span class="kw1"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li2"&gt;&lt;div class="de2"&gt;&amp;nbsp; &lt;span class="kw1"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&lt;span class="kw1"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;

&lt;p&gt;&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;Indeed, a &lt;em&gt;simple&lt;/em&gt; Rake task will suffice, but that&amp;#8217;s certainly not what we&amp;#8217;re looking at above.  While we &lt;em&gt;could&lt;/em&gt; write tests for this logic in its current state, doing so is unnecessarily difficult.  We&amp;#8217;d be restricted to solely black box tests.  To test each individual decision point, we&amp;#8217;re forced to also construct a new file holding the appropriate dataset, run the Rake task, and then inspect the state of the data in the database.  For &lt;em&gt;every&lt;/em&gt; decision point.  &lt;/p&gt;

&lt;h2&gt;Scripts Can Be Classy Too&lt;/h2&gt;

&lt;p&gt;We shouldn&amp;#8217;t have to also test the ability to read a file (i.e., line 7) just so that we can test the ability to populate a vendor based on a given vendor number (i.e., line 21).  For sure, we want one good end-to-end test to verify that all the cogs are working together correctly.  But if that&amp;#8217;s our sole testing strategy, then we&amp;#8217;ve made testing just painful enough that it probably won&amp;#8217;t happen at all.  &lt;/p&gt;

&lt;p&gt;Whether we&amp;#8217;re talking about hard-to-test code in start-up scripts, hard-to-test code in migration scripts, or hard-to-test code hiding out in the handful of other custom scripts that an application tends to accumulate over time, the answer&amp;#8217;s the same in each case.  Just because the coverage report doesn&amp;#8217;t see this hidden code doesn&amp;#8217;t mean that it&amp;#8217;s not worth testing.  And just because our framework-of-choice might not provide a convention for testing this logic, that doesn&amp;#8217;t mean that we should just punt.&lt;/p&gt;

&lt;p&gt;When something&amp;#8217;s too hard to test, we should refactor it until it&amp;#8217;s easy to test.  &lt;/p&gt;

&lt;div class="dean_ch" style="white-space: wrap;"&gt;&lt;ol&gt;&lt;li class="li1"&gt;&lt;div class="de1"&gt;namespace &lt;span class="re3"&gt;:db&lt;/span&gt; &lt;span class="kw1"&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; namespace &lt;span class="re3"&gt;:load&lt;/span&gt; &lt;span class="kw1"&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; desc &lt;span class="st0"&gt;&amp;#8216;Load products from csv&amp;#8217;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; task &lt;span class="re3"&gt;:products&lt;/span&gt; &lt;span class="kw1"&gt;do&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li2"&gt;&lt;div class="de2"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="kw3"&gt;require&lt;/span&gt; &lt;span class="st0"&gt;&amp;#8216;environment&amp;#8217;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; importer = ProductCsvImporter.&lt;span class="me1"&gt;new&lt;/span&gt;&lt;span class="br0"&gt;&amp;#40;&lt;/span&gt;&lt;span class="st0"&gt;&amp;quot;#{RAILS_ROOT}/db/input/csv/product-catalog/products.csv&amp;quot;&lt;/span&gt;&lt;span class="br0"&gt;&amp;#41;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; importer.&lt;span class="me1"&gt;run&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &amp;nbsp; &lt;span class="kw1"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;div class="de1"&gt;&amp;nbsp; &lt;span class="kw1"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li class="li2"&gt;&lt;div class="de2"&gt;&lt;span class="kw1"&gt;end&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;

&lt;p&gt;&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;In the case of this Rake task, and in each of the cases discussed above, by simply moving the logic out of the script and into a proper class (or module), the testing strategy goes from clumsy at best to downright obvious.  We no longer need to invoke the whole script in order to verify the particular unit of functionality that we want to test.  Instead, we test that functionality in isolation, and allow the script to resume its trivial role of merely calling our well-tested class.&lt;/p&gt;

&lt;h2&gt;Use It Wisely&lt;/h2&gt;

&lt;p&gt;In order to make effective use of coverage analysis, it&amp;#8217;s important for us to understand what a coverage report is telling us &lt;em&gt;and&lt;/em&gt; what it&amp;#8217;s incapable of telling us.  Tools are imperfect, but we can adopt strategies to make sure we&amp;#8217;re reaping the maximum benefit from the tools we choose to employ.  With good naming conventions and an agreed-upon application structure, we can easily configure an intelligent solution that allows the coverage tool to automatically pick up any new source files that we want included in the report.  With a commitment to testing all application logic - regardless of whether it&amp;#8217;s needed in a model, a view, a script, etc. - we&amp;#8217;ll extract the code that would otherwise be buried in a dark corner of our app.  We&amp;#8217;ll benefit from the ability to test it in isolation, and we&amp;#8217;ll allow the coverage tool to assess that code, giving us a more realistic and complete view of our codebase.&lt;/p&gt;

&lt;p&gt;Invisible code is hidden technical debt, but the sooner you expose it, the sooner you can start to pay it down.&lt;/p&gt;

&lt;h2&gt;Notes&lt;/h2&gt;

&lt;p&gt;[1]  In past posts in this series, I&amp;#8217;ve advocated test-driven development (TDD) as means for combatting the various testing anti-patterns. Invisible code is no exception.  While this post is geared more toward &lt;em&gt;uncovering&lt;/em&gt; invisible code so that we can give it the testing it deserves, developing test-first is the best bet for &lt;em&gt;preventing&lt;/em&gt; invisible code in the first place.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This &lt;a href="http://jasonrudolph.com/blog/tag/testing-anti-patterns/" title="jasonrudolph.com/blog - Testing Anti-Patterns"&gt;series&lt;/a&gt; is taken from the &lt;a href="http://blog.thinkrelevance.com/2008/5/23/how-to-fail-with-100-test-coverage" title="Relevance Blog : How To Fail With 100% Test Coverage"&gt;How To Fail With 100% Test Coverage&lt;/a&gt; talk. Check the &lt;a href="http://thinkrelevance.com/events" title="Relevance: Events"&gt;schedule&lt;/a&gt; for a talk near you.&lt;/p&gt;

&lt;p&gt;&amp;#8211;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks&lt;/strong&gt; to &lt;a href="http://muness.blogspot.com/" title="Mundane Essays"&gt;Muness Alrubaie&lt;/a&gt;, &lt;a href="http://thinkrelevance.com/about/justin-gehtland" title="Relevance: Justin Gehtland"&gt;Justin Gehtland&lt;/a&gt;, and &lt;a href="http://gigavolt.net/blog/" title="Potential Differences"&gt;Greg Vaughn&lt;/a&gt; for reading drafts of this post.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/jasonrudolph?a=KYLlIk"&gt;&lt;img src="http://feeds.feedburner.com/~f/jasonrudolph?i=KYLlIk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jasonrudolph?a=L29AxK"&gt;&lt;img src="http://feeds.feedburner.com/~f/jasonrudolph?i=L29AxK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jasonrudolph?a=zydDRk"&gt;&lt;img src="http://feeds.feedburner.com/~f/jasonrudolph?i=zydDRk" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/jasonrudolph/~4/367967922" height="1" width="1"/&gt;</description>
      <pubDate>Mon, 18 Aug 2008 08:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://jasonrudolph.com/blog/?p=191</guid>
      <dc:creator>Jason Rudolph</dc:creator>
    </item>
    <item>
      <title>Agile 2008 - Sanjiv Augustine - The effect of Agile Projects on Middle Management</title>
      <link>http://www.therichwebexperience.com/blog/robert_payne/2008/08/agile_2008__sanjiv_augustine__the_effect_of_agile_projects_on_middle_management.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>I talk with Sanjiv Augustine about his work with Agile Project/Portfolio Management and the Middle Managers that execute projects within organizations.  Sanjiv and I have worked together for years on client engagements, training and publishing.  More recently we have been working to kick off Agile Philanthropy.  LitheSpeed was the sponsor for the LiveAid Stage this year and you will be seeing more of Sanjiv and LitheSpeed in the years to come here on the Agile Toolkit Podcast.&#xD;
&lt;br /&gt;&#xD;
&lt;br /&gt;Enjoy.&#xD;
&lt;br /&gt;&#xD;
&lt;br /&gt;-bob payne</description>
      <pubDate>Sun, 17 Aug 2008 16:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://agiletoolkit.libsyn.com/index.php?post_id=369243#</guid>
      <dc:creator>Bob Payne</dc:creator>
    </item>
    <item>
      <title>eRubyCon 2008 Day 2</title>
      <link>http://www.therichwebexperience.com/blog/josh_holmes/2008/08/erubycon_2008_day_2.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;&#xD;
Yesterday I wrote a write up of &lt;a href="http://www.joshholmes.com/2008/08/15/eRubyCon2008Day1.aspx"&gt;eRubyCon&#xD;
2008 Day 1&lt;/a&gt;. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a title="Erubycon" href="http://www.flickr.com/photos/86613980@N00/2770067004/"&gt;&#xD;
            &lt;img class="flickr" alt="Erubycon" hspace="5" src="http://static.flickr.com/3263/2770067004_23cfa89154_m.jpg" align="left" vspace="5" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt; -&#xD;
Charles Nutter started up with JRuby. I'm always impressed by people that are able&#xD;
to make their weekend project their full time job. I was further impressed that Charles&#xD;
was up with the rest of the speakers until closer to 4am than any of us should really&#xD;
admit, drinking really good scotch and solving the world's problems. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Charles talked about the JVM and Java as both a problem and a great asset. There are&#xD;
a lot of people that look at the J in JRuby and automatically associate it with all&#xD;
of the things that they don't like about Java. Charles answer is to separate the JVM&#xD;
from the Java language. He did a really good job of talking about the things that&#xD;
the JVM brings over the standard Ruby runtimes such as world class garbage collection,&#xD;
memory compaction, thread handling and the like. He did a number of really compelling&#xD;
demos around threading in particular. One of the things that he said here is that&#xD;
JRuby and IronRuby are really the only Ruby implementations that are able to do native&#xD;
threads because they are the only ones that are built on production quality VMs that&#xD;
handle that native threading for them. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.joshholmes.com/content/binary/WindowsLiveWriter/eRubyCon2008Day2_8792/0816080915_2.jpg"&gt;&#xD;
            &lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 5px; border-right-width: 0px" height="184" alt="0816080915" src="http://www.joshholmes.com/content/binary/WindowsLiveWriter/eRubyCon2008Day2_8792/0816080915_thumb.jpg" width="244" align="right" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;One&#xD;
of the great quotes was "We write a lot of Java. So you don't have to..." - Charles&#xD;
Nutter&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
After setting the stage, he pulled up a long list of features and said - "There's&#xD;
way too much for me to cover in the time left - what do you want to see?". that was&#xD;
fun. The first suggestion that he showed was 2D graphics that flashed a bunch of little&#xD;
balls around the screen. It was even responsive to voice commands. The second suggestion&#xD;
was to show Rails running on JRuby. He showed that they are running Rails on Ruby&#xD;
1.8.6 (java). Next he brought up image_voodoo to do more 2D libraries. Lastly, he&#xD;
showed "java_inline" which allows you to inline Java code similar to the Ruby_inline&#xD;
which allows you to inline C right in your Ruby code. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
  - Evan Light came up next. Unfortunately I was putting out a few small fires.&#xD;
Fortunately Michael Lettere wrote up a small write up so that I could include it here. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Evan Light hates EJBs.&lt;br&gt;&#xD;
EJB encourages difficult to test idioms, private fields, private static final fields.&lt;br&gt;&#xD;
Nice demo code "public class DeepThought" &amp;lt;--- How do you test that?&lt;br&gt;&#xD;
You COULD shoot the guy who wrote it, but don't do that.&lt;br&gt;&#xD;
Very good use of humor, engaged the audience. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a title="Stuart Halloway, Neal Ford" href="http://www.flickr.com/photos/86613980@N00/2770050696/"&gt;&#xD;
            &lt;img class="flickr" alt="Stuart Halloway, Neal Ford" hspace="5" src="http://static.flickr.com/3294/2770050696_e08e4b02bf_m.jpg" align="right" vspace="5" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt; -&#xD;
The lunch keynote was Neal Ford. Neil Ford is an amazing speaker. What’s cool about&#xD;
him is that every time I see him speaker, I wonder how he could get any better. And&#xD;
then he does. Today’s talk was about complexity. One of the core concepts that he&#xD;
talked about is the idea of Language Lockdown. It’s when language writers put in features&#xD;
to protect people from themselves and cut down on the stupid things that you can do.&#xD;
The idea is that if you do that the lower end (read cheaper) developers will still&#xD;
be productive. “What they are trying to do is strap a rocket to the ass of a turtle.&#xD;
What they are actually doing is putting chains on the rabbits than can go fast.”&lt;br&gt;&#xD;
The problem with that take though is two fold. First, it is not a linear line between&#xD;
the top developers and the lower end developers. What that means is that on the curve,&#xD;
a highly productive programmer will get done in one day what it will take an average&#xD;
developer more than a week to do and the weak developer a month or more. To point&#xD;
out the second issue, Neal quoted one of my other favorite speaker - “Bad developers&#xD;
will move heaven and earth to do the wrong thing” - Glenn Vanderburgh&lt;br&gt;&#xD;
One of the huge questions that he put out there is “How much of your enterprise software&#xD;
simple services accidental complexity?”. It’s a great question. &#xD;
&lt;br&gt;&#xD;
As he was wrapping up, he left us with the thought that “Courage is contagious. Cowardice&#xD;
is infectious”. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a title="Stuart Halloway" href="http://www.flickr.com/photos/86613980@N00/2769207061/"&gt;&#xD;
            &lt;img class="flickr" alt="Stuart Halloway" hspace="5" src="http://static.flickr.com/3097/2769207061_9732021f41_m.jpg" align="left" vspace="5" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;-&#xD;
Following Neal was Stuart Halloway again. He was talking this time about how one can&#xD;
fail with 100% test coverage. It’s an interesting topic because for so many people,&#xD;
100% test coverage is the holy grail that they shoot for. The first thing that he&#xD;
pointed out is that you might cover all the lines, but not all the branches so it&#xD;
depends on how you measure things to get to 100% coverage. The second thing that he&#xD;
points out is that you can cover all the code, but not all the corner cases. The example&#xD;
that he used is testing if a value is above or below $25.00 but forgetting $25.00&#xD;
even. Oops. Then you can start writing way too much code and too much complexity into&#xD;
your tests. Now you need to test your tests and you’ve taken too much time writing&#xD;
them. Then he talked about the “ugly mirror” where the test is really a mirror of&#xD;
the code where you’re covering the line but using the code that you are trying to&#xD;
test while testing – oh dear I have a headache. This is where he says that you are&#xD;
allowed to write literals in your tests. &#xD;
&lt;br&gt;&#xD;
Neal Ford piped in - “It’s ok for your test to be moist, not drenched”. &#xD;
&lt;br&gt;&#xD;
The next topic was slow tests and how dangerous they are. The short version of the&#xD;
issue is that if the unit tests don’t run in under 1 second, developers are not going&#xD;
to run them. Functional tests should run in under 2 minutes. If they don’t, then factor&#xD;
them so that they run on different schedules, parallelize them on different machines&#xD;
to get the normal check-in process back under the 2 minute mark if possible. &#xD;
&lt;br&gt;&#xD;
The last type of fail that he talked about is shallow tests. The quote that he referenced&#xD;
is “No automated test suite can ever replace exploratory testing.” - Jay Fields. The&#xD;
goal is that once the unit and functional testing passes, that people will put themselves&#xD;
in the clients seat and go spelunking and try out a bunch of stuff. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a title="Joe O'Brien, Chris Nelson, Jim Weirich" href="http://www.flickr.com/photos/86613980@N00/2770056920/"&gt;&#xD;
            &lt;img class="flickr" alt="Joe O'Brien, Chris Nelson, Jim Weirich" hspace="5" src="http://static.flickr.com/3031/2770056920_5f56bd462b_m.jpg" align="right" vspace="5" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt; -&#xD;
The next talk was a very unique idea called “Dialogue Concerning the Two Chief Modeling&#xD;
Systems”. They wrote a play! The guys from EdgeCase, Joe O’Brien, Jim Weirich and&#xD;
Chris Nelson, acted out a normal project for them. They started out on twitter talking&#xD;
about the new project that they just landed. Then they actually started with the early&#xD;
on meetings that they have. Joe played the cowboy dev lead who insists that it’s a&#xD;
“simple rails app” and decides to do a data first model. Chris played clueless nub&#xD;
and Jim played the seasoned architect that was concerned about requirements analysis,&#xD;
separation of layers and behavior driven models. Joe, ready to start slamming code&#xD;
out, starts pairing with Chris. The first thing that they tackle is a simple calendar&#xD;
event. Then they have to schedule reoccuring events. Joe, the cowboy, just decides&#xD;
to replicate the events in order to do the reoccurence. The next requirement is rescheduling&#xD;
the reoccuring meetings.... Oops. They have neatly coded themselves into a corner&#xD;
and start hacking out a solution. At that point, Chris decided to take a walk and&#xD;
went to see what Jim thought of it all. Jim started writing out CRC cards and started&#xD;
thinking about higher level ideas, bringing in light-weight design patterns around&#xD;
temporal expressions from Martin Fowler and so on. Jim, the architect, is blithely&#xD;
ignoring “implementation details” such as where to store the data and performance.&#xD;
When performance sucked – they went back to the drawing board. Jim and Joe had to&#xD;
eventually come together. Of course the answer was to write a DSL... :)&lt;br&gt;&#xD;
Great talk. The good news is that Neal Ford is following them so there won’t be a&#xD;
let down as we end the day... &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
- The last talk of the day was Neal Ford talking about Design Patterns in Ruby. One&#xD;
of the things that he pointed out fairly early on is that the Design Patterns book,&#xD;
even according to one of the authors ( Vlissides), should have been called “Making&#xD;
C++ Suck Less”. Even the Smalltalk that’s in the book was really C++ written in Smalltalk&#xD;
syntax. He covered a number of different patterns including the Iterator and the Interpretor&#xD;
pattern. There were a number of circumstances where he pointed out that the issues&#xD;
addressed by the pattern were addressed by the Ruby language. For example, the interpretor&#xD;
pattern’s intent is really addressed by DLSs which are dead easy to implement in Ruby.&#xD;
The only problem with this session is that it’s at the end of the day and my brain&#xD;
is a little mush at this point. &#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.joshholmes.com/aggbug.ashx?id=4ad4f70f-2af2-4e1b-884f-0ea2f6afd606"&gt;&lt;/img&gt;&#xD;
      &lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/JoshHolmes?a=YlcMnK"&gt;&lt;img src="http://feeds.feedburner.com/~f/JoshHolmes?i=YlcMnK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/JoshHolmes?a=5w10ak"&gt;&lt;img src="http://feeds.feedburner.com/~f/JoshHolmes?i=5w10ak" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/JoshHolmes?a=PhIiAk"&gt;&lt;img src="http://feeds.feedburner.com/~f/JoshHolmes?i=PhIiAk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/JoshHolmes?a=kgHzdK"&gt;&lt;img src="http://feeds.feedburner.com/~f/JoshHolmes?i=kgHzdK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/JoshHolmes?a=QkInqk"&gt;&lt;img src="http://feeds.feedburner.com/~f/JoshHolmes?i=QkInqk" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JoshHolmes/~4/367267181" height="1" width="1"/&gt;</description>
      <pubDate>Sun, 17 Aug 2008 13:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://www.joshholmes.com/PermaLink,guid,4ad4f70f-2af2-4e1b-884f-0ea2f6afd606.aspx</guid>
      <dc:creator>Josh Holmes</dc:creator>
    </item>
    <item>
      <title>Dan Pritchett on Availability</title>
      <link>http://www.therichwebexperience.com/blog/michael_nygard/2008/08/dan_pritchett_on_availability.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;&lt;a href="http://www.linkedin.com/in/driveawedge"&gt;Dan Pritchett&lt;/a&gt; is a man after my own heart. His &lt;a href="http://www.addsimplicity.com/adding_simplicity_an_engi/2008/08/availability-en.html"&gt;latest post&lt;/a&gt; talks about the path to availability enlightenment. The obvious path--reliable components and vendor-supported commercial software--leads only to tears.&lt;/p&gt;&lt;p&gt;You can begin on the path to enlightenment when you set aside dreams of perfect software running on perfect hardware, talking over perfect networks. Instead, embrace the reality of fallible components. Don't design around them, design for them. &lt;/p&gt;&lt;p&gt;How do you design for failure-prone components? That's what most of &lt;a href="http://www.amazon.com/gp/product/0978739213?ie=UTF8&amp;amp;tag=michaelnygard-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0978739213"&gt;Release It!&lt;/a&gt; is all about. &lt;br /&gt;&lt;/p&gt;</description>
      <pubDate>Sun, 17 Aug 2008 11:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://www.michaelnygard.com/blog/2008/08/dan_pritchett_on_availability.html</guid>
      <dc:creator>Michael Nygard</dc:creator>
    </item>
    <item>
      <title>Storytelling</title>
      <link>http://www.therichwebexperience.com/blog/alex_miller/2008/08/storytelling.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;I&amp;#8217;ve been taking a lot of walks lately and listening to podcasts, and I&amp;#8217;ve become kind of addicted to podcasts oriented around story-telling.  Perhaps the best is &lt;a href="http://thislife.org"&gt;This American Life with Ira Glass&lt;/a&gt;.  This &lt;a href="http://npr.org"&gt;NPR&lt;/a&gt; series every week takes a theme and tells a series of stories around it.  They do an amazing job of putting together a riveting show every week.  You can subscribe on iTunes but to reduce bandwidth they only provide the most recent episode.&lt;/p&gt;
&lt;p&gt;Last week&amp;#8217;s episode &lt;a href="http://thislife.org/Radio_Episode.aspx?episode=361"&gt;&amp;#8220;Fear of Sleep&amp;#8221;&lt;/a&gt; featured a number of good stories, but the one that stood out for me was &lt;a href="http://www.birbigs.com"&gt;Mike Birbiglia&amp;#8217;s&lt;/a&gt; stories about him acting out his dreams.  For one, it&amp;#8217;s really funny, as only extended personal stories can be.  For another, the presentation is just pitch-perfect - the pauses, the word choice, the pacing, etc.  Of course, the comedian background should make this no surprise.&lt;/p&gt;
&lt;p&gt;Of course, Mike&amp;#8217;s performance was actually taken from a show at &lt;a href="http://www.themoth.org/"&gt;The Moth&lt;/a&gt;, which I&amp;#8217;ve never heard of before.  Apparently, they do storytelling shows in both New York and LA.  Even better, they have a &lt;a href="http://www.themoth.org/podcast"&gt;podcast&lt;/a&gt;. :)  So, now I&amp;#8217;ve been working my way through their podcast and enjoying it immensely.&lt;/p&gt;
&lt;p&gt;Anyone else have any favorite story podcasts to share?
&lt;/p&gt;</description>
      <pubDate>Sun, 17 Aug 2008 08:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://tech.puredanger.com/2008/08/16/storytelling/</guid>
      <dc:creator>Alex Miller</dc:creator>
    </item>
    <item>
      <title>Ajax4jsf/RichFaces presentations at JSFOne</title>
      <link>http://www.therichwebexperience.com/blog/max_katz/2008/08/ajax4jsf_richfaces_presentations_at_jsfone.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;Besides my &lt;a href="http://www.jsfone.com/show_session_view.jsp?presentationId=11080&amp;#038;showId=166" target="new"&gt;presentation&lt;/a&gt;, there are a two other talks covering Ajax4jsf/RichFaces at JSFOne:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dan Allen, &lt;a href="http://www.jsfone.com/show_session_view.jsp?presentationId=11072&amp;#038;showId=166" target="new"&gt;Building JSF components with the Ajax4jsf CDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;David Geary, &lt;a href="http://www.jsfone.com/show_session_view.jsp?presentationId=11086&amp;#038;showId=166" target="new"&gt;Using Ajax4jsf&lt;/li&gt;
&lt;p&gt;&lt;/a&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="http://mkblog.exadel.com/?p=125"&gt;Read&lt;/a&gt; more about Ajax4jsf and RichFaces names&lt;/p&gt;</description>
      <pubDate>Sat, 16 Aug 2008 16:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://mkblog.exadel.com/?p=124</guid>
      <dc:creator>Max Katz</dc:creator>
    </item>
    <item>
      <title>Framework Design Guidelines 2nd Edition Available today on Rough Cuts</title>
      <link>http://www.therichwebexperience.com/blog/brad_abrams/2008/08/framework_design_guidelines_2nd_edition_available_today_on_rough_cuts.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;&lt;img title="Framework Design Guidelines: Conventions, Idioms, and Patterns for Reuseable .NET Libraries" height="113" alt="Framework Design Guidelines: Conventions, Idioms, and Patterns for Reuseable .NET Libraries" src="http://safari.informit.com/images/9780321545671/9780321545671_xs.jpg" width="86" align="right" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/kcwalina/"&gt;Krys&lt;/a&gt; and I just finished writing the update to the framework &lt;a href="http://blogs.msdn.com/kcwalina/archive/2008/01/03/FrameworkDesignGuidelines2ndEdition.aspx"&gt;design guidelines&lt;/a&gt; and you are can already get the &amp;quot;Rough Cuts&amp;quot;!&amp;#160;&amp;#160; That is right, in today's instant information world why wait for copy editing, printing and shipping time!&amp;#160; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://safari.informit.com/9780321545671"&gt;Framework Design Guidelines: Conventions, Idioms, and Patterns for Reuseable .NET Libraries&lt;/a&gt; on Rough Cuts&lt;/p&gt;  &lt;p&gt;Expect it in on Amazon and in book stores late this year.&amp;#160; &lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8871635" width="1" height="1"&gt;</description>
      <pubDate>Sat, 16 Aug 2008 13:00:01 CDT</pubDate>
      <guid isPermaLink="true">91d46819-8472-40ad-a661-2c78acb4018c:8871635</guid>
      <dc:creator>Brad Abrams</dc:creator>
    </item>
    <item>
      <title>Getting a list of Grails plugins programmatically</title>
      <link>http://www.therichwebexperience.com/blog/kenneth_kousen/2008/08/getting_a_list_of_grails_plugins_programmatically.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;div class='snap_preview'&gt;&lt;br /&gt;&lt;p&gt;In September, I&amp;#8217;m very happy to be giving a couple of presentations at the &lt;a href="http://www.nofluffjuststuff.com/conference/boston/2008/09/index.html"&gt;No Fluff, Just Stuff&lt;/a&gt; conference in the Boston area.  One of my presentations is a review of the various available Grails plugins.  To prepare for that, I thought I&amp;#8217;d create a Grails application that acted as a survey, so people could rate the plugins they like.&lt;/p&gt;
&lt;p&gt;One task is to get a list of available Grails plugins.  I wanted to do that programmatically, too, because I&amp;#8217;d like to update the list automatically using the &lt;a href="http://www.grails.org/Quartz+plugin"&gt;Quartz plugin&lt;/a&gt; (of course).&lt;/p&gt;
&lt;p&gt;How do you get a list of available plugins?  My first thought was to do the HTML equivalent of screen scraping at the &lt;a href="http://grails.org/Plugins"&gt;main plugin site&lt;/a&gt;, http://grails.org/Plugins .  At that site everything is nicely divided into categories, along with links to descriptions and more.&lt;/p&gt;
&lt;p&gt;Screen scraping HTML is not fun, though.  I&amp;#8217;ve done it before, when necessary, but it&amp;#8217;s not very robust and tends to run into problems.  Many of those problems have to do with the fact that HTML is a mess.  Most web sites are filled with HTML that isn&amp;#8217;t even well-formed, making processing it programmatically a real pain.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.manning.com/koenig/"&gt;GinA&lt;/a&gt;, however, mentioned &lt;a href="http://httpunit.sourceforge.net/index.html"&gt;HTTPUnit&lt;/a&gt; as an easy way to access a web page.  Since it&amp;#8217;s a regular old Java library, that meant I could use it with Groovy.  Therefore, my first attempt was:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
import com.meterware.httpunit.WebConversation

def baseUrl = 'http://grails.org/Plugins'

def wc = new WebConversation()
def resp = wc.getResponse(baseUrl)
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Unfortunately, I&amp;#8217;m already in trouble even at that point.  If I run that, I get a massive exception stack trace with shows that the included Neko DOM parser choked on the embedded &lt;a href="http://prototypejs.org"&gt;prototype&lt;/a&gt; JavaScript library.&lt;/p&gt;
&lt;p&gt;While I was debating what to do about that (I really didn&amp;#8217;t want to just open the URL, get the text, and start having Fun With Regular Expressions), I noticed a blog posting &lt;a href="http://www.grailsdeveloper.com/blog/2008/07/how-to-install-plugin-faster-without-get-list-of-available-plugins-first/"&gt;here&lt;/a&gt;, from someone named Isak Rickyanto, from Jakarta, Indonesia.&lt;/p&gt;
&lt;p&gt;(A Java developer from Java.  How cool is that?  Or should I say, &amp;#8220;how Groovy?&amp;#8221; :))&lt;/p&gt;
&lt;p&gt;Isak points out that there is a list of Grails plugins at http://svn.codehaus.org/grails-plugins/ .  As a Subversion repository listing, it&amp;#8217;s not full of JavaScript.  Even better, every plugin is listed as a simple link in an unordered list.&lt;/p&gt;
&lt;p&gt;I therefore modified my script to look like this:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
def baseUrl = 'http://svn.codehaus.org/grails-plugins/'

def wc = new WebConversation()
def resp = wc.getResponse(baseUrl)
def pluginNames = []
resp.links.each { link -&amp;gt;
    if (link.text =~ /^grails/) {
        def name = link.text - 'grails-' - '/'
        pluginNames &amp;lt;&amp;lt; name
    }
}
println pluginNames
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Here I&amp;#8217;m taking advantage of the fact that the &lt;code&gt;WebResponse&lt;/code&gt; class (returned from &lt;code&gt;getResponse(url)&lt;/code&gt;) has a method called &lt;code&gt;getLinks()&lt;/code&gt;.  Since there was one link that had the name &amp;#8220;&lt;code&gt;.plugin-meta&lt;/code&gt;&amp;#8220;, I decided to use a trivial regular expression to filter down to the links definitely associated with plugins.  The &lt;code&gt;WebLink.getText()&lt;/code&gt; method then returned the text of the link, with gave values of the form&lt;/p&gt;
&lt;p&gt;&lt;code&gt;grails-XXX/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;for each plugin.  One of the things I love about Groovy is that I can then just subtract out the characters I don&amp;#8217;t want, which is how I added the actual plugin names to an array.&lt;/p&gt;
&lt;p&gt;Unfortunately, while that&amp;#8217;s part of what I want, that isn&amp;#8217;t everything I want.  I&amp;#8217;d like the version numbers and the descriptions, too, if possible.  I could go digging into the various directories and look for patterns, but a different idea occurred to me.&lt;/p&gt;
&lt;p&gt;I finally remembered that the way I normally find out what plugins are available is to run the&lt;/p&gt;
&lt;p&gt;&lt;code&gt;grails list-plugins&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;command and look at the output.  You&amp;#8217;ve probably seen it.  It gives an output like&lt;/p&gt;
&lt;pre&gt;
Welcome to Grails 1.0.3 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: c:\grails-1.0.3

Base Directory: c:\
Note: No plugin scripts found
Running script c:\grails-1.0.3\scripts\ListPlugins.groovy
Environment set to development

Plug-ins available in the Grails repository are listed below:
-------------------------------------------------------------

acegi               &amp;lt;0.3&amp;gt;            --  Grails Spring Security 2.0 Plugin
aop                 &amp;lt;no releases&amp;gt;    --  No description available
audit-logging       &amp;lt;0.4&amp;gt;            --  adds hibernate audit logging and onChange event handlers ...
authentication      &amp;lt;1.0&amp;gt;            --  Simple, extensible authentication services with signup ....
autorest            &amp;lt;no releases&amp;gt;    --  No description available
&lt;/pre&gt;
&lt;p&gt;etc.  So if I could get this output, I could break each line into the pieces I want with simple String processing.&lt;/p&gt;
&lt;p&gt;How can I do that?  In the spirit of reducing it to a problem already solved, I realized I just wanted to execute that command programmatically and capture the output.  One way to do that is to take advantage of Groovy&amp;#8217;s ability to run command line scripts (GinA covers this, of course, but so does Scott Davis&amp;#8217;s most excellent &lt;a href="http://www.pragprog.com/titles/sdgrvr/groovy-recipes"&gt;Groovy Recipes &lt;/a&gt;book).  Here&amp;#8217;s the result:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
def names = []
def out = "cmd /c grails list-plugins".execute().text
out.split("\n").each { line -&amp;gt;
    if (line =~ /&amp;lt;.*&amp;gt;/) {
        def spaceSplit = line.split()
        def tokenSplit = line.split('--')
        def name = spaceSplit[0]
        def version = spaceSplit[1] - '&amp;lt;' - '&amp;gt;'
        def description = tokenSplit[-1].trim()
        names &amp;lt;&amp;lt; name
    }
}
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Basically I&amp;#8217;m executing the &lt;code&gt;list-plugins&lt;/code&gt; command at a command prompt under Windows (sorry, but that&amp;#8217;s still my life), splitting the output at the carriage returns (for some odd reason, using &lt;code&gt;eachLine&lt;/code&gt; directly kept giving me errors), and processing each line individually.  The lines listing plugins are the ones with version numbers in angle brackets (like &lt;code&gt;&amp;lt;0.3&amp;gt;&lt;/code&gt;), and the descriptions came after two dashes.  It seemed easiest to just split the lines both ways in order to get the data I wanted.&lt;/p&gt;
&lt;p&gt;I ran this script and the other script together to see if I got the same output.  Here&amp;#8217;s the result:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
println "From 'grails list-plugins': " + names
println "From svn repo: " + pluginNames
println "Difference: " + (pluginNames - names)

From 'grails list-plugins': ["acegi", "aop", "audit-logging", ..., "yui"]
From svn repo: ["acegi", "aop", "audit-logging", ..., "yui"]
Difference: ["extended-data-binding"]
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Why the difference? From the list-plugins output, here&amp;#8217;s the line for &amp;#8220;&lt;code&gt;extended-data-binding&lt;/code&gt;&amp;#8220;:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
ext-ui              &amp;lt;no releases&amp;gt;    --  No description available
extended-data-binding&amp;lt;0.2&amp;gt;            --  This plugin extends Grails' data binding ...
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;Yup, the name ran into the version number format.  Sigh.  Of course, the other problem with this is that at the moment it&amp;#8217;s dependent on my own system configuration (Windows, with the grails command in the path), which can&amp;#8217;t be a good thing.&lt;/p&gt;
&lt;p&gt;Finally, after all this work, I suddenly realized that I already have the script used to list the plugins.  As with all the other Grails commands, it&amp;#8217;s a Gant script in the &lt;code&gt;&amp;lt;GRAILS_HOME&amp;gt;\scripts&lt;/code&gt; directory called, obviously enough, &lt;code&gt;ListPlugins.groovy&lt;/code&gt;.  According to the documentation at the top, it was written by Sergey Nebolsin for version 0.5.5.&lt;/p&gt;
&lt;p&gt;What Sergey does is to go to a slightly different URL and then parse the results as XML.  His script accesses&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DEFAULT_PLUGIN_DIST = "http://plugins.grails.org"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;instead of the SVN repo location listed above, but if you go there, they look remarkably alike.  I wouldn&amp;#8217;t be surprised if http://plugins.grails.org is simply an alias for the SVN repository.&lt;/p&gt;
&lt;p&gt;Note that the script also creates a cached version of the plugin list, called &lt;code&gt;plugins-list.xml&lt;/code&gt;, which is kept in the&lt;/p&gt;
&lt;p&gt;&lt;code&gt;"${userHome}/.grails/${grailsVersion}/plugins/"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;directory.  That&amp;#8217;s completely understandable, but a lousy location on a Windows box.  I never go to my so-called &amp;#8220;user home&amp;#8221; directory, so I would never occur to me to look there for information.&lt;/p&gt;
&lt;p&gt;His script checks to see if that file is missing or out of date.  If it&amp;#8217;s necessary to update it, he opens a URL and starts processing:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
def remoteRevision = 0
new URL(DEFAULT_PLUGIN_DIST).withReader { Reader reader -&amp;gt;
    def line = reader.readLine()

...

    // for each plugin directory under Grails Plugins SVN in form of 'grails-*'
    while(line=reader.readLine()) {
        line.eachMatch(/&amp;lt;li&amp;gt;&amp;lt;a href="grails-(.+?)"&amp;gt;/) {
            // extract plugin name
           def pluginName = it[1][0..-2]

           // collect information about plugin
           buildPluginInfo(pluginsList, pluginName)
        }
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;etc.&lt;/p&gt;
&lt;p&gt;So, in effect, he&amp;#8217;s screen scraping the SVN page; he&amp;#8217;s just doing a better job of it than I was.&lt;/p&gt;
&lt;p&gt;Incidentally, the line in his script that lead to my parsing problems is on line 86:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;plugins &amp;lt;&amp;lt; "${pluginLine.padRight(20, " ")}${versionLine.padRight(16, " ")} --  ${title}"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I could bump up the padding by one, or learn to parse the output better. &lt;img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /&gt;  I expect the &amp;#8220;right&amp;#8221; answer, though, is to do what Sergey did, pretty much.  Still, if all I have to do is add a little padding, it&amp;#8217;s awfully tempting to just &amp;#8220;reuse&amp;#8221; Sergey&amp;#8217;s existing script.&lt;/p&gt;
&lt;p&gt;In an upcoming post, I&amp;#8217;ll talk about how I used the RichUI plugin to apply a &amp;#8220;star rating&amp;#8221; to each entry so that people could vote.  I don&amp;#8217;t have the site ready yet, though.  I&amp;#8217;ll be sure to mention it when I do.&lt;/p&gt;
&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/kousenit.wordpress.com/130/" /&gt; &lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/kousenit.wordpress.com/130/" /&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/kousenit.wordpress.com/130/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/kousenit.wordpress.com/130/" /&gt;&lt;/a&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/kousenit.wordpress.com/130/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/kousenit.wordpress.com/130/" /&gt;&lt;/a&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/kousenit.wordpress.com/130/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/kousenit.wordpress.com/130/" /&gt;&lt;/a&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/kousenit.wordpress.com/130/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/kousenit.wordpress.com/130/" /&gt;&lt;/a&gt; &lt;a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/kousenit.wordpress.com/130/"&gt;&lt;img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/kousenit.wordpress.com/130/" /&gt;&lt;/a&gt; &lt;img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=kousenit.wordpress.com&amp;blog=186706&amp;post=130&amp;subd=kousenit&amp;ref=&amp;feed=1" /&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 16 Aug 2008 11:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://kousenit.wordpress.com/?p=130</guid>
      <dc:creator>Kenneth Kousen</dc:creator>
    </item>
    <item>
      <title>eRubyCon 2008 Day 1</title>
      <link>http://www.therichwebexperience.com/blog/josh_holmes/2008/08/erubycon_2008_day_1.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;
&lt;a href="http://www.joshholmes.com/content/binary/WindowsLiveWriter/eRubyCon2008Day1_B71A/image_4.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 5px; border-right-width: 0px" height="137" alt="image" src="http://www.joshholmes.com/content/binary/WindowsLiveWriter/eRubyCon2008Day1_B71A/image_thumb_1.png" width="297" align="right" border="0"&gt;&lt;/a&gt; I'm
sitting here at the second &lt;a href="http://www.erubycon.com/"&gt;Enterprise Ruby Conference
(eRubyCon)&lt;/a&gt;. There's a couple of fun and interesting things that have happened
this year. 
&lt;/p&gt;
&lt;p&gt;
One of them that's exciting for me is that the whole event is being hosted at the &lt;a href="http://www.erubycon.com/venue.html"&gt;Microsoft
facilities in Columbus, OH&lt;/a&gt;. &lt;a href="http://www.objo.com"&gt;Joe O'Brien&lt;/a&gt; was
looking for a facility so I offered up the office since we can get that for free.
There are some minor facility issues, such as the internet access is fairly limited
due to the Microsoft security policies. We got that mostly sorted by renting a number
of cell card based routers from &lt;a href="http://www.ibox2go.com"&gt;iBox2Go&lt;/a&gt;. It's
not a perfect solution because we're at about double the recommended number of users
per router. That's caused network to be a touch spotty but it's better than non-existent. 
&lt;/p&gt;
&lt;p&gt;
Another thing that's a ton of fun is that we've doubled the number of attendees. The
conference room here at the Microsoft office is FULL. Tomorrow I'll show some pictures
from the conference room. It's really cool to see. 
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.joshholmes.com/content/binary/WindowsLiveWriter/eRubyCon2008Day1_B71A/0815081326_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 5px; border-right-width: 0px" height="184" alt="0815081326" src="http://www.joshholmes.com/content/binary/WindowsLiveWriter/eRubyCon2008Day1_B71A/0815081326_thumb.jpg" width="244" align="left" border="0"&gt;&lt;/a&gt;The
whole event is going very well. Joe has been plagued with speakers having travel issues
and the like. For example, Stu Halloway was supposed to do a lunch time keynote but
was thrown off as his plane had mechanical issues. The great news is that this is
an Agile conference and everyone is used to requirements changing mid-project and
Joe was able to shuffle the speakers. 
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Image:Bob_at_Easel.jpg"&gt;&lt;img style="margin: 5px" height="284" alt="" src="http://upload.wikimedia.org/wikipedia/en/thumb/7/70/Bob_at_Easel.jpg/220px-Bob_at_Easel.jpg" width="220" align="right" border="0"&gt;&lt;/a&gt;-
First up was &lt;a href="http://evilmartini.com/"&gt;Randall Thomas&lt;/a&gt; from the &lt;a href="http://engineyard.com/"&gt;Engine
Yard&lt;/a&gt;. He was talking about ETL (Extract, Transform, Load). He did a masterful
job of making that important topic interesting and fun. It's a fundamental topic but
even Randall equated it to &lt;a href="http://en.wikipedia.org/wiki/Bob_Ross"&gt;Bob Ross&lt;/a&gt; painting
trees and it was tough to keep people awake talking about the best possible way to
make one string into two and two into one... 
&lt;/p&gt;
&lt;p&gt;
- Next was &lt;a href="http://blog.engineyard.com/"&gt;Tom Mornini&lt;/a&gt;. I wish I had been
able to stick around for this talk. He talked heavily about Vertebra, Scalability
and Accountability. 
&lt;/p&gt;
&lt;p&gt;
- &lt;a href="http://chi.mp"&gt;Anthony Eden&lt;/a&gt; followed Tom with a session on Identity
Management. It was interesting to hear his take on OpenID, InformationCard, SAML and
how Ruby works with those. The good news for Ruby is that it does really well with
and is leading the way with OpenID. The bad news is that the things that are done
inside of an enterprise are a little less prevalent in the Ruby at the moment. It
was a great tutorial on the state of 
&lt;/p&gt;
&lt;div style="float: left; width: 159px; height: 160px"&gt;&lt;a title="Code Generation in Action: Jack Herrington: Books" href="http://www.amazon.com/exec/obidos/ASIN/1930110979/joshholmes-20"&gt;&lt;img src="http://images.amazon.com/images/P/1930110979.01.MZZZZZZZ.jpg" align="left" border="0" &gt;&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;
- &lt;a href="http://gilesbowkett.blogspot.com/"&gt;Giles Bowkett&lt;/a&gt; talked about Meta-Programming
vs. Code Generation. He had a fun and deep tirade on something called Monkeypatching. 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
"A &lt;b&gt;monkey patch&lt;/b&gt; (also spelled &lt;b&gt;monkey-patch&lt;/b&gt;, &lt;b&gt;MonkeyPatch&lt;/b&gt;) is a
way to extend or modify the &lt;a href="http://en.wikipedia.org/wiki/Runtime"&gt;runtime&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Code_(computer_programming)"&gt;code&lt;/a&gt; of
dynamic languages (e.g. &lt;a href="http://en.wikipedia.org/wiki/Smalltalk"&gt;Smalltalk&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Javascript_programming_language"&gt;Javascript&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Objective-C"&gt;Objective-C&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Ruby_programming_language"&gt;Ruby&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Perl_programming_language"&gt;Perl&lt;/a&gt;,
and &lt;a href="http://en.wikipedia.org/wiki/Python_(programming_language)"&gt;Python&lt;/a&gt;)
without altering the original &lt;a href="http://en.wikipedia.org/wiki/Source_code"&gt;source
code&lt;/a&gt;." - &lt;a title="http://en.wikipedia.org/wiki/Monkey_patch" href="http://en.wikipedia.org/wiki/Monkey_patch"&gt;http://en.wikipedia.org/wiki/Monkey_patch&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
This is meta-programming at it's finest. He then went on to talk about meta-monkey-patching
or meta meta programming... Somewhere in there I got a headache. That's about the
time that he brought it back to Code Generation. My favorite quote, other than "Here's
a completely gratuitous picture of Jessica Albert" (which did come with a gratuitous
picture of Jessica Albert...) " "Should I hire a programmer or should I just write
one?". He gave an example of a past job at NY Times where he left after he wrote a
"mini-giles". That's a code generator that did much of what he had been doing until
he wrote the generator. The "mini-giles" meme has really taken off since then and
has been worked into a ton of the talks and conversations... 
&lt;p&gt;
- &lt;a href="http://blog.thinkrelevance.com/"&gt;Stuart Halloway&lt;/a&gt; followed Giles with
a keynote called "Ending Legacy Code in Our Lifetime". He had one of the better starts
that I've ever heard - "Legacy Code is like Porn. I know it when I see it. It's ubiquitous
on the internet. And like all porn, it's ultimately unsatisfying". (At least he has
it on good authority that porn is ultimately unsatisfying). One of the things that
Stuart points out is that code can be broken down to Ceremony and Essence. The Essence
is what you actually want to get done. The Ceremony is the stuff that you have to
do in order to have the Essence work. For example, if you have gone from "New" on
an object to writing factories - the reality is the factory is Ceremony. End of the
day, all you really wanted is an object. 
&lt;/p&gt;
&lt;p&gt;
Another great quote from Stuart was "Ceremony leads to fear. Fear leads to anger.
Anger leads to pain. Pain leads to Ceremony." The goal, according to Stuart, is to
have as little ceremony as possible and have every line of code contribute to the
Essence. And right now, Ruby is the closest answer as it's got a fairly high Essence
to Ceremony ratio. 
&lt;/p&gt;
&lt;p&gt;
His talk was chock full of great quotes - "What authority authorizes this in the Ruby
world? - ME - and I'm Right". It was full enough of great quotes that there's a &lt;a href="http://search.twitter.com/search?q=&amp;amp;ands=%40stuarthalloway&amp;amp;phrase=&amp;amp;ors=&amp;amp;nots=&amp;amp;tag=&amp;amp;lang=all&amp;amp;from=&amp;amp;to=&amp;amp;ref=&amp;amp;near=&amp;amp;within=15&amp;amp;units=mi&amp;amp;since=2008-08-15&amp;amp;until=2008-08-16&amp;amp;rpp=15"&gt;Stu
Halloway Quote Tracker&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
- Brian Sam-Bodden, always a great speaker, closed out the day with Refactoring with
JRuby. He talked about the core of refactoring is having a great suite of tests. One
of my favorite quotes from him was "Since I'm a Java consultant, I have a lot of work
to do...". 
&lt;/p&gt;
&lt;p&gt;
Overall, it was a great day. I really enjoyed catching up with a lot of the guys that
I don't get to see at the .NET community events. I'm hoping that most of these guys
will be at &lt;a href="http://www.codemash.org"&gt;CodeMash&lt;/a&gt; cause that will give me
2 times a year to hang out.&amp;nbsp; 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.joshholmes.com/aggbug.ashx?id=7aa2f2e1-a749-481c-af08-d87f587d7d5f" /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/JoshHolmes?a=WJhnpK"&gt;&lt;img src="http://feeds.feedburner.com/~f/JoshHolmes?i=WJhnpK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/JoshHolmes?a=Bl8uok"&gt;&lt;img src="http://feeds.feedburner.com/~f/JoshHolmes?i=Bl8uok" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/JoshHolmes?a=sn9EJk"&gt;&lt;img src="http://feeds.feedburner.com/~f/JoshHolmes?i=sn9EJk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/JoshHolmes?a=sVJjyK"&gt;&lt;img src="http://feeds.feedburner.com/~f/JoshHolmes?i=sVJjyK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/JoshHolmes?a=LvQbsk"&gt;&lt;img src="http://feeds.feedburner.com/~f/JoshHolmes?i=LvQbsk" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/JoshHolmes/~4/365995051" height="1" width="1"/&gt;</description>
      <pubDate>Sat, 16 Aug 2008 08:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://www.joshholmes.com/PermaLink,guid,7aa2f2e1-a749-481c-af08-d87f587d7d5f.aspx</guid>
      <dc:creator>Josh Holmes</dc:creator>
    </item>
    <item>
      <title>Ajax4jsf and RichFaces - historical perspective</title>
      <link>http://www.therichwebexperience.com/blog/max_katz/2008/08/ajax4jsf_and_richfaces__historical_perspective.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;The following is a snippet from my upcoming book which talks about Ajax4jsf and RichFaces names and historical perspective. &lt;/p&gt;
&lt;p&gt;It’s a good idea to give you some background on how RichFaces was born and also tell you what Ajax4jsf is. Ajax4jsf has its roots in RichFaces. The Ajax4jsf framework was created and designed by Alexander Smirnov. In early 2005, he was looking to add a “hot” new technology along with the associated experience to his resume. Roughly at the same time, the concept of Ajax was being established by Jesse James Garrett. Meanwhile, JSF was starting to pick up steam. Alexander figured why not just merge the two, so it would be easy to have Ajax functionality within a JSF application. He figured this would be an excellent addition to his resume. He started the project on sourcforge.net and called it Telamon (taken from the Shakespeare play, Anthony and Cleopatra) and Ajax4jsf was born. &lt;/p&gt;
&lt;p&gt;In the fall of that same year, Alexander joined Exadel and continued to develop the framework. Alexander’s goal was to create a tool that was easy to use and that could be used with any existing JSF component libraries. The first version of what would become Ajax4jsf was released in March 2006. It wasn’t quite a standalone thing, yet. Rather, it was part of a product called Exadel RichFaces. Later in the same year, RichFaces was split off and the Ajax4jsf framework was born. While RichFaces provided out-of-the-box components or what’s called a component-centric Ajax approach (components that do everything you need), Ajax4jsf provided what’s called page-wide Ajax support. You as a developer specify what parts of the page should be processed on the server after some client side user actions and what parts should be rendered back (rendering is happening on the server and then partial DOM updating on the client) after processing. &lt;/p&gt;
&lt;p&gt;Ajax4jsf became an open source project hosted on Java.net while RichFaces became a commercial JSF component library. Fast-forward to March 2007. JBoss and Exadel forged a partnership where Ajax4jsf and RichFaces would now be under the JBoss umbrella and be called JBoss Ajax4jsf and JBoss RichFaces. RichFaces would now also be open source and free. In September 2007, JBoss and Exadel decided to recombine Ajax4jsf and RichFaces under the RichFaces name. It made sense as both libraries were now free and open source. Having just one product solved many version and compatibility issues that existed before, such as which version of Ajax4jsf works with what version of RichFaces?  While today you will still see an a4j namespace used, the product is now called JBoss RichFaces. &lt;/p&gt;</description>
      <pubDate>Fri, 15 Aug 2008 16:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://mkblog.exadel.com/?p=125</guid>
      <dc:creator>Max Katz</dc:creator>
    </item>
    <item>
      <title>Is Your Product Development Half-Actions?</title>
      <link>http://www.therichwebexperience.com/blog/johanna_rothman/2008/08/is_your_product_development_half_actions_.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;Via &lt;a href="http://blog.jackvinson.com" target="_blank"&gt;Jack Vinson&lt;/a&gt;, I found this gem: &lt;a href="http://poder.dk/2008/08/05/stop-doing-half-actions/" target="_blank"&gt;Stop doing half-actions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of you who are separating your developers from your testers? You are doing half-actions. Separating the writers from the developers and testers? Half actions there, too. Even when you define architecture and implement across the architecture, instead of by feature, that&amp;#8217;s a half-action. A half-action means you have technical debt and will have to get back to that area of the product.&lt;/p&gt;
&lt;p&gt;Silos encourage half-actions (or third-actions or sixth-actions). Defining the architecture and implementing across it encourages half-actions. Create a cross-functional product development team. Have them finish one feature at a time. That&amp;#8217;s a full action.&lt;/p&gt;
&lt;div id="adb-tooltip" style="z-index: 1000; position: absolute; display: none; left: 34px; top: -47px;"&gt;
&lt;div style="border: 5px solid #c4dae8; margin: 0px; text-transform: uppercase; font-family: arial; font-style: normal; font-variant: normal; font-weight: bold; font-size: 11px; font-size-adjust: none; font-stretch: normal; -x-system-font: none; line-height: 13px; background-color: white; color: #333333;"&gt;
&lt;div style="border: 1px solid #78b3d9; padding: 5px; text-align: left;"&gt;
&lt;div&gt;Person&lt;span style="color: #006699;"&gt; Jack Vinson&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-transform: none; color: #999999; line-height: 14px;"&gt;Right click for SmartMenu shortcuts&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=FlotQK"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=FlotQK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=05QBdK"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=05QBdK" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=bmyKHk"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=bmyKHk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=riTA3k"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=riTA3k" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=cKd00K"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=cKd00K" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/ManagingProductDevelopment?a=T8pjsK"&gt;&lt;img src="http://feeds.feedburner.com/~f/ManagingProductDevelopment?i=T8pjsK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ManagingProductDevelopment/~4/365791372" height="1" width="1"/&gt;</description>
      <pubDate>Fri, 15 Aug 2008 13:00:01 CDT</pubDate>
      <guid isPermaLink="true">http://jrothman.com/blog/mpd/?p=8474</guid>
      <dc:creator>Johanna Rothman</dc:creator>
    </item>
    <item>
      <title>The Never-Ending Debate of Specialist v. Generalist</title>
      <link>http://www.therichwebexperience.com/blog/ted_neward/2008/08/the_never_ending_debate_of_specialist_v_generalist.html?utm_source=blogitem&amp;utm_medium=rss&amp;utm_campaign=blogrss</link>
      <description>&lt;p&gt;
Another DZone newsletter crosses my Inbox, and again I feel compelled to comment.
Not so much in the uber-aggressive style of my previous attempt, since I find myself
more on the fence on this one, but because I think it's a worthwhile debate and worth
calling out.
&lt;/p&gt;
&lt;p&gt;
The article in question is "5 Reasons Why You Don't Want A Jack-of-all-Trades Developer",
by Rebecca Murphey. In it, she talks about the all-too-common want-ad description
that appears on job sites and mailing lists:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
I've spent the last couple of weeks trolling Craigslist and have been shocked at the
number of ads I've found that seem to be looking for an entire engineering team rolled
up into a single person. Descriptions like this aren't at all uncommon: &lt;blockquote&gt; 
&lt;p&gt;
Candidates must have 5 years experience defining and developing data driven web sites
and have solid experience with ASP.NET, HTML, XML, JavaScript, CSS, Flash, SQL, and
optimizing graphics for web use. The candidate must also have project management skills
and be able to balance multiple, dynamic, and sometimes conflicting priorities. This
position is an integral part of executing our web strategy and must have excellent
interpersonal and communication skills.
&lt;/p&gt;
&lt;/blockquote&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Her disdain for this practice is the focus of the rest of the article:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
Now I don't know about you, but if I were building a house, I wouldn't want an architect
doing the work of a carpenter, or the foundation guy doing the work of an electrician.
But ads like the one above are suggesting that a single person can actually do all
of these things, and the simple fact is that these are fundamentally different skills.
The foundation guy may build a solid base, but put him in charge of wiring the house
and the whole thing could, well, burn down. When it comes to staffing a web project
or product, the principle isn't all that different -- nor is the consequence.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
I'll admit, when I got to this point in the article, I was fully ready to start the
argument right here and now--developers &lt;em&gt;have&lt;/em&gt; to have a well-rounded collection
of skills, since anecdotal evidence suggests that trying to go the route of programming
specialization (along the lines of medical specialization) isn't going to work out,
particularly given the shortage of programmers in the industry right now to begin
with. But she goes on to make an interesting point:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
The thing is, the more you know, the more you find out you don't know. A year ago
I'd have told you I could write PHP/MySQL applications, and do the front-end too;
now that I've seen what it means to be truly skilled at the back-end side of things,
I realize the most accurate thing I can say is that I understand PHP applications
and how they relate to my front-end development efforts. To say that I can write them
myself is to diminish the good work that truly skilled PHP/MySQL developers are doing,
just as I get a little bent when a back-end developer thinks they can do my job.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
She really caught me eye (and interest) with that first statement, because it echoes
something Bjarne Stroustrup told me almost 15 years ago, in an email reply sent back
to me (in response to my rather audacious cold-contact email inquiry about the costs
and benefits of writing a book): "The more you know, the more you know you don't know".
What I think also caught my eye--and, I admit it, earned respect--was her admission
that she maybe isn't as good at something as she thought she was before. This kind
of reflective admission is a good thing (and missing far too much from our industry,
IMHO), because it leads not only to better job placements for us as well as the companies
that want to hire us, but also because the more honest we can be about our own skills,
the more we can focus efforts on learning what needs to be learned in order to grow.
&lt;/p&gt;
&lt;p&gt;
She then turns to her list of 5 reasons, phrased more as a list of suggestions to
companies seeking to hire programming talent; my comments are in italics:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
So to all of those companies who are writing ads seeking one magical person to fill
all of their needs, I offer a few caveats before you post your next Craigslist ad: 
&lt;p&gt;
1. If you're seeking a single person with all of these skills, make sure you have
the technical expertise to determine whether a person's skills match their resume.
Outsource a tech interview if you need to. Any developer can tell horror stories about
inept predecessors, but when a front-end developer like myself can read PHP and think
it's appalling, that tells me someone didn't do a very good job of vetting and got
stuck with a programmer who couldn't deliver on his stated skills. 
&lt;p&gt;
&lt;em&gt;(T: I cannot stress this enough--the technical interview process practiced at
most companies is a complete sham and travesty, and usually only succeeds in making
sure the company doesn't hire a serial killer, would-be terrorist, or financially
destitute freeway-underpass resident. I seriously think most companies should outsource
the technical interview process entirely.)&lt;/em&gt; 
&lt;p&gt;
2. A single source for all of these skills is a single point of failure on multiple
fronts. Think long and hard about what it will mean to your project if the person
you hire falls short in some aspect(s), and about the mistakes that will have to be
cleaned up when you get around to hiring specialized people. I have spent countless
days cleaning up after back-end developers who didn't understand the nuances and power
of CSS, or the difference between a div, a paragraph, a list item, and a span. Really. 
&lt;p&gt;
&lt;em&gt;(T: I'm not as much concerned about the single point of failure argument here,
to be honest. Developers will always have "edges" to what they know, and companies
will constantly push developers to that edge for various reasons, most of which seem
to be financial--"Why pay two people to do what one person can do?" is a really compelling
argument to the CFO, particularly when measured against an unquantifiable, namely
the quality of the project.)&lt;/em&gt; 
&lt;p&gt;
3. Writing efficient SQL is different from efficiently producing web-optimized graphics.
Administering a server is different from troubleshooting cross-browser issues. Trust
me. All are integral to the performance and growth of your site, and so you're right
to want them all -- just not from the same person. Expecting quality results in every
area from the same person goes back to the foundation guy doing the wiring. You're
playing with fire. 
&lt;p&gt;
&lt;em&gt;(T: True, but let's be honest about something here. It's not so much that the
company wants to play with fire, or that the company has a manual entitled "Running
a Dilbert Company" that says somewhere inside it, "Thou shouldst never hire more than
one person to run the IT department", but that the company is dealing with limited
budgets and headcount. If you only have room for one head under the budget, you want
the maximum for that one head. And please don't tell me how wrong that practice of
headcount really is--you're preaching to the choir on that one. The people you want
to preach to are the Jack Welches of the world, who apparently aren't listening to
us very much.)&lt;/em&gt; 
&lt;p&gt;
4. Asking for a laundry list of skills may end up deterring the candidates who will
be best able to fill your actual need. Be precise in your ad: about the position's
title and description, about the level of skill you're expecting in the various areas,
about what's nice to have and what's imperative. If you're looking to fill more than
one position, write more than one ad; if you don't know exactly what you want, try
harder to figure it out before you click the publish button. 
&lt;p&gt;
&lt;em&gt;(T: Asking people to think before publishing? Heresy! Truthfully, I don't think
it's a question of not knowing what they want, it's more trying to find what they
want. I've seen how some of these same job ads get generated, and it's usually because
a programmer on the team has left, and they had some degree of skill in all of those
areas. What the company wants, then, is somebody who can step into exactly what that
individual was doing before they handed in their resignation, but ads like, "Candidate
should look at Joe Smith's resume on Dice.com (http://...) and have exactly that same
skill set. Being named Joe Smith a desirable 'plus', since then we won't have to have
the sysadmins create a new login handle for you." won't attract much attention. Frankly,
what I've found most companies want is to just not lose the programmer in the first
place.)&lt;/em&gt; 
&lt;p&gt;
5. If you really do think you want one person to do the task of an entire engineering
team, prepare yourself to get someone who is OK at a bunch of things and not particularly
good at any of them. Again: the more you know, the more you find out you don't know.
I regularly team with a talented back-end developer who knows better than to try to
do my job, and I know better than to try to do his. Anyone who represents themselves
as being a master of front-to-back web development may very well have no idea just
how much they don't know, and could end up imperiling your product or project -- front
to back -- as a result. 
&lt;p&gt;
&lt;em&gt;(T: Or be prepared to pay a lot of money for somebody who is an expert at all
of those things, or be prepared to spend a lot of time and money growing somebody
into that role. Sometimes the exact right thing to do is have one person do it all,
but usually it's cheaper to have a small team work together.)&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
(On a side note, I find it amusing that she seems to consider PHP a back-end skill,
but I don't want to sound harsh doing so--that's just a matter of perspective, I suppose.
(I can just imagine the guffaws from the mainframe guys when I talk about EJB, message-queue
and Spring systems being "back-end", too.) To me, the whole "web" thing is front-end
stuff, whether you're the one generating the HTML from your PHP or servlet/JSP or
ASP.NET server-side engine, or you're the one generating the CSS and graphics images
that are sent back to the browser by said server-side engine. If a user sees something
I did, it's probably because something bad happened and they're looking at a stack
trace on the screen.)
&lt;/p&gt;
&lt;p&gt;
The thing I find interesting is that HR hiring practices and job-writing skills haven't
gotten any better in the near-to-two-decades I've been in this industry. I can still
remember a fresh-faced wet-behind-the-ears Stroustrup-2nd-Edition-toting job candidate
named Neward looking at job placement listings and finding much the same kind of laundry
list of skills, including those with the impossible number of years of experience.
(In 1995, I saw an ad looking for somebody who had "10 years of C++ experience", and
wondering, "Gosh, I guess they're looking to hire Stroustrup or Lippmann", since those
two are the only people who could possibly have filled that requirement at the time.
This was right before reading the ad that was looking for 5 years of Java experience,
or the ad below it looking for 15 years of Delphi....)
&lt;/p&gt;
&lt;p&gt;
Given that it doesn't seem likely that HR departments are going to "get a clue" any
time soon, it leaves us with an interesting question: if you're a developer, and you're
looking at these laundry lists of requirements, how do you respond?
&lt;/p&gt;
&lt;p&gt;
Here's my own list of things for programmers/developers to consider over the next
five to ten years:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;These "laundry list" ads are not going away any time soon.&lt;/em&gt; We can rant and
rail about the stupidity of HR departments and hiring managers all we want, but the
basic fact is, this is the way things are going to work for the forseeable future,
it seems. Changing this would require a "sea change" across the industry, and sea
change doesn't happen overnight, or even within the span of a few years. So, to me,
the right question to ask isn't, "How do I change the industry to make it easier for
me to find a job I can do?", but "How do I change what I do when looking for a job
to better respond to what the industry is doing?" 
&lt;l