<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DE8MRX07eCp7ImA9WxJUFEQ.&quot;"><id>tag:blogger.com,1999:blog-4110180</id><updated>2009-07-13T07:54:44.300-07:00</updated><title>Tapestry Central</title><subtitle type="html">The inside scoop on what's happening with Tapestry ... from the creator of the Apache Tapestry framework.  Plus all the normal, random thoughts on coding and technology.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://tapestryjava.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>632</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/TapestryCentral" type="application/atom+xml" /><entry gd:etag="W/&quot;DEEERHsycSp7ImA9WxJVFUs.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-1178611148957672368</id><published>2009-07-02T13:10:00.000-07:00</published><updated>2009-07-02T13:30:05.599-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-02T13:30:05.599-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="intellij" /><category scheme="http://www.blogger.com/atom/ns#" term="eclipse" /><category scheme="http://www.blogger.com/atom/ns#" term="ides" /><title>Caught between Two IDEs</title><content type="html">&lt;p&gt;
I seem to be caught between two IDEs: Eclipse and IntelliJ. I abandoned Eclipse a couple of years back, partly based on wide spread recommendations from many different people, and partly because Eclipse just stopped working for me (it crashed out).

&lt;p&gt;
After I got started with IntelliJ I started to appreciate its merits, despite a generally clunky interface (with lots of modal windows), truly awful documentation. Many things are streamlined and only a ctrl-alt-shift-coke-bottle-touch-your-nose away.

&lt;p&gt;However, over time, using IntelliJ got slower and slower and slower. It also started running the Tapestry test suite horrifically slowly: 40 minutes and up (it should be about five). It would often &lt;em&gt;go away&lt;/em&gt;, even when memory wasn't tight. Indexing? Checking Repositories? Computing primes?  No way to tell.

&lt;p&gt;
Meanwhile, Eclipse has been moving forward, with Eclipse Galileo being a Cocoa (not a Carbon) application. Critical plugins such as M2Eclipse have gotten nice, and the Clojure plugin is mostly better than the IntelliJ one (though both are very early).

&lt;p&gt;
For a while I was using IntelliJ when teaching Tapestry (as part of the VMWare image I use when training) ... and I got a lot of resistance. People were much happier with Eclipse on the last couple of go-rounds, and I'm sticking with it.

&lt;p&gt;
Overall, I'm feeling that &lt;em&gt;most&lt;/em&gt; of what I've grown used to in IntelliJ is present in Eclipse, just handled a bit differently. The Clojure plugins are a wash; IntelliJ has the edge on the Git plugin. I think Subversion inside Eclipse is actually better.

&lt;p&gt;I've even cranked up NetBeans but didn't find anything there compelling enough to switch.

&lt;p&gt;
It seems like all my major tools (Firefox, Firebug, Eclipse, IntelliJ) are in the habit of growing too complex, and doing too much stuff in the background that I don't care about. All those intentions in IntelliJ that you have to turn off (for performance reasons), and all those extra plugins for Eclipse that you need to not download in the first place ... they're all getting in my way.  

&lt;p&gt;
I think a lot of this falls into the general category of accidental complexity ... to address the limitations of the Java programming language, all this extra stuff is coming into play: tools and wizards and plugins and indexes and whatnot. I find it pretty pleasant to work with Clojure instead, where the accidental complexity of Java is managed and isolated and the IDE doesn't feel the need to be overly ambitious. That's the Clojure concept right there ... grow the language to your needs, rather than building up tools. I think that's the Tapestry ethic as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-1178611148957672368?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/7XUSHRp-H5o" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/1178611148957672368/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=1178611148957672368" title="11 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/1178611148957672368?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/1178611148957672368?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/7XUSHRp-H5o/caught-between-two-ides.html" title="Caught between Two IDEs" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">11</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/07/caught-between-two-ides.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUIBQ3g6eip7ImA9WxJVE0U.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-685702067930311333</id><published>2009-06-30T10:33:00.000-07:00</published><updated>2009-06-30T10:39:12.612-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-30T10:39:12.612-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><category scheme="http://www.blogger.com/atom/ns#" term="training" /><title>Public Tapestry Training in London: Aug 10 - 12</title><content type="html">&lt;p&gt;
&lt;img src="http://skillsmatter.com/custom/images/sm-logo-black-manga.gif" style="float:right;"/&gt;
&lt;a href="http://formos.com"&gt;Formos&lt;/a&gt; is partnering with 
&lt;a href="http://skillsmatter.com"&gt;SkillsMatter&lt;/a&gt; to provide &lt;a href="http://skillsmatter.com/course/java-jee/tapestry-web-development"&gt;open enrollment Tapestry training&lt;/a&gt;. The training will take place at the SkillsMatter offices in &lt;a href="http://maps.google.co.uk/maps?f=q&amp;hl=en&amp;geocode=&amp;q=skills+matter+ec1r+0be&amp;ie=UTF8&amp;om=1&amp;cid=51524602,-104662,10325109927309711932&amp;source=embed&amp;ll=51.532455,-0.100422&amp;spn=0.047039,0.05785&amp;z=14"&gt;downtown London&lt;/a&gt;.

&lt;p&gt;
This is the same course materials that I use for my on-site Tapestry training ... and I'll be debuting a new lab on Ajax techniques.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-685702067930311333?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/xTQLbzQV1rI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/685702067930311333/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=685702067930311333" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/685702067930311333?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/685702067930311333?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/xTQLbzQV1rI/public-tapestry-training-in-london-aug.html" title="Public Tapestry Training in London: Aug 10 - 12" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/06/public-tapestry-training-in-london-aug.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YDRnY9fip7ImA9WxJWF00.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-7052335776298508673</id><published>2009-06-22T15:11:00.000-07:00</published><updated>2009-06-22T15:19:37.866-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-22T15:19:37.866-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="nfjs" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><title>Speaking on Clojure and Cappuccino as NFJS Seattle</title><content type="html">&lt;p&gt;
I'll be talking about Clojure and Cappuccino at &lt;a href="http://www.nofluffjuststuff.com/conference/seattle/2009/09/home"&gt;NoFluffJustStuff Pacific Northwest Software Symposium&lt;/a&gt;, which runs from Sept. 18th to the 20th in Redmond, WA.

&lt;p&gt;
I seem to have the 'C's covered, but how about the 'T's?  If you &lt;strong&gt;are attending NFJS&lt;/strong&gt; or you absolutely, positively, 100% would attend if I was speaking on Tapestry there ... &lt;a href="http://www.nofluffjuststuff.com/feedback.jsp"&gt;provide some feedback to Jay&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-7052335776298508673?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/JVty8_FcHr4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/7052335776298508673/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=7052335776298508673" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/7052335776298508673?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/7052335776298508673?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/JVty8_FcHr4/speaking-on-clojure-and-cappuccino-as.html" title="Speaking on Clojure and Cappuccino as NFJS Seattle" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/06/speaking-on-clojure-and-cappuccino-as.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MCQ3o7eip7ImA9WxJWFE8.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-2104560182397646682</id><published>2009-06-19T09:32:00.000-07:00</published><updated>2009-06-19T09:37:42.402-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-19T09:37:42.402-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><category scheme="http://www.blogger.com/atom/ns#" term="javaone" /><title>Apache Tapestry 5: State of the Union</title><content type="html">&lt;p&gt;
I've just uploaded my slide deck from JavaOne this year:

&lt;div style="width:425px;text-align:left" id="__ss_1609493"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/hlship/tapestry-state-of-the-union?type=powerpoint" title="Tapestry: State of the Union"&gt;Tapestry: State of the Union&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=tapestry-state-of-the-union-key-090619111704-phpapp01&amp;stripped_title=tapestry-state-of-the-union" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=tapestry-state-of-the-union-key-090619111704-phpapp01&amp;stripped_title=tapestry-state-of-the-union" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;documents&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/hlship"&gt;Howard Lewis Ship&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;
As usual, embedded animations and screencasts don't work, but there's a lot of value here regardless. 

&lt;p&gt;
This presentation was a slightly extended version of the &lt;a href="http://tapestryjava.blogspot.com/2009/05/last-call-tapestry-webinar-thu-may-21.html"&gt;Webinar&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-2104560182397646682?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/5D5EmSnXo7I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/2104560182397646682/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=2104560182397646682" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/2104560182397646682?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/2104560182397646682?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/5D5EmSnXo7I/apache-tapestry-5-state-of-union.html" title="Apache Tapestry 5: State of the Union" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/06/apache-tapestry-5-state-of-union.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMGRX04eyp7ImA9WxJWE0g.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-7660974041491242874</id><published>2009-06-18T12:04:00.001-07:00</published><updated>2009-06-18T12:13:44.333-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-18T12:13:44.333-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><category scheme="http://www.blogger.com/atom/ns#" term="oscon" /><title>Clojure talk from Open Source Bridge</title><content type="html">&lt;p&gt;
Here's the slides for my Clojure talk at Open Source Bridge:

&lt;div style="width:425px;text-align:left" id="__ss_1604005"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/hlship/clojure-functional-concurrency-for-the-jvm-presented-at-open-source-bridge?type=presentation" title="Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)"&gt;Clojure: Functional Concurrency for the JVM (presented at Open Source Bridge)&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=clojure-opensourcebridge-090618111043-phpapp01&amp;stripped_title=clojure-functional-concurrency-for-the-jvm-presented-at-open-source-bridge" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=clojure-opensourcebridge-090618111043-phpapp01&amp;stripped_title=clojure-functional-concurrency-for-the-jvm-presented-at-open-source-bridge" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;PDF documents&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/hlship"&gt;Howard M. Lewis Ship&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;
The upload to &lt;a href="http://www.slideshare.net"&gt;SlideShare&lt;/a&gt; was confused by parts of the slide deck, but you can follow the gist of it.

&lt;p&gt;
Presenting Clojure in 45 minutes is a challenge, and I'll need to be even briefer at &lt;a href="http://en.oreilly.com/oscon2009/public/schedule/detail/7917"&gt;OSCON&lt;/a&gt; next month.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-7660974041491242874?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/2WU7j9SXMUU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/7660974041491242874/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=7660974041491242874" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/7660974041491242874?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/7660974041491242874?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/2WU7j9SXMUU/clojure-talk-from-open-source-bridge.html" title="Clojure talk from Open Source Bridge" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/06/clojure-talk-from-open-source-bridge.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MNR3Y6cCp7ImA9WxJWEUQ.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-4560834016810754811</id><published>2009-06-16T15:45:00.000-07:00</published><updated>2009-06-16T17:44:56.818-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-16T17:44:56.818-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><category scheme="http://www.blogger.com/atom/ns#" term="scrum" /><title>Why choose Tapestry?</title><content type="html">&lt;p&gt;
I recently had an e-mail exchange with a Tapestry user; after congratulating me on creating Tapestry, he went on with the following observation on his organization:

&lt;blockquote&gt;
The company I work at unfortunately chose JSF for their big app. The reason was that Tapestry was "brittle" in the sense that, if one developer breaks something, on
a page or a service, very often the whole site won't come up because the initial registry startup will fail.  Or for example, if page A has a pagelink to page B, and page B
is broken, then page A won't render.  While I agree that we shouldn't ship unless the whole app is working, this is a thousands of pages big app with hundreds of
mediocre (as in likely to break things) developers. They'd rather have 80% of the thing working than nothing at all.  I never thought of this for my own projects,
and haven't had the time to examine the truth of their claims. What's your take?
&lt;/blockquote&gt;

&lt;p&gt;I provided the following response:

&lt;p&gt;
&lt;img src="http://upload.wikimedia.org/wikipedia/en/thumb/7/73/Thetippingpoint.jpg/200px-Thetippingpoint.jpg" style="float: right;"&gt;
Early failures are absolutely, 100%, the only path towards code quality. You may have heard the phrase "no broken windows" (see "&lt;a href="http://en.wikipedia.org/wiki/The_Tipping_Point_(book)"&gt;The Tipping Point&lt;/a&gt;" by Malcom Gladwell for more details) but the short form is that when errors go uncorrected (whether they are broken windows in an abandoned building, or broken code in an application) they tend to multiply quite rapidly.

&lt;p&gt;
The things that will "break" a link from page A to page B are substantial problems such as invalid templates, references to unknown properties or components, or compile errors in the page B class ... things that no other developer should ever see when page B's developer is working and checking in code. That is, problems that should never be checked into trunk, but instead kept in a local workspace or a private branch.

&lt;p&gt;
An organization that thinks that fail early is a problem is an organization that isn't prepared to develop a large application in &lt;strong&gt;any&lt;/strong&gt; technology. The image I'm getting is one where there is no build server, no continuous integration, at best CVS for source code management (or possibly one of those "shared directory" monstrosities) .... i.e., a chaotic environment where errors are allowed to be checked in to the trunk and can go unnoticed for some time.

&lt;p&gt;
The solution to coding errors in pages or components is not to wait until  your testers (or end users)  find the bugs, but to identify and fix the bugs early. That's called "engineering discipline" and the reality is that even self-professed "mediocre" developers can do it.  Tapestry helps because it fails early and has great exception reporting to guide you right the problem so that you can fix it. 

&lt;p&gt;
Another factor here is enforced helplessness.  If only Fred understands page B and he's out when it's broken, then all development stops waiting for Fred to get back. I hit this problem myself, years ago working on a large Struts application (those words give me the heebie jeebies now!). We had lots of code, a fragile and slow build process, and many little code "fiefdoms". I spent too much wasted time twiddling my thumbs.

&lt;p&gt;
Nobody should "own the code"; if page B is is broken, Julie (who normally develops page A) should be free to fix it. Julie will need to understand the page B code well enough to fix it, but also you need an overall environment with shared source, no repository locks (that is, nothing that says "Only Fred can change this file"), and no management &lt;a href="http://en.wikipedia.org/wiki/Pointy_haired_boss"&gt;PHB&lt;/a&gt;'s getting in the way. &lt;a href="http://en.wikipedia.org/wiki/Pair_programming"&gt;Pair programming&lt;/a&gt; is the best way for Fred and Julie to share knowledge so that they can understand each other's code. Even if pairing occurs only part time, it's very effective at knowledge transfer as well as ordinary coding.

&lt;p&gt;
The idea that "mediocre" developers should use JSF as it is more tolerant of errors is absurd!  Tapestry 5 is designed to improve productivity for all developers, by streamlining, simplifying, being smart and being concise ... not to mention live class reloading and best-of-breed exception reporting, which makes it fast to identify and fix those errors. 

&lt;p&gt;&lt;strong&gt;If your doctor tells you to eat less red meat, that doesn't mean you should switch to a diet of fried chicken three meals a day!&lt;/strong&gt;  Likewise, if you have concerns with code quality from your developers, you should not switch to a less agile, more code-intensive, less supportive development model and hope to catch all the bugs in QA. Sweeping problems under the rug is never a winning strategy.

&lt;p&gt;
Coming down off my soap box, I should also add that Tapestry 5.1 works a little bit differently than 5.0 in this respect, so it does (in fact) defer more of the page loading and validation until a link is actually clicked. This is more for performance reasons than to shield developers from application problems. Even in 5.0, the loading and validation was the "reach" from page A to pages explicitly referenced (usually via PageLink during the rendering of page A), so it's a highly unlikely case that a single error in a 1000 page application will keep the application from starting up, unless the start page of the application links to all 999 other pages.

&lt;p&gt;
&lt;img src="http://www.sciencecartoonsplus.com/images/miracle3.gif" style="float: right;"/&gt;
Re-reading the above post I can't emphasize enough: you can't ignore quality problems. Quality problems lead to development failures, schedule slips, missing functionality, low morale and high turnover. Saying "we don't have time to fix the quality problem first" is to ignore the &lt;a href="http://en.wikipedia.org/wiki/Second_law_of_thermodynamics"&gt;second law of Thermodynamics&lt;/a&gt;. You are expecting a miracle, literally writing it into your project plan.

&lt;p&gt;&lt;a href="http://formos.com"&gt;Formos&lt;/a&gt; addresses this issue two ways:  First, we use &lt;a href="http://en.wikipedia.org/wiki/Scrum_(development)"&gt;Scrum&lt;/a&gt; and deliver on (typically) 4 week cycles. Thus we set real deadlines and have a constant check on quality (we're providing working code constantly). We don't even try to predict what we'll be doing six months or two years from now, we just deliver a steady, manageable stream of software.

&lt;p&gt;Secondly, Formos uses Tapestry precisely for all the reasons that the anonymous developer's organization rejected it, and for many, many more reasons besides.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-4560834016810754811?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/UTsB_tDCRaY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/4560834016810754811/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=4560834016810754811" title="13 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/4560834016810754811?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/4560834016810754811?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/UTsB_tDCRaY/why-chose-tapestry.html" title="Why choose Tapestry?" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">13</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/06/why-chose-tapestry.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8BQnc_eCp7ImA9WxJXGE4.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-4721934702110555537</id><published>2009-06-12T12:56:00.001-07:00</published><updated>2009-06-12T13:00:53.940-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-12T13:00:53.940-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><category scheme="http://www.blogger.com/atom/ns#" term="training" /><title>Back from Tapestry 5 Training / Madison, WI</title><content type="html">&lt;p&gt;
Just got back last night from training in Madison WI. This was primarily an intro to Tapestry 5 for Tapestry 4 developers (and a couple of new-to-web-programming developers) and a lot of hands on pair programming to get them going with their conversion work.  It was a lot of fun, and as usual, I learned a bit.

&lt;p&gt;
I have a couple of weeks respite now before &lt;a href="http://tapestryjava.blogspot.com/2009/06/upcoming-clojure-talks.html"&gt;OSCON&lt;/a&gt; which will be followed with training in York, UK, then Estonia, then London.

&lt;p&gt;
I'm continuing to hold off on code changes to Tapestry 5, though I hit enough minor annoyances that I'm considering a 5.1 bug fix release before starting 5.2 in earnest.

&lt;p&gt;
I have a backlog of work related to &lt;a href="http://tapestry.formos.com/"&gt;Tapestry360&lt;/a&gt; and then my main emphasis is going to be Documentation, Screencasts, Articles, Documentation and Documentation, plus some additional Documentation.  It may be a while before I start with new features for 5.2.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-4721934702110555537?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/E2Js8DT2Wmc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/4721934702110555537/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=4721934702110555537" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/4721934702110555537?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/4721934702110555537?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/E2Js8DT2Wmc/back-from-tapestry-5-training-madison.html" title="Back from Tapestry 5 Training / Madison, WI" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/06/back-from-tapestry-5-training-madison.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcBR345eCp7ImA9WxJWE0g.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-7126768729253781378</id><published>2009-06-07T08:24:00.001-07:00</published><updated>2009-06-18T12:07:36.020-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-18T12:07:36.020-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><category scheme="http://www.blogger.com/atom/ns#" term="oscon" /><title>Upcoming Clojure Talks</title><content type="html">&lt;p&gt;I'll be speaking about Clojure at 
&lt;a href="http://opensourcebridge.org/sessions/69"&gt;Open Source Bridge&lt;/a&gt; on June 17th here in Portland.

&lt;p&gt;
&lt;a href="http://conferences.oreilly.com/oscon"&gt;
&lt;img src="http://assets.en.oreilly.com/1/event/27/oscon2009_banner_speaking_210x60.gif" width="210" height="60"  border="0"  alt="OSCON 2009" title="OSCON 2009"  /&gt;
&lt;/a&gt;


&lt;p&gt;
In addition, I'll be speaking on Clojure at
&lt;a href="http://en.oreilly.com/oscon2009/public/schedule/detail/7917"&gt;OSCON&lt;/a&gt;, on July 23rd. OSCON has left its traditional home, Portland, in favor of San Jose, alas. If you are thinking of attending, use my friends, co-workers and family discount code, &lt;strong&gt;os09fos&lt;/strong&gt;, and save 20%.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-7126768729253781378?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/aLvd-ewqqBU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/7126768729253781378/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=7126768729253781378" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/7126768729253781378?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/7126768729253781378?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/aLvd-ewqqBU/upcoming-clojure-talks.html" title="Upcoming Clojure Talks" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/06/upcoming-clojure-talks.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEUBSXk9fSp7ImA9WxJXE0U.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-3193550582176901756</id><published>2009-06-07T07:49:00.001-07:00</published><updated>2009-06-07T07:50:58.765-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-07T07:50:58.765-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="travel" /><title>Tapestry Road Show: Madison, Wisconsin</title><content type="html">&lt;p&gt;
This week, I'm in Madison, Wisconsin doing some on-site Tapestry training and mentoring. I've been here before and remember it as a pretty cool little college town. In any case, if you want to get together one night this week and chat Tapestry, Java, Open Source, Clojure or anything like that, drop a line!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-3193550582176901756?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/kJzcfYOH_e4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/3193550582176901756/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=3193550582176901756" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/3193550582176901756?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/3193550582176901756?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/kJzcfYOH_e4/tapestry-road-show-madison-wisconsin.html" title="Tapestry Road Show: Madison, Wisconsin" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/06/tapestry-road-show-madison-wisconsin.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkICQHgyfSp7ImA9WxJQGEo.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-1191510167684739842</id><published>2009-06-01T09:39:00.000-07:00</published><updated>2009-06-01T09:42:41.695-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-01T09:42:41.695-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="video" /><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><title>Vendor Client Relationship Video</title><content type="html">&lt;p&gt;
This has been making the rounds on YouTube:

&lt;p&gt;
&lt;object width="660" height="405"&gt;&lt;param name="movie" value="http://www.youtube.com/v/R2a8TRSgzZY&amp;hl=en&amp;fs=1&amp;color1=0xe1600f&amp;color2=0xfebd01&amp;border=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/R2a8TRSgzZY&amp;hl=en&amp;fs=1&amp;color1=0xe1600f&amp;color2=0xfebd01&amp;border=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="660" height="405"&gt;&lt;/embed&gt;&lt;/object&gt;


&lt;p&gt;
As a vendor, I can identify with this ... but I think a lot of clients out there (those not using Formos, for example) are ordering and charged for the Filet and receive the Tacos. Seriously ... multi-year development efforts are a different beast than purchasing a DVD, which is why short iterations and agile development keep everyone's expectations (of both cost and functionality) inline and satisified.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-1191510167684739842?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/v4exFTWOgTM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/1191510167684739842/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=1191510167684739842" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/1191510167684739842?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/1191510167684739842?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/v4exFTWOgTM/vendor-client-relationship-video.html" title="Vendor Client Relationship Video" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/06/vendor-client-relationship-video.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEARH84fCp7ImA9WxJQGE0.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-6602210090828652066</id><published>2009-05-31T12:22:00.001-07:00</published><updated>2009-05-31T13:44:05.134-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-31T13:44:05.134-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="iphone" /><title>Back from Training and Portland Code Camp</title><content type="html">&lt;p&gt;It's been a rough week ... I still had my sore throat (noticeable during the &lt;a href="http://tapestryjava.blogspot.com/2009/05/last-call-tapestry-webinar-thu-may-21.html"&gt;webinar&lt;/a&gt;) when I arrived to do four days of accelerated Tapestry training in Michigan. Returning after midnight on Friday, I had  morning and afternoon slots at &lt;a href="http://tapestryjava.blogspot.com/2009/05/tapestry-clojure-portland-code-camp.html"&gt;Portland Code Camp&lt;/a&gt; on Saturday to talk about Clojure and Tapestry. I think it was a good little conference, and 75 minute time slots are just barely enough time to say something meaningful.

&lt;p&gt;I attended a &lt;a href="http://portlandcodecamp.org/session.aspx?sid=c714691b-bf52-47f3-bbf5-81d4d152e48f"&gt;nice introduction to jQuery&lt;/a&gt; (once again confirming that I backed the wrong horse when selecting Prototype over jQuery for Tapestry), and another session on coding for iPhone.

&lt;p&gt;
The only other session I attended was &lt;a href="http://portlandcodecamp.org/session.aspx?sid=47b1503e-612b-4230-8d82-21465e421f62"&gt;iPhone Development from an ex Softie&lt;/a&gt; by Rory Blyth.  It was entertaining in an unusual way, since Rory is very glib in a stream of consciousness kind of way, but he spent all but five minutes of his time ranting against Objective-C and iPhone toolkits.  Literally he had five minutes for the core of his talk!

&lt;p&gt;I was one of a few people in the audience who knew Objective-C (though it's more than ten years since I coded in it) and found many of his objections quite unreasonable.  Basically, he wants Objective-C to look like every other language derived from C, which is missing the point of what Objective-C actually is: a melding of concepts from C and Smalltalk designed to operate on the very constrained hardware available, even for desktops, in the late 80's.  It obligates developers to do  something unreasonable by today's standards (a cumbersome retain count mechanism, rather than garbage collection), and the (&lt;em&gt;optional&lt;/em&gt;) type syntax (such as &lt;code&gt;(NSString *)&lt;/code&gt;) reveals its C heritage (as Smalltalk doesn't deal with declared types).

&lt;p&gt;
I even made this point to him; that Objective-C may be a natural fit for the constrained devices such as mobile platforms. His response to any challenge from any audience member was that we were afflicted with "Stockholm syndrome".

&lt;p&gt;Strangely, a few minutes after I pointed out the "constrained device" theory (which he dismissed, disjointedly citing Windows smart phones as a "success") he then talked about ... the constraints of the iPhone in terms of memory, battery and CPU utilization. 

&lt;p&gt;Basically, Rory is unable to wrap his head around anything unfamiliar or to understand how a difference in philosophy can inform how a language syntax evolves, as well as the terminology (i.e., Objective-C's "receivers", "messages" and "selectors") used to describe that language.

&lt;p&gt;There's a quote from the book &lt;a href="http://en.wikipedia.org/wiki/Freakonomics"&gt;Freakonomics&lt;/a&gt;, roughly (from memory):

&lt;blockquote&gt;
Morality is how we think we should live our lives. Economics reveals how we actually do.
&lt;/blockquote&gt;

&lt;p&gt;
Rory has a kind of "language morality" that states the objects should be listed first, with periods separating member access, such as method invocation, and that languages that deviate from this are failed and broken. Unfortunately for that argument, the explosive success of the iPhone and the iPhone app market indicates that Objective-C is a tremendous development platform for the kind of intuitive, focused, responsive applications that dominate the market.

&lt;p&gt;
It was a shame, because his style was entertaining, if very "slacker" styled, and if he organized his thoughts a bit and kept track of the clock, his valid criticisms of the iPhone development environment would hold a bit more weight and reach a wider, more receptive audience.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-6602210090828652066?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/-vYYs8FTsM8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/6602210090828652066/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=6602210090828652066" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/6602210090828652066?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/6602210090828652066?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/-vYYs8FTsM8/back-from-training-next-up-javaone.html" title="Back from Training and Portland Code Camp" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/back-from-training-next-up-javaone.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQNR306cCp7ImA9WxJQE0o.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-848243257798600848</id><published>2009-05-26T14:11:00.000-07:00</published><updated>2009-05-26T14:13:16.318-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-26T14:13:16.318-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><category scheme="http://www.blogger.com/atom/ns#" term="idea" /><title>Tapestry 5 Support in IDEA Maia</title><content type="html">&lt;p&gt;The next generation of IDEA, &lt;a href="http://blogs.jetbrains.com/idea/2009/05/maia-eap-is-finally-here/"&gt;Maia&lt;/a&gt; will include Tapestry 5 support; this is according to Hugo Palma, who wrote the initial version of the IDEA Tapestry plugin that has been expanded for inclusion in Maia.  Cool!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-848243257798600848?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/_ZrBivv8k18" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/848243257798600848/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=848243257798600848" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/848243257798600848?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/848243257798600848?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/_ZrBivv8k18/tapestry-5-support-in-idea-maia.html" title="Tapestry 5 Support in IDEA Maia" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/tapestry-5-support-in-idea-maia.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUYHSX44fip7ImA9WxJQEks.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-3651858778066110986</id><published>2009-05-25T07:48:00.000-07:00</published><updated>2009-05-25T07:52:18.036-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-25T07:52:18.036-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><category scheme="http://www.blogger.com/atom/ns#" term="conferences" /><title>Tapestry &amp; Clojure @ Portland Code Camp</title><content type="html">&lt;p&gt;&lt;a href="http://portlandcodecamp.org/default.aspx"&gt;Portland Code Camp&lt;/a&gt; is a local (in Portland) free conference on development tools and languages ... and it's coming up fast (this Saturday). I'll &lt;em&gt;most likely&lt;/em&gt; be talking about Tapestry and Clojure ... I actually won't know until they make their last minute session selection tomorrow (it's based on how many attendees express interest). If you're in the Portland area and want to learn a bit more about &lt;a href="http://portlandcodecamp.org/session.aspx?sid=111436ad-849c-4720-9357-a91b434eeaa3"&gt;Tapestry&lt;/a&gt; or &lt;a href="http://portlandcodecamp.org/session.aspx?sid=14ae6ba3-35f9-48a6-b077-aad9c0ba45db"&gt;Clojure&lt;/a&gt;, sign up and vote!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-3651858778066110986?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/9CMW9A9hOGE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/3651858778066110986/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=3651858778066110986" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/3651858778066110986?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/3651858778066110986?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/9CMW9A9hOGE/tapestry-clojure-portland-code-camp.html" title="Tapestry &amp; Clojure @ Portland Code Camp" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/tapestry-clojure-portland-code-camp.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMEQX4zeSp7ImA9WxJQEkw.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-1856429306182649654</id><published>2009-05-24T19:05:00.000-07:00</published><updated>2009-05-24T19:10:00.081-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-24T19:10:00.081-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="travel" /><title>Tapestry Road Show: Ann Arbor, Michigan</title><content type="html">&lt;p&gt;
This week, I'll be in Ann Arbor, MI to do a bit (aka, four grueling days) of on-site Tapestry training. If you're in Ann Arbor and would like to get together for a drink and a chat about Tapestry, Open Source, or anything along those lines, please drop a line!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-1856429306182649654?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/3u_Fy8Ld86E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/1856429306182649654/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=1856429306182649654" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/1856429306182649654?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/1856429306182649654?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/3u_Fy8Ld86E/tapestry-road-show-ann-arbor-michigan.html" title="Tapestry Road Show: Ann Arbor, Michigan" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/tapestry-road-show-ann-arbor-michigan.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEDRXs_eCp7ImA9WxJRGE4.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-1376776069703173738</id><published>2009-05-20T08:49:00.001-07:00</published><updated>2009-05-20T08:51:14.540-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-20T08:51:14.540-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><category scheme="http://www.blogger.com/atom/ns#" term="webinar" /><title>Last call: Tapestry Webinar (Thu May 21)</title><content type="html">&lt;p&gt;
&lt;a href="http://formos.com"&gt;Formos&lt;/a&gt; is sponsoring a live Tapestry Webinar on May 21st. I'll be presenting a 35 - 40 minute introduction to &lt;a href="http://tapestry.apache.org/tapestry5.1/"&gt;Tapestry 5&lt;/a&gt;, followed by live Q&amp;A.  I'll be focusing on the big-picture issues about what makes Tapestry useful, unique and fun. If you've been curious about what Tapestry is, or want a chance to ask a question about Tapestry directly, this is a great chance to do it!

&lt;p&gt;
Click a link below to register for the Webinar:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www1.gotomeeting.com/register/829996153"&gt;Thu, May 21, 2009 8:00 AM - 9:00 AM PDT&lt;/a&gt;
&lt;li&gt;&lt;a href="https://www1.gotomeeting.com/register/484227329"&gt;Thu, May 21, 2009 1:00 PM - 2:00 PM PDT&lt;/a&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-1376776069703173738?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/g-3-QE19-1o" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/1376776069703173738/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=1376776069703173738" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/1376776069703173738?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/1376776069703173738?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/g-3-QE19-1o/last-call-tapestry-webinar-thu-may-21.html" title="Last call: Tapestry Webinar (Thu May 21)" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/last-call-tapestry-webinar-thu-may-21.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcNRno8fSp7ImA9WxJRE08.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-3781679746038165076</id><published>2009-05-14T11:27:00.001-07:00</published><updated>2009-05-14T11:34:57.475-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-14T11:34:57.475-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><category scheme="http://www.blogger.com/atom/ns#" term="performance" /><title>Tapestry 5 Performance Study</title><content type="html">&lt;p&gt;Ben Gidley has done a &lt;a href="http://blog.gidley.co.uk/2009/05/tapestry-load-testing-round-up.html"&gt;detailed analysis of Tapestry 5 performance&lt;/a&gt; He used some quite reasonable assumptions, including running tests for over an hour to gauge memory use over time.  His conclusion is that Tapestry performance is excellent, which is a relief if not a surprise.

&lt;p&gt;
What I'm really pleased with is that he's demonstrated that Tapestry will perform well under load; more importantly, if a Tapestry application gets "Slashdotted", it may slow down, but it recovers once the wave of requests dies down.

&lt;p&gt;
Ben compared a Tapestry application to a Struts application with similar behavior and found that T5 out-performed Struts pretty handily, despite the fact that T5 doubles the number of requests (due to its automatic redirect-after-post behavior). 

&lt;p&gt;Thanks for the great work Ben!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-3781679746038165076?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/eihb9L3_CL4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/3781679746038165076/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=3781679746038165076" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/3781679746038165076?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/3781679746038165076?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/eihb9L3_CL4/tapestry-5-performance-study.html" title="Tapestry 5 Performance Study" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/tapestry-5-performance-study.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcDQ345eSp7ImA9WxJREUs.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-8535745376933418323</id><published>2009-05-12T13:26:00.000-07:00</published><updated>2009-05-12T13:27:52.021-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-12T13:27:52.021-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><title>Clojure @ JavaWorld</title><content type="html">&lt;p&gt;
Another nice introduction to Clojure is now online: &lt;a href="http://www.javaworld.com/javaworld/jw-05-2009/jw-05-clojure.html"&gt;Clojure: Challenge your Java Assumptions&lt;/a&gt; at JavaWorld.  An introductory Tapestry article is due at JavaWorld shortly as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-8535745376933418323?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/B32vUY40vKc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/8535745376933418323/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=8535745376933418323" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/8535745376933418323?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/8535745376933418323?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/B32vUY40vKc/clojure-javaworld.html" title="Clojure @ JavaWorld" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/clojure-javaworld.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkQNRH8ycSp7ImA9WxJREUs.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-511181724602380054</id><published>2009-05-09T08:47:00.000-07:00</published><updated>2009-05-12T13:33:15.199-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-12T13:33:15.199-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><title>Apache Tapestry Community Map</title><content type="html">&lt;p&gt;
Inspired by a map for &lt;a href="http://tinyurl.com/clojure-map"&gt;Clojure&lt;/a&gt;, I created a map for Tapestry users:
&lt;p&gt;

&lt;iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="http://maps.google.com/maps/ms?ie=UTF8&amp;amp;hl=en&amp;amp;msa=0&amp;amp;msid=106662057515738259524.0004696f8216ba268b74a&amp;amp;ll=36.315125,-74.882812&amp;amp;spn=92.320899,149.414063&amp;amp;z=2&amp;amp;output=embed"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;small&gt;View &lt;a href="http://maps.google.com/maps/ms?ie=UTF8&amp;amp;hl=en&amp;amp;msa=0&amp;amp;msid=106662057515738259524.0004696f8216ba268b74a&amp;amp;ll=36.315125,-74.882812&amp;amp;spn=92.320899,149.414063&amp;amp;z=2&amp;amp;source=embed" style="color:#0000FF;text-align:left"&gt;Apache Tapestry Users Worldwide&lt;/a&gt; in a larger map&lt;/small&gt;

&lt;p&gt;
Want to add yourself?  The map is &lt;a href="http://maps.google.com/maps/ms?ie=UTF8&amp;hl=en&amp;msa=0&amp;msid=106662057515738259524.0004696f8216ba268b74a&amp;z=2"&gt;wide open&lt;/a&gt;, something I'll probably regret later.

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: People have been adding themselves over the weekend, and trends are starting to appear. It seems like adoption is heavier in Europe than in the US (at least, among the narrow set of people who use Tapestry, know about the map, and have actually added themselves). Still, if that sample is true, it begs the question: &lt;em&gt;why?&lt;/em&gt; Is it more to do with the European developers, or due to features of Tapestry (such as localization support).

&lt;p&gt;I'm tending towards the former: talking with many Europeans shows that managers have a more "hands off" attitude towards project leaders, who are given more free reign to use tools of choice as long as they deliver. But that's also a horrible generalization from limited data.  In fact, a contrary opinion was offered by some developers in Oslo last september ... in Norway, a small number of developers make strong vocal choices (lately, Spring and SpringMVC) and the whole community follows along. But even Europe is a big place which room for many different developer cultures.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-511181724602380054?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/P2hxNuba0Lg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/511181724602380054/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=511181724602380054" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/511181724602380054?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/511181724602380054?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/P2hxNuba0Lg/apache-tapestry-community-map.html" title="Apache Tapestry Community Map" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/apache-tapestry-community-map.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEINR3w5eyp7ImA9WxJSGE0.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-3348224351293873278</id><published>2009-05-08T11:10:00.000-07:00</published><updated>2009-05-08T11:16:36.223-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-08T11:16:36.223-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><category scheme="http://www.blogger.com/atom/ns#" term="webinar" /><title>Tapestry 5 Webinar: May 21st</title><content type="html">&lt;p&gt;
&lt;a href="http://formos.com"&gt;Formos&lt;/a&gt; is sponsoring a live Tapestry Webinar on May 21st. I'll be presenting a 35 - 40 minute introduction to &lt;a href="http://tapestry.apache.org/tapestry5.1/"&gt;Tapestry 5&lt;/a&gt;, followed by live Q&amp;A.  I'll be focusing on the big-picture issues about what makes Tapestry useful, unique and fun. If you've been curious about what Tapestry is, or want a chance to ask a question about Tapestry directly, this is a great chance to do it!

&lt;p&gt;
Click a link below to register for the Webinar:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www1.gotomeeting.com/register/829996153"&gt;Thu, May 21, 2009 8:00 AM - 9:00 AM PDT&lt;/a&gt;
&lt;li&gt;&lt;a href="https://www1.gotomeeting.com/register/484227329"&gt;Thu, May 21, 2009 1:00 PM - 2:00 PM PDT&lt;/a&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-3348224351293873278?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/wQkQRHbG8lk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/3348224351293873278/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=3348224351293873278" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/3348224351293873278?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/3348224351293873278?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/wQkQRHbG8lk/tapestry-5-webinar-may-21st.html" title="Tapestry 5 Webinar: May 21st" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/tapestry-5-webinar-may-21st.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08FRXk-fip7ImA9WxJSFkg.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-4394513820519577204</id><published>2009-05-06T15:53:00.000-07:00</published><updated>2009-05-06T17:23:34.756-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-06T17:23:34.756-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><title>Apache Tapestry 5.1 Final Release - 5.1.0.5</title><content type="html">&lt;p&gt;                     The stable release for Tapestry 5.1, release 5.1.0.5, is now available for                     download.                 &lt;/p&gt; &lt;p&gt;&lt;a href="http://tapestry.apache.org/tapestry5.1/"&gt;Tapestry 5.1&lt;/a&gt;                     includes a large number of improvements to the speed and                     scalability of Tapestry without sacrificing backwards compatibility. However, you                     should still consult the                     &lt;a href="http://tapestry.apache.org/tapestry5.1/upgrade.html" class="externalLink"&gt;upgrade notes&lt;/a&gt;                     that identify a couple of minor "gotchas".                 &lt;/p&gt; &lt;p&gt;                     Major improvements from Tapestry 5.0 to Tapestry 5.1:                 &lt;/p&gt; &lt;ul&gt;&lt;li&gt;Performance optimizations that speed rendering of very complex pages, and reduce memory usage                     &lt;/li&gt;&lt;li&gt;Static JavaScript libraries will now be dynamically combined into a single request&lt;/li&gt;&lt;li&gt;Automatic GZIP compression of static and dynamic content, for clients that support it&lt;/li&gt;&lt;li&gt;Significant improvements to Tapestry's property expression language&lt;/li&gt;&lt;li&gt;Partial page updates (via Ajax) may now update multiple client-side Zones&lt;/li&gt;&lt;li&gt;Many new features and improvements to Tapestry template files&lt;/li&gt;&lt;li&gt;Improved client- and server-side validation of numeric input values&lt;/li&gt;&lt;li&gt;User's preferred locale is now encoded into the URL, rather than stored in a cookie&lt;/li&gt;&lt;li&gt;A new ProgressiveDisplay component for incremental page loading&lt;/li&gt;&lt;li&gt;Vastly improved Quickstart Archetype&lt;/li&gt;&lt;li&gt;New Tapestry IoC features to make it easier to override services and contributions to service                         configurations                     &lt;/li&gt;&lt;li&gt;Many new localizations of validation messages&lt;/li&gt;&lt;li&gt;Component reference documentation now identifies events triggered by components&lt;/li&gt;&lt;li&gt;Really slick new client-side logging facility (based on &lt;a href="http://www.gscottolson.com/blackbirdjs/" class="externalLink"&gt;Blackbird&lt;/a&gt;)                     &lt;/li&gt;&lt;li&gt;New API for URL rewriting (to provide improved control over Tapestry URLs)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;                     ... and many, many more bug fixes and improvements; full details are available in the                     &lt;a href="http://tapestry.apache.org/tapestry5.1/release-notes.html" class="externalLink"&gt;release notes&lt;/a&gt;.                 &lt;/p&gt; &lt;p&gt;&lt;a href="http://tapestry.apache.org/download.html"&gt;Download Tapestry 5.1.0.5&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-4394513820519577204?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/fbWMr0DxA60" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/4394513820519577204/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=4394513820519577204" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/4394513820519577204?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/4394513820519577204?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/fbWMr0DxA60/apache-tapestr-51-final-release-5105.html" title="Apache Tapestry 5.1 Final Release - 5.1.0.5" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/apache-tapestr-51-final-release-5105.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0UBRH0_cCp7ImA9WxJSF04.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-8217463919429555944</id><published>2009-05-05T16:43:00.000-07:00</published><updated>2009-05-07T16:34:15.348-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-07T16:34:15.348-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="monads" /><category scheme="http://www.blogger.com/atom/ns#" term="cloure" /><title>Clojure: Turns out, parsing is somewhat iterative, not functional</title><content type="html">&lt;p&gt;
... at least for me. I'm working on some more real-world code in Clojure, and I'm struggling with turning a stream of tokens (representing XML content parsed from a stream) into a DOM-like hierarchy. The tokens represent open tags, attributes, close tags, and text content.

&lt;p&gt;
I've written dozens of recursive decent compilers in the past, in Pascal, C, PL/1 and Java. The problem is, that style of compiler works by &lt;em&gt;consuming&lt;/em&gt; a stream (of characters or tokens) ... a destructive operation. 

&lt;p&gt;Logically, I want code such as:

&lt;pre&gt;
List parseTemplate(tokens)
{
  result = []

  while (tokens not empty)
  {
    token = pop(tokens)
    if (token.type == text)
    {
      add text token to result;
      continue;
    }

    if (token.type == element)
    {
      e = parse_element (token, tokens)
      add e to result;
      continue;
  }
}
&lt;/pre&gt;

&lt;p&gt;Now, in Clojure I can write a (parse-element) function that takes a bunch of tokens, and it can work its way through the tokens using Clojure's (loop) and (recur) forms ... but to the calling function, tokens will not have changed. 

&lt;p&gt;
One approach might be to pass along some pretty complex state; literally a state machine (inside a map) so that each function can keep push and popping values into and out of the state before invoking each. This would involve recursing on each token. Anyway, I have a rough idea of what that would look like and it seems complicated.

&lt;p&gt;
Instead, I've been pounding my head, looking at Clojure's support for &lt;a href="http://intensivesystems.net/tutorials/monads_101.html"&gt;monads&lt;/a&gt;. &lt;a href="http://foldoc.org/index.cgi?query=monad&amp;action=Search"&gt;Monad&lt;/a&gt; are a way to combine certain types of functions together in a way that appears as if there were mutable state. You provide some base types of monadic functions and, within the context of a monad definition, it streamlines the way those basic monadic functions can be strung together to form more complex monadic functions.

&lt;p&gt;
Still trying to wrap my head around the concept however. It gets really confusing because the real power of monads appears when the monadic values, the things returned from a monadic function, are themselves functions. Yep, that's where I get lost too.

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; passed the initial Monad hurdle; I'm finally beginning to understand them, perhaps even enough to explain them to other people.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-8217463919429555944?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/jAdvav-Ucn8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/8217463919429555944/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=8217463919429555944" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/8217463919429555944?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/8217463919429555944?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/jAdvav-Ucn8/clojure-turns-out-parsing-is-somewhat.html" title="Clojure: Turns out, parsing is somewhat iterative, not functional" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/clojure-turns-out-parsing-is-somewhat.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MHRHk6fCp7ImA9WxJSE0s.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-2725870774391403115</id><published>2009-05-03T09:40:00.000-07:00</published><updated>2009-05-03T09:50:35.714-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-03T09:50:35.714-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="clojure" /><title>Excellent Clojure Introduction</title><content type="html">&lt;p&gt;R. Mark Volkmann has put together a terrific &lt;a href="http://jnb.ociweb.com/jnb/jnbMar2009.html"&gt;Clojure Introduction&lt;/a&gt;. It starts with basic syntax and quickly works through all the core functions, broken out by categories such as "Collections", "Iteration" or "Concurrency".

&lt;p&gt;Very brisk, but full of functions (from the core) that I didn't know of. 

&lt;p&gt;
For example, here's a function I never noticed before, &lt;code&gt;(get-in)&lt;/code&gt;, as defined in the &lt;a href="http://clojure.org/api#toc276"&gt;Clojure API&lt;/a&gt;

&lt;blockquote&gt;
&lt;pre&gt;
&lt;strong&gt;(get-in m ks)&lt;/strong&gt;
returns the value in a nested associative structure, where ks is a sequence of keys
&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;
That's accurate, but really encourages you to read the source or experiment in the REPL to see exactly how it works. Worse, its mixed in with hundreds of other functions and really easy to miss (I never noticed it before!).

&lt;p&gt;
Here's what the &lt;a href="http://jnb.ociweb.com/jnb/jnbMar2009.html#Collections"&gt;Clojure Introduction&lt;/a&gt; says:

&lt;blockquote&gt;

To demonstrate this we'll create a map that describes a person. It has a key whose value describes their address using a map. It also has a key whose value describes their employer which has its own address map.

&lt;pre&gt;
&lt;code&gt;
(def person {
  :name "Mark Volkmann"
  :address {
    :street "644 Glen Summit"
    :city "St. Charles"
    :state "Missouri"
    :zip 63304}
  :employer {
    :name "Object Computing, Inc."
    :address {
      :street "12140 Woodcrest Executive Drive, Suite 250"
      :city "Creve Coeur"
      :state "Missouri"
      :zip 63141}}})
&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;
The get-in function takes a map and a key sequence. It returns the value of the nested map key at the end of the sequence. The -&amp;gt; macro and the reduce function can also be used for this purpose. All of these are demonstrated below to retrieve the employer city which is "Creve Coeur".

&lt;pre&gt;
&lt;code&gt;
(get-in person [:employer :address :city])
(-&amp;gt; person :employer :address :city) ; explained below
(reduce get person [:employer :address :city]) ; explained below
&lt;/code&gt;
&lt;/pre&gt;
&lt;/blockquote&gt;


&lt;p&gt;
This is a document to keep linked and to print out and study. Thanks Mr. Volkmann!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-2725870774391403115?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/t8-mf7yrc-Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/2725870774391403115/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=2725870774391403115" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/2725870774391403115?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/2725870774391403115?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/t8-mf7yrc-Y/excellent-clojure-introduction.html" title="Excellent Clojure Introduction" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/05/excellent-clojure-introduction.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QGR3Y9eSp7ImA9WxJTGEg.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-7176882745164776864</id><published>2009-04-27T10:47:00.002-07:00</published><updated>2009-04-27T11:02:06.861-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-27T11:02:06.861-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="couchdb" /><title>Ruby and CouchDB</title><content type="html">&lt;p&gt;
I've started looking into &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt; of late; I think it may be a great solution to some of our common issues around collecting "survey" style data from users. Our current approach uses a big nasty hierarchy of Hibernate entities.

&lt;p&gt;
I wanted to have some real, and real-world, data. Since I'm a big board gamer, I thought it would be nice to have a local copy of the &lt;a href="http://boardgamegeek.com/"&gt;BoardGameGeek&lt;/a&gt; database. I wrote a program that scrapes data from the BGG site and loads it into CouchDB.

&lt;pre&gt;
#!/usr/bin/ruby

require 'rubygems'
require 'hpricot'
require 'open-uri'
require 'thread'
require 'couchrest'


# Extension to Hpricot

class Hpricot::Elem
  # content at
  # if block given, return value comes from yielding
  # actual content to the block
  def cat(expr)
    result = self.at(expr)

    return nil unless result

    content = result.inner_html.fixup

    return (yield content) if block_given?

    return content
  end

  # content-at converted to int (via to_i)

  def cati(expr)
    self.cat(expr) { |content| content.to_i }
  end

  def search_to_text(expr)
    self.search(expr).map { |e| e.inner_text.fixup}
  end
end

$BGG = "http://boardgamegeek.com"


$catalog_pages = 0
$game_pages = 0
$games_added = 0

# Access to couch db.  From what I can tell, the Databsae is multithreaded.

$DB = CouchRest.database!("http://127.0.0.1:5984/board-game-geek")

# The thread pool.

$POOL_SIZE = 10

$QUEUE = Queue.new

workers = (1..$POOL_SIZE).map do |i|
  Thread.new("worker #{i}") do
    begin
      proc = $QUEUE.deq
      proc.call()
    end until $QUEUE.empty?
  end
end

def enqueue &amp;amp;action
  $QUEUE &amp;lt;&amp;lt; action
end


def parse_browser_page(url)
end

class String
  def fixup()
    self.gsub("&amp;amp;#039;", "'").gsub("&amp;amp;amp;", "&amp;amp;")
  end
end

def parse_and_load_game(game_id)

  $game_pages += 1

  page = Hpricot.XML(open("#$BGG/xmlapi/boardgame/#{game_id}?comments=1&amp;amp;stats=1"))

  bg = page.at("//boardgame")

  ratings = bg.at("//ratings")

  comments = (bg/"comment").map do |e|
    {
            "user" =&amp;gt; e[:username].fixup,
            "comment" =&amp;gt; e.inner_text.fixup
    }
  end

  doc = {
          "_id" =&amp;gt; game_id,
          "title" =&amp;gt; bg.cat("name[@primary='true']"),
          "description" =&amp;gt; bg.cat("description"),
          "designers" =&amp;gt; bg.search_to_text("boardgamedesigner"),
          "artists" =&amp;gt; bg.search_to_text("boardgameartist"),
          "publishers" =&amp;gt; bg.search_to_text("boardgamepublisher"),
          "published" =&amp;gt; bg.cati("yearpublished"),
          "categories" =&amp;gt; bg.search_to_text("boardgamecategory"),
          "mechanics" =&amp;gt; bg.search_to_text("boardgamemechanic"),
          "images" =&amp;gt;{
                  "url", bg.cat("image"),
                  "thumbnailUrl", bg.cat("thumbnail"),
                  },
          "players" =&amp;gt; {
                  "min" =&amp;gt; bg.cati("minplayers"),
                  "max" =&amp;gt; bg.cati("maxplayers"),
                  "age" =&amp;gt; bg.cati("age")
          },
          "stats" =&amp;gt; {
                  "rank" =&amp;gt; ratings.cati("rank"),
                  "averageRating" =&amp;gt; ratings.cat("average") { |content| content.to_f },
                  "ownedCount" =&amp;gt; ratings.cati("owned")
          },
          "comments" =&amp;gt; comments
  }

  enqueue do
    $games_added += 1

    $DB.save_doc(doc)
  end

end


def process_game(game_id)

  begin
    doc = $DB.get(game_id)

    # Found, do nothing

  rescue RestClient::ResourceNotFound

    # Not in the database yet, so fire off a request to parse its page.

    enqueue { parse_and_load_game game_id }

  end
end

def parse_catalog_page(url)

  puts("[%24s] %4d catalog pages, %4d/%4d games parsed/added (%4d actions queued)" % [Time.now.ctime, $catalog_pages,
       $game_pages, $games_added, $QUEUE.length])

  doc = Hpricot(open(url))

  $catalog_pages += 1


  doc.search("//table[@id='collectionitems']/tr/td[3]//a") do |elem|
    href = elem[:href]
    game_id = href.split('/').last()
    enqueue { process_game game_id }
  end

  next_page_link = doc.at("//a[@title='next page']")

  return unless next_page_link

  next_page = next_page_link[:href]

  # Add this last, to give the other actions a chance to operate.
  # A better mechanism would be a priority-based queue, where the catalog
  # page parse action is lower priority than the other actions.

  enqueue { parse_catalog_page($BGG + next_page) }

end


# Kick it off

start_page = $ARGV[0] || ($BGG + "/browse/boardgame")

enqueue { parse_catalog_page start_page }

# Wait for all the workers to complete

workers.each { |th| th.join }

puts "BoardGameGeek loader complete."

puts "Queue not empty!" unless $QUEUE.empty?
&lt;/pre&gt;

&lt;p&gt;
Key pieces of this is &lt;a href="http://wiki.github.com/why/hpricot"&gt;Hpricot&lt;/a&gt; to parse HTML and XML, and &lt;a href="http://groups.google.com/group/couchrest"&gt;CouchRest&lt;/a&gt; to get the data into CouchDB.

&lt;p&gt;
Did I go overboard?  I don't think so ... this runs in about two hours, and created a database of nearly 40,000 documents (about 340MB).  Using a thread pool just seemed to make sense, since (outside of the XML parsing), every aspect of this is I/O bound: pulling data from BGG or pushing data to CouchDB.

&lt;p&gt;The code is naive about some threading issues and simply crashes if there's an error.  Oh well.  

&lt;p&gt;
Next up: learning how to build views against this data and deciding how to use it all.  I'm thinking &lt;a href="http://cappuccino.org/"&gt;Cappuccino&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-7176882745164776864?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/TBQKBXdRXAA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/7176882745164776864/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=7176882745164776864" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/7176882745164776864?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/7176882745164776864?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/TBQKBXdRXAA/ruby-and-couchdb_27.html" title="Ruby and CouchDB" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/04/ruby-and-couchdb_27.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYDQ3w6fyp7ImA9WxJSFUk.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-7970208210114632809</id><published>2009-04-27T09:32:00.001-07:00</published><updated>2009-05-05T09:49:32.217-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-05T09:49:32.217-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="derby" /><title>Wither Derby?</title><content type="html">&lt;p&gt;
Over lunch last week with co-workers, we were discussing the Oracle buy out of Sun and how that would affect &lt;a href="http://www.mysql.com/"&gt;MySQL&lt;/a&gt; and what other options there would be. Several people had some experience with &lt;a href="http://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; (including myself), but then I brought up &lt;a href="http://db.apache.org/derby/"&gt;Apache Derby&lt;/a&gt; ... and &lt;em&gt;no one&lt;/em&gt; had used it or event downloaded it, and only a few had even heard of it.  I just checked their web site and the last update was in November 2008.   When I last played around with it, it seemed to have all the major features of a real database and the advantage of being pure Java (I can't speak to performance).

&lt;p&gt;
How many people are using Derby and if not, why not?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-7970208210114632809?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/jSCmJ8WPnK8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/7970208210114632809/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=7970208210114632809" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/7970208210114632809?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/7970208210114632809?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/jSCmJ8WPnK8/wither-derby.html" title="Wither Derby?" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">9</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/04/wither-derby.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YCQXs8eyp7ImA9WxJTEko.&quot;"><id>tag:blogger.com,1999:blog-4110180.post-4493003599766622707</id><published>2009-04-20T11:20:00.000-07:00</published><updated>2009-04-20T16:46:00.573-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-20T16:46:00.573-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="tapestry" /><title>Tapestry 5.1 is Beta!</title><content type="html">&lt;p&gt;We just had a vote, and Tapestry 5.1 (that is, release 5.1.0.3) is a beta release. At this point, everything is stable except for minor changes to the brandy-new URL rewriting APIs. I've been chasing down bugs and improvements for the 5.1.0.4 release, which will probably be created and voted on later this week. My guess is that 5.1.0.4 will be the final/stable release for 5.1.

&lt;p&gt;
I'm already thinking for 5.2.  Ditch Maven for Buildr?  Strong possibility.  Start using Groovy for tests?  Why not?  Finally get Spring Web Flow integration working ... you betcha!  Portlets?  Shouldn't be a problem.  Release date?  I think before the end of the year.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4110180-4493003599766622707?l=tapestryjava.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TapestryCentral/~4/VV6PdJthNGA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://tapestryjava.blogspot.com/feeds/4493003599766622707/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=4110180&amp;postID=4493003599766622707" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/4493003599766622707?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4110180/posts/default/4493003599766622707?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/TapestryCentral/~3/VV6PdJthNGA/tapetsry-51-is-beta.html" title="Tapestry 5.1 is Beta!" /><author><name>Howard</name><uri>http://www.blogger.com/profile/04486596490758986709</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09517791948272924282" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total><feedburner:origLink>http://tapestryjava.blogspot.com/2009/04/tapetsry-51-is-beta.html</feedburner:origLink></entry></feed>
