<?xml version="1.0"?>
<!-- RSS generated by Radio UserLand v8.0.8 on Fri, 21 Nov 2003 18:59:48 GMT -->
<rss version="2.0">
	<channel>
		<title>Rodney Waldhoff: Java</title>
		<link>http://radio.weblogs.com/0122027/categories/java/</link>
		<description>about the Java programming language</description>
		<language>en</language>
		<copyright>Copyright 2003 Rodney Waldhoff</copyright>
		<lastBuildDate>Fri, 21 Nov 2003 18:59:48 GMT</lastBuildDate>
		<docs>http://backend.userland.com/rss</docs>
		<generator>Radio UserLand v8.0.8</generator>
		<managingEditor>rwaldhoff@eb.com</managingEditor>
		<webMaster>rwaldhoff@eb.com</webMaster>
		<category domain="http://www.weblogs.com/rssUpdates/changes.xml">rssUpdates</category> 
		<skipHours>
			<hour>1</hour>
			<hour>2</hour>
			<hour>20</hour>
			<hour>22</hour>
			<hour>23</hour>
			<hour>21</hour>
			<hour>0</hour>
			<hour>4</hour>
			</skipHours>
		<cloud domain="radio.xmlstoragesystem.com" port="80" path="/RPC2" registerProcedure="xmlStorageSystem.rssPleaseNotify" protocol="xml-rpc"/>
		<ttl>60</ttl>
		<item>
			<title>On Programming Idioms</title>
			<link>http://radio.weblogs.com/0122027/2003/11/14.html#a99</link>
			<description>&lt;p&gt;
Two things I&apos;m always keen to learn when picking up a new programming language are:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How does one organize large projects?  In other words, how does one partition responsibilities and types across namespaces, modules and files?&lt;/li&gt;
&lt;li&gt;What are the common idioms in the language?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
I&apos;ve been doing some string processing work with Ruby recently, and it&apos;s got me thinking about examples of the latter.
&lt;/p&gt;&lt;p&gt;
For example, in Java, the String class doesn&apos;t have a direct, boolean-valued method that will tell you whether or not a String contains another String, i.e., there&apos;s nothing like:
&lt;/p&gt;
&lt;pre&gt;if(someString.contains(anotherString)) { ... }&lt;/pre&gt;
&lt;p&gt;
Instead, most Java developers will write:
&lt;/p&gt;
&lt;pre&gt;if(someString.indexOf(anotherString) != -1) { ... }&lt;/pre&gt;
&lt;p&gt;
where String.indexOf(String) returns the index of the first occurrence of the argument String, or -1 if the given String isn&apos;t found.  Most Java developers will immediately recognize that as the &quot;String.contains&quot; idiom, and won&apos;t miss a beat.
&lt;/p&gt;&lt;p&gt;
This idiom is so strong in the Java community that it&apos;s almost counter-productive to write a custom utility method:
&lt;/p&gt;
&lt;pre&gt;public class StringUtils {
  public static boolean contains(String a, String b) {
    return (a.indexOf(b) != -1);
  }
}&lt;/pre&gt;
&lt;p&gt;
since many developers who see 
&lt;/p&gt;
&lt;pre&gt;if(StringUtils.contains(someString,anotherString)) { ... }&lt;/pre&gt;
&lt;p&gt;
are likely to wonder whether the StringUtils.contains method really does what it is implied--Is this equivalent to the String.indexOf idiom?  Is that someString.contains(anotherString) or vice versa? How are null&apos;s handled? etc.  Unless the developer is already comfortable and familiar with the StringUtils class being used, this code is probably less readable to an experienced developer than the &quot;indexOf != -1&quot; formulation.
&lt;/p&gt;&lt;p&gt;
(This is not to say that &quot;String.indexOf(x) != -1&quot; is actually preferable to &quot;String.contains(x)&quot;, but rather that in the absence of String.contains, the idiom is more widely recognized than a custom utility method.  Why Sun can&apos;t at some point introduce a String.contains method, say in JDK 1.5,  isn&apos;t entirely clear to me.)
&lt;/p&gt;&lt;p&gt;
Now, in the Ruby scripting I&apos;ve been doing recently, I keep needing to determine whether a String begins with a given prefix.  In Java, that&apos;s the String.startsWith method, of course.  The Ruby String class does not have a startsWith method, but one of the neat things about Ruby is that it&apos;s possible to literally add such a method the the String class, as follows:
&lt;/p&gt;
&lt;pre&gt;class String
  def startsWith str
    return self[0...str.length] == str
  end
end&lt;/pre&gt;
&lt;p&gt;
after which everything behaves exactly like the built-in String class contained that definition.  For example, one can then write:
&lt;/p&gt;
&lt;pre&gt;if someString.startsWith(anotherString) ...&lt;/pre&gt;
&lt;p&gt;
or even
&lt;/p&gt;
&lt;pre&gt;if &quot;a literal string&quot;.startsWith(anotherString) ...&lt;/pre&gt;
&lt;p&gt;
etc.
&lt;/p&gt;&lt;p&gt;
Of course, the implementation I used for String.startsWith (&lt;code&gt;self[0...str.length] == str&lt;/code&gt;) is just one of several possible implementations.  Regular expressions provide one way of implementing such a check.  The Java-like indexOf function provides another (e.g., &lt;code&gt;self.indexOf(str) == 0&lt;/code&gt;). 
&lt;/p&gt;&lt;p&gt;
Since there is no built-in String.startsWith (or for that matter String.contains) in Ruby, I wonder if there is some common idiom that experienced Ruby developers find more readable than adding a custom method to String?  If not for String.startsWith, how about String.contains?
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/11/14.html#a99</guid>
			<pubDate>Fri, 14 Nov 2003 17:36:09 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=99&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F11%2F14.html%23a99</comments>
			</item>
		<item>
			<title>Apache Jakarta Commons Primitives 1.0 Released</title>
			<link>http://radio.weblogs.com/0122027/2003/11/06.html#a97</link>
			<description>&lt;p&gt;
I&apos;ve blogged a bit about the &lt;a href=&quot;http://jakarta.apache.org/commons/primitives/&quot; title=&quot;Apache Jakarta Commons Primitives&quot;&gt;Primitives Component&lt;/a&gt;
in &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/04/15.html#a22&quot; title=&quot;Tuesday, 15 April 2003: I/O Iterators for Java&quot;&gt;the&lt;/a&gt; &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/04/07.html#a13&quot; title=&quot;Monday, 7 April 2003: Rod&apos;s Open Source To Do List&quot;&gt;past&lt;/a&gt;, and I&apos;m happy to note that &lt;a href=&quot;http://article.gmane.org/gmane.comp.jakarta.commons.devel/34432&quot; title=&quot;[ANN] Jakarta Commons Primitives 1.0 Released&quot;&gt;commons-primitives now has an official 1.0 release&lt;/a&gt;
(&lt;a href=&quot;http://jakarta.apache.org/site/binindex.cgi#commons-primitives&quot; title=&quot;links to download primitives from a mirror&quot;&gt;binaries&lt;/a&gt;) (&lt;a href=&quot;http://jakarta.apache.org/site/sourceindex.cgi#commons-primitives&quot; title=&quot;links to download primitives from a mirror&quot;&gt;source&lt;/a&gt;).
&lt;/p&gt;&lt;p&gt;
Currently Primitives provides Java-primitive based versions of various Collection interfaces, which is substantially smaller and faster than working with the Object-wrapper equivalents.  For instance, an ArrayShortList requires 1/10th the space of an ArrayList of Shorts, and an ArrayLongList requires 2/5ths the space of an ArrayList of Longs.  There&apos;s a substantial time savings as well, in that one isn&apos;t constantly &quot;boxing&quot; and &quot;unboxing&quot; the primitives and their Object equivalents when moving them in and out of the Collection.  There are readability and &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/04/15.html#a22&quot; title=&quot;Tuesday, 15 April 2003: I/O Iterators for Java&quot;&gt;other&lt;/a&gt; advantages as well.
&lt;/p&gt;&lt;p&gt;
(And, no, as I understand it, neither the auto-boxing nor the generics features of JDK 1.5 will obviate the need for this library.  You could use auto-boxing to emulate the syntax of list.add(int), but the internal representation will still be Object based.)
&lt;/p&gt;&lt;p&gt;
We use the primitive collections fairly extensively within the &lt;a href=&quot;http://axion.tigris.org/&quot; title=&quot;Axion Java Database Engine&quot;&gt;Axion database&lt;/a&gt; project for things like indices and lists of row identifiers or data file offsets, indeed the code was originally developed there.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/11/06.html#a97</guid>
			<pubDate>Thu, 06 Nov 2003 17:08:37 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=97&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F11%2F06.html%23a97</comments>
			</item>
		<item>
			<title>The Jakarta Commons Problem in a Nutshell</title>
			<link>http://radio.weblogs.com/0122027/2003/10/30.html#a94</link>
			<description>&lt;a href=&quot;http://nagoya.apache.org/eyebrowse/ReadMsg?listName=commons-dev@jakarta.apache.org&amp;msgNo=37216&quot;&gt;Exhibit A&lt;/a&gt;, 
&lt;a href=&quot;http://nagoya.apache.org/eyebrowse/ReadMsg?listName=commons-dev@jakarta.apache.org&amp;msgNo=37218&quot;&gt;Exhibit B&lt;/a&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/10/30.html#a94</guid>
			<pubDate>Thu, 30 Oct 2003 15:26:23 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=94&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F10%2F30.html%23a94</comments>
			</item>
		<item>
			<title>Wiki + Blog = PIM</title>
			<link>http://radio.weblogs.com/0122027/2003/10/22.html#a92</link>
			<description>&lt;p&gt;
I&apos;m one of those people who&apos;s so obsessed with organization that he&apos;s poorly organized.  I&apos;m constantly trying out new ways to manage the notes I scribble on various physical and electronic media, so much so that the frequency of change leads to greater disorganization.
&lt;/p&gt;&lt;p&gt;
I&apos;ve tried a number of &quot;information management&quot; tools, including index cards, sticky notes, notebooks, a Franklin planner, Microsoft Outlook, and various outlining, mind-mapping and PIM programs, and found them all wanting in one way or another (maybe it&apos;s me).  Paper based systems were too hard to search and too static in their organization.  Lacking a PDA, electronic systems weren&apos;t portable enough.  No matter what the system, I&apos;d always spend more time trying to set up organizational categories than I ever saved by using them. In fact I had pretty much broken the habit, falling back to a collection of loosely organized text files that I could easily scp to and from whatever workstation I was currently using.
&lt;/p&gt;&lt;p&gt;
About a year ago, I got a Sharp Zaurus, and since that addresses one of my recurring PIM complaints--having something that&apos;s always readily available, my hopes for finding the perfect PIM system were renewed.  I&apos;ve played around with a number of the PIM systems available.  Using the bundled Address Book/Calendar/To Do List/Email Client was too jumbled.  The &quot;outliner&quot; &lt;a href=&quot;http://iqnotes.kybu.sk/?page=index&quot;&gt;IQNotes&lt;/a&gt; was promising, but a single hierarchy is inflexible and using it to create dated journal entries requires too much manual effort.  In the end, I came back to a loosely organized collection of text files, this time stored on the Zaurus.
&lt;/p&gt;&lt;p&gt;
Back in my &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/03/28.html#a3&quot; title=&quot;28 March 2003: First Post&quot;&gt;first post&lt;/a&gt;, I mentioned that one of the reasons I was interested in blogging is that I had become interested in journaling in general.  These two concepts--the search for the perfect organizational system and interest in journaling--interrelate.
&lt;/p&gt;&lt;p&gt;
As I&apos;m sure I&apos;m not the first to suggest, it seems that the ideal PIM system presents at least two perspectives on the information to be managed:
&lt;/p&gt;&lt;p&gt;
1) A time based view, answering such questions as &quot;what have I been working with recently?&quot; or &quot;what else was I working on around that time?&quot;
&lt;/p&gt;&lt;p&gt;
2) A &quot;concept network&quot; view, answering such questions as &quot;what&apos;s related to this topic?&quot; or &quot;what else do I know about this subject?&quot;
&lt;/p&gt;&lt;p&gt;
Clearly, I presume, blog-like software is an excellent starting point for the former, and wiki-like software is an excellent starting point for the former.  Fortunately, a number of projects have begun to explore combinations of the two, either by implementing a blog-as-wiki (like &lt;a href=&quot;http://snipsnap.org/&quot; title=&quot;snipsnap.org&quot;&gt;SnipSnap&lt;/a&gt; does) or by adding blogging features to a wiki engine (like &lt;a href=&quot;http://www.jspwiki.org/&quot; title=&quot;jspwiki.org&quot;&gt;JspWiki&lt;/a&gt; and no doubt others do).
&lt;/p&gt;&lt;p&gt;
Having a fair amount of Java experience (indeed, I&apos;ve built a little wiki or two in Java), my first thought was to get a Java based wiki up and running on my Zaurus.  JspWiki looks nice, and like most Java-based wikis is Servlet/JSP based, so I endeavored to get a WAR-friendly Java Servlet engine up and running on my Zaurus.  Having tried both Tomcat and Jetty under both the &lt;a href=&quot;http://www.esmertec.com/products/products_jeode.shtm&quot; title=&quot;Jeode Java Runtime Environment&quot;&gt;Jeode evm&lt;/a&gt; and &lt;a href=&quot;http://developer.java.sun.com/developer/earlyAccess/pp4zaurus/&quot; title=&quot;J2ME Personal Profile for Zaurus&quot;&gt;Personal Java cvm&lt;/a&gt;, I came close, but fundamentally failed to do this.  (I note that my SL-5500 had just barely enough disk space or memory to do this as well.) 
&lt;/p&gt;&lt;p&gt;
I briefly considered setting up a stand-alone (i.e., non-Servlet/JSP) Java wiki engine on the Zaurus, but without a moderate amount of development that seems like an awkward environment for templating and modification, and non-servlet Java web development feels like dead-end development. (Its only a matter of time before a reasonably micro servlet engine is available.)  That&apos;s when I stumbled across &lt;a href=&quot;http://c2.com/cgi/wiki?PhlIp&quot; title=&quot;Ward&apos;s Wiki: PhlIp&quot;&gt;PhlIp&lt;/a&gt;&apos;s &lt;a href=&quot;http://www.xpsd.com/MiniRubyWiki&quot; title=&quot;XpSD Wiki: Mini Ruby Wiki&quot;&gt;Mini Ruby Wiki&lt;/a&gt;, which implements a featureful, stand-alone wiki server in around 1000 lines of Ruby code.
&lt;/p&gt;&lt;p&gt;
(For the record, one could readily build a similarly featured wiki in Java, and probably a number of languages, in roughly the same number of lines, it might not be as much fun.)
&lt;/p&gt;&lt;p&gt;
It still took me a while to get a Ruby interpreter up and running on the Zaurus (after trying a few different builds, I finally got the one from &lt;a href=&quot;http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/46111&quot; title=&quot;Re: Ruby on the Sharp Zaurus PDA&quot;&gt;Vincent Fiack&lt;/a&gt; working), but the resulting binaries are smaller in terms of disk and memory footprint than the JVMs I was playing with.  Perhaps more importantly, as a purely interpreted language, the engine itself is easier to tweak.  And this gives me a reasonably good excuse to hack out some Ruby code.  I&apos;ve already added/modified a few minor features, adding some simple blog-like features to the calendar features that already existed.  If I come up with something I&apos;m not to embarrassed to share, I&apos;ll post it here or submit it to PhlIp&apos;s &lt;a href=&quot;http://rubyforge.org/projects/minirubywiki&quot; title=&quot;RubyForge: Project Info: MiniRubyWiki&quot;&gt;RubyForge&lt;/a&gt; project.
&lt;/p&gt;&lt;p&gt;
My only problem now is resisting the temptation to continually tweak the wiki engine code.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/10/22.html#a92</guid>
			<pubDate>Wed, 22 Oct 2003 15:40:46 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=92&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F10%2F22.html%23a92</comments>
			</item>
		<item>
			<title>Kudos to Jakarta Commons FileUpload</title>
			<link>http://radio.weblogs.com/0122027/2003/09/15.html#a89</link>
			<description>&lt;p&gt;
Recently &lt;a href=&quot;http://www.sauria.com/blog/2003/09/13#580&quot; title=&quot;Ted Leung: 13 Sep 2003: I don&apos;t want to read your damned source code&quot;&gt;Ted&lt;/a&gt; and &lt;a href=&quot;http://www.freeroller.net/page/jdmarshall/20030912#disinterest_is_not_incompetence&quot; title=&quot;Jason Marshall: 12 Sep 2003: Disinterest Is Not Incompetence&quot;&gt;Jason&lt;/a&gt; blogged on an old complaint: open source projects aren&apos;t well documented.
&lt;/p&gt;&lt;p&gt;
In a curious coincidence, at the same time I had an very positive experience with open source documentation.  Being a Jakarta Commons committer, and having done my share of multipart/form-data parsing in the past, I was vaguely familiar with &lt;a href=&quot;http://jakarta.apache.org/commons/fileupload/&quot; title=&quot;Apache&apos;s Jakarta Commons FileUpload&quot;&gt;Commons FileUpload&lt;/a&gt; but hadn&apos;t had much cause to look into it until recently.  Not only does it feature an easy-to-use API that works like a charm, the &lt;a href=&quot;http://jakarta.apache.org/commons/fileupload/using.html&quot;&gt;Using FileUpload&lt;/a&gt; page tells one everything he needs to know to get up and running in minutes.
&lt;/p&gt;&lt;/p&gt;
Granted FileUpload addresses a pretty limited domain, and &lt;a href=&quot;http://jakarta.apache.org/commons/fileupload/customizing.html&quot; title=&quot;Customizing FileUpload&quot;&gt;not all the documentation is as complete&lt;/a&gt;, but I can&apos;t remember the last time I picked up a Java library and started using it without even cracking open the JavaDocs.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/09/15.html#a89</guid>
			<pubDate>Mon, 15 Sep 2003 15:37:40 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=89&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F09%2F15.html%23a89</comments>
			</item>
		<item>
			<title>Commons Logging was my fault</title>
			<link>http://radio.weblogs.com/0122027/2003/08/15.html#a81</link>
			<description>&lt;p&gt;
I&apos;ll come right out and admit it: &lt;a href=&quot;http://jakarta.apache.org/commons/logging.html&quot; title=&quot;Jakarta Commons Logging&quot;&gt;commons-logging&lt;/a&gt;, at least in its initial form, was my fault, though probably not mine alone.
&lt;/p&gt;&lt;p&gt;
Back in 2001 I did a fair bit of work &lt;a href=&quot;http://google.com/search?q=cache:www.mail-archive.com/jakarta-commons%40jakarta.apache.org/msg03954.html&quot; title=&quot;&amp;quot;[httpclient] refactoring httpclient&amp;quot; (from jakarta-commons@jakarta.apache.org, 27 Aug 2001) [google cache]&quot;&gt;refactoring and debugging&lt;/a&gt; &lt;a href=&quot;http://jakarta.apache.org/commons/httpclient&quot; title=&quot;Jakarta Commons HttpClient&quot;&gt;commons-httpclient&lt;/a&gt;.  As part of that effort, I replaced a custom setDebug()/System.out.println based logging system with &lt;a href=&quot;http://jakarta.apache.org/log4j/&quot; title=&quot;Apache&apos;s Jakarta Log4J&quot;&gt;log4j&lt;/a&gt;.  I did this for several reasons but all of them come down to the fact that a fully-fledged logging system is often quite useful.  In fact, that debugging effort probably wouldn&apos;t have happened without it.
&lt;/p&gt;&lt;p&gt;
This change turned out to be controversial, and a runtime dependency upon log4j was in fact &lt;a href=&quot;http://google.com/search?q=cache:www.mail-archive.com/jakarta-commons%40jakarta.apache.org/msg02694.html&quot; title=&quot;&amp;quot;Re: [httpclient] logging and testing changes&amp;quot; (from jakarta-commons@jakarta.apache.org, 27 Jul 2001) [google cache]&quot;&gt;vetoed&lt;/a&gt;.  After an enormous amount of discussion, not all of it pretty, a &lt;a href=&quot;http://google.com/search?q=cache:www.mail-archive.com/jakarta-commons%40jakarta.apache.org/msg02778.html&quot; title=&quot;&amp;quot;Re: [httpclient] [VOTE] HTTP client 1.0 release&amp;quot; (from jakarta-commons@jakarta.apache.org, 1 Aug 2001) [google cache]&quot;&gt;compromise&lt;/a&gt; was finally agreed to.  This compromise basically said (a) use a thin wrapper around either log4j or the System.out logging initially implemented and (b) allow the user to specify whether to use log4j or System.out.println based upon a method call (inversion-of-control style I guess) or an external property.  I did the first implementation of this.  It was later &lt;a href=&quot;http://google.com/search?q=cache:www.mail-archive.com/jakarta-commons%40jakarta.apache.org/msg02794.html&quot; title=&quot;&amp;quot;logging again (was RE: [httpclient] [VOTE] HTTP client 1.0 release)&amp;quot; (from jakarta-commons@jakarta.apache.org, 3 Aug 2001) [google cache]&quot;&gt;suggested&lt;/a&gt;, probably reasonably so, that this &quot;log wrapping&quot; package be extracted from httpclient for use in similar circumstances.  In a more robust or complicated form (depending upon your perspective) this eventually became commons-logging.
&lt;/p&gt;&lt;p&gt;
For all its warts, this brief history of Commons Logging shows the &quot;bazaar-style&quot; of open source development working as it should: the operative word here being &quot;compromise&quot;.
&lt;/p&gt;&lt;p&gt;
Personally, I don&apos;t believe it to be especially important that Jakarta Commons committers be able to express their creativity by the selection of logging frameworks.  I&apos;d have been happy simply using log4j, and I think Ceki&apos;s work with the &quot;light&quot; log4j-ME would have been sufficient to address most of the technical concerns raised.  Yet others disagree, and I&apos;ll respect that position.  Certainly respect for that position has encouraged advocates of &lt;a href=&quot;http://avalon.apache.org/logkit/&quot; title=&quot;Apache Avalon LogKit&quot;&gt;alternative logging implementations&lt;/a&gt; to participate more fully in Jakarta Commons.
&lt;/p&gt;&lt;p&gt;
That said, I think &lt;a href=&quot;http://www.freeroller.net/page/fate/20030811#the_evils_of_commons_logging&quot; title=&quot;The evils of commons-logging.jar and its ilk&quot;&gt;Hani&lt;/a&gt; and &lt;a href=&quot;http://www.freeroller.net/page/gstamp/20030812#commons_logging&quot; title=&quot;Commons logging&quot;&gt;Glen&lt;/a&gt; miss the point entirely.  The purpose of Commons Logging is &lt;i&gt;not&lt;/i&gt; to isolate your code from changes in the underlying logging framework.  (That&apos;s certainly easy enough to do on your own, and not really worth doing in the first place given the ease of switching from one logging framework to another.)  The purpose of Commons Logging is &lt;i&gt;not&lt;/i&gt; to somehow be more useful than actual logging frameworks by being more general.  The purpose of Commons Logging is &lt;i&gt;not&lt;/i&gt; to somehow take the logging world by storm.  In fact, there are very limited circumstances in which Commons Logging is useful. If you&apos;re building a stand-alone application, don&apos;t use commons-logging.  If you&apos;re building an application server, don&apos;t use commons-logging.  If you&apos;re building a moderately large framework, don&apos;t use commons-logging.  If however, like the Jakarta Commons project, you&apos;re building a tiny little &lt;i&gt;component&lt;/i&gt; that you intend for other developers to embed in their applications and frameworks, and you believe that logging information might be useful to those clients, and you can&apos;t be sure what logging framework they&apos;re going to want to use, then commons-logging might be useful to you.
&lt;/p&gt;&lt;p&gt;
On a slightly unrelated note, I think that Hani&apos;s post fails to adequately explain how the problems caused by trying to integrate systems that use incompatible versions of the same component are unique to Commons Logging.  If you want a discussion of the technical issues with Commons Logging, which are quite genuine, there are &lt;a href=&quot;http://www.qos.ch/logging/thinkAgain.html&quot; title=&quot;Ceki&apos;s &amp;quot;Think again before adopting the commons-logging API&amp;quot;&quot;&gt;much better analyses&lt;/a&gt; available.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/08/15.html#a81</guid>
			<pubDate>Fri, 15 Aug 2003 18:59:08 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=81&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F08%2F15.html%23a81</comments>
			</item>
		<item>
			<title>Clover Plug-in for Eclipse (and NetBeans)</title>
			<link>http://madbean.com/blog/45/</link>
			<description>&lt;p&gt;
Matt Quail &lt;a href=&quot;http://madbean.com/blog/45/&quot;&gt;writes&lt;/a&gt; &quot;We have just released (beta) an &lt;a href=&quot;http://www.thecortex.net/clover/userguide/eclipse/index.html&quot;&gt;Eclipse&lt;/a&gt; plugin and a &lt;a href=&quot;http://www.thecortex.net/clover/userguide/netbeans/index.html&quot;&gt;NetBeans&lt;/a&gt; plugin for Clover, allowing you to instrument your code and view coverage results all from with the those Java IDEs.&quot;
&lt;/p&gt;&lt;p&gt;
Haven&apos;t tried it yet, but the screenshots look like exactly what I was hoping for. Sweet.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/08/08.html#a76</guid>
			<pubDate>Fri, 08 Aug 2003 12:45:59 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=76&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F08%2F08.html%23a76</comments>
			</item>
		<item>
			<title>Wanted: GUI Wrapper for Text-Based Java Applications</title>
			<link>http://radio.weblogs.com/0122027/2003/07/29.html#a67</link>
			<description>&lt;p&gt;
I&apos;ve got a simple console-based (i.e.,  text interface) Java application that I&apos;d like to expose via Java Web Start or as an Applet.  I can&apos;t, however, because System.in and System.out aren&apos;t attached to anything useful, so my application runs invisibly and can&apos;t collect any input.
&lt;/p&gt;&lt;p&gt;
What I need is a simple wrapper application that creates a basic text i/o frame that looks like stdin/stdout to my application&apos;s main method.  (Or, failing that, to a custom &lt;nobr&gt;&lt;code&gt;main(String[] args, InputStream stdin, PrintStream stdout, PrintStream stderr)&lt;/code&gt;&lt;/nobr&gt; method.)  More elaborate interfaces, such as color coded output, distinct stdout and stderr frames, spool to file, etc., are easily imagined.
&lt;/p&gt;&lt;p&gt;
I believe such an application would have fairly broad utility.  A web search finds quite a few elaborate telnet/ssh oriented terminal emulators, which one might be able to pare down to what I&apos;m looking for, but it seems like someone would have already tackled this problem.  Lazy web to the rescue?
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/07/29.html#a67</guid>
			<pubDate>Wed, 30 Jul 2003 00:10:38 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=67&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F07%2F29.html%23a67</comments>
			</item>
		<item>
			<title>A is for Axion ... Z is for Zaurus</title>
			<link>http://radio.weblogs.com/0122027/2003/07/24.html#a64</link>
			<description>&lt;p&gt;
I&apos;ve got &lt;a href=&quot;http://axion.tigris.org/&quot; title=&quot;Axion Java Relational Database&quot;&gt;Axion&lt;/a&gt; up and running on my &lt;a href=&quot;http://www.zaurus.com/&quot; title=&quot;Zaurus.com: Sharp&apos;s Zaurus site&quot;&gt;Zaurus&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
If you&apos;d like to do the same, here&apos;s how:
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Obtain a build of the Axion HEAD (1.0M3-dev).  See the &lt;a href=&quot;http://axion.tigris.org/building.html&quot; title=&quot;Building Axion&quot;&gt;instructions on building Axion&lt;/a&gt; for details.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Obtain binaries of Axion&apos;s runtime dependencies, namely &lt;a href=&quot;http://jakarta.apache.org/commons/collections/&quot; title=&quot;Jakarta Commons Collections&quot;&gt;Jakarta Commons Collections&lt;/a&gt; (currently a &lt;a href=&quot;http://jakarta.apache.org/builds/jakarta-commons/nightly/commons-collections/&quot; title=&quot;Commons-Collections nightlies&quot;&gt;nightly&lt;/a&gt; build is required) and &lt;a href=&quot;http://jakarta.apache.org/commons/logging/&quot; title=&quot;Jakarta Commons Logging&quot;&gt;Jakarta Commons Logging&lt;/a&gt; (you&apos;ll want release 1.0.3, earlier versions don&apos;t work on the Jeode VM).&lt;/p&gt;
&lt;p&gt;If you want to use the LIKE operator, you&apos;ll also need &lt;a href=&quot;http://jakarta.apache.org/regexp/&quot; title=&quot;Jakarta Regexp&quot;&gt;Jakarta Regexp&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to use the BASE64ENCODE or BASE64DECODE functions, you&apos;ll also need &lt;a href=&quot;http://jakarta.apache.org/commons/codec&quot; title=&quot;Jakarta Commons Codec&quot;&gt;Jakarta Commons Codec&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;Ensure that you have the java.util Collections and java.sql JDBC packages available on your platform.  Since the Insignia Jeode VM installed on the Zaurus by default is JDK 1.1 based, I had to copy over the JDK Collections manually.  I had thought the Collections package was available as a standalone JAR to drop in to JDK 1.1 environments but as I was unable to find it.  I just copied over the rt.jar from a JDK 1.3 installation, but I think the java.util package would suffice.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Obtain a copy of axiondb.properties.  You can pull this out of the Axion JAR or from &lt;a href=&quot;http://axion.tigris.org/source/browse/axion/conf/axiondb.properties&quot; title=&quot;axion/conf/axiondb.properties&quot;&gt;CVS&lt;/a&gt;.  Normally Axion loads this file out of the JAR automatically, but the Jeode VM seems to always return null for getClassLoader so we had to add a mechanism for specifying the configuration as an external file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now simply copy those files over to the Zaurus, add the JARs to your classpath, and you are ready to go.  For example to run the Axion console I use:&lt;/p&gt;
&lt;pre&gt;evm 
 -Dorg.axiondb.engine.BaseDatabase.properties=axiondb.properties 
 -classpath axion-1.0-M3-dev.jar:
            commons-collections.jar:
            commons-logging.jar:
            commons-codec.jar:
            regexp.jar:
            rt.jar 
 org.axiondb.tools.Console $1 $2&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
Similar steps should get Axion up and running on other micro or J2ME platforms or for that matter, other JDK 1.1 environments.
If the console is any indication, Axion seems to run rather well on the Zaurus (even running off a compact flash card rather than the RAM disk).
&lt;/p&gt;&lt;p&gt;
If folks were interested, it wouldn&apos;t be difficult to create an IPK installer for Axion, although my interest here, and others as well I imagine, is in using Axion within other apps on the Zaurus, rather than playing with Axion via the console.
&lt;/p&gt;&lt;p&gt;
If you&apos;re curious, I did have to make a few minor changes to Axion to get it run on the Jeode/JDK 1.1 VM.  Here&apos;s a brief list of what I had to change:
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The Jeode VM always seems to return null for getClassLoader (rather than throwing a security exception), so I had to add checks for null, and provide an alternative mechanism for loading the properties file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We had used File.createNewFile in several places, which is a JDK 1.2 method.  These calls turned out to be unnecessary anyway, so I simply removed them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Although it&apos;s easy to add java.util.Comparable and java.util.Comparator to the classpath, none of the core objects (Number, String, etc.) actually implement Comparable in JDK 1.1, so I had to add custom Comparators replacing ComparableComparator for those DataTypes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For reasons I don&apos;t understand, in several places where we had an hierarchy like this:&lt;/p&gt;
&lt;pre&gt;interface Foo {
  void someMethod();
}
&amp;nbsp;
abstract class AbstractBar implements Foo {
  void anotherMethod() {
    doSomething();
  }
}
&amp;nbsp;
class Bar extends AbstractBar {
  void someMethod() {
    doSomethingElse();
  }
}&lt;/pre&gt;
&lt;p&gt;I had to declare the interface methods in the abstract class:&lt;/p&gt;
&lt;pre&gt;abstract class AbstractBar implements Foo {
  &lt;b&gt;abstract void someMethod();&lt;/b&gt;
&amp;nbsp;
  void anotherMethod() {
    doSomething();
  }
}&lt;/pre&gt;&lt;p&gt;
to make various AbstractMethodErrors go away.
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
These changes have already been checked into the HEAD version of Axion, and should be part of the Milestone 3 release.
&lt;/p&gt;&lt;p&gt;
There are few Axion-based apps I&apos;ve been thinking of tinkering with on my Zaurus, some for personal use, others for my day job.  That may shake out a few issues I haven&apos;t yet encountered, but so far I&apos;ve got feature I&apos;ve tried working without too much trouble.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/07/24.html#a64</guid>
			<pubDate>Thu, 24 Jul 2003 18:11:39 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=64&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F07%2F24.html%23a64</comments>
			</item>
		<item>
			<title>LGPL and Java: More confused than ever</title>
			<link>http://radio.weblogs.com/0122027/2003/07/18.html#a57</link>
			<description>&lt;p&gt;
After &lt;a href=&quot;http://linuxintegrators.com/hl30/blog/technology/?permalink=LGPL+in+Java.html&amp;page=comments&quot; title=&quot;comments on Andy&apos;s &apos;LGPL in Java&apos;&quot;&gt;reading&lt;/a&gt; &lt;a href=&quot;http://www.rollerweblogger.org/comments/roller/Weblog/for_java_lgpl_is_viral&quot; title=&quot;comments on Dave&apos;s &apos;For Java, LGPL is viral.&apos;&quot;&gt;the&lt;/a&gt; &lt;a href=&quot;http://www.intertwingly.net/blog/1519.html&quot; title=&quot;comments on Sam&apos;s &apos;Two paths&apos;&quot;&gt;various&lt;/a&gt; &lt;a href=&quot;http://radiocomments2.userland.com/comments?u=122027&amp;p=56&quot; title=&quot;comments on Rod&apos;s &apos;The [L]GPL, Java and Asymmetry&apos;&quot;&gt;comment&lt;/a&gt; &lt;a href=&quot;http://developers.slashdot.org/developers/03/07/17/2257224.shtml&quot; title=&quot;comments on Slashdot&apos;s &apos;LGPL is Viral for Java&apos;&quot;&gt;threads&lt;/a&gt;, and seeing Andy and David&apos;s exchange in &lt;a href=&quot;http://superlinksoftware.com/text/lgpl.txt&quot;&gt;a bit more context&lt;/a&gt;, I&apos;m more confused than ever.
&lt;/p&gt;&lt;p&gt;
As quoted by Andy, Roy wrote:
&lt;/p&gt;
&lt;blockquote&gt;What the FSF needs to say is that inclusion of the external interface names (methods, filenames, imports, etc. defined by an LGPL jar file, so that a non-LGPL jar can make calls to the LGPL jar&apos;s implementation, does not cause the including work to be derived from the LGPL work even though java uses late-binding by name (requiring that names be copied into the derived executable), and thus does not (in and of itself) cause the package as a whole to be restricted to distribution as (L)GPL or as open source per section 6 of the LGPL.&lt;/blockquote&gt;
&lt;p&gt;
and Andy asked:
&lt;/p&gt;
&lt;blockquote&gt;Is this statement true with regards to the use of LGPL Java libraries by non-LGPL Java libraries?&lt;/blockquote&gt;
&lt;p&gt;
To which David replied:
&lt;/p&gt;
&lt;blockquote&gt;If I understand the statement correctly, yes -- that&apos;s exactly what section 6 is for.&lt;/blockquote&gt;
&lt;p&gt;
Seen in context, my reading is that LGPL does not infect Java code that simply references, invokes methods of, or extends an LGPL&apos;ed class.  Brad Kuhn&apos;s comments mentioned in the slashdot &quot;update&quot; seem to be reiterating that position.  I see this as saying all of my &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/04/07.html#a12&quot; title=&quot;7 April 2003: A Question on Applying the LGPL to Java&quot;&gt;examples&lt;/a&gt; are not infectious.  Joe&apos;s &lt;a href=&quot;http://radiocomments2.userland.com/comments?u=122027&amp;p=12&quot; title=&quot;comments on &apos;A Question on Applying the LGPL to Java&apos;&quot;&gt;comments&lt;/a&gt; on that post focus on the word &quot;distribute&quot; in what may be a clarifying way (i.e., the in-memory, late-bound version of code that combines LGPL and non-LGPL code is not distributed, it is assembled at runtime, and therefore not in violation).
&lt;/p&gt;&lt;p&gt;
I hesitate to ask but the question seems inevitable: what does it mean to apply aspects to LGPL&apos;ed code?  If I hook in code to a cut-point in some LGPL&apos;ed code, is my cut-point code infected?  Does it matter if my AOP-system is implemented with byte-code manipulation, reflection or composition?  Does it matter if this happens at runtime or at compile time?  It seems that it would, and that feels like a fairly arbitrary distinction in some ways.
&lt;/p&gt;&lt;p&gt;
IANAL and this makes my head spin.  I&apos;m going back to writing code.  Someone let me know when there&apos;s a clear answer here.  (Unfortunately I think it may take a court to decide that.  Let&apos;s hope it never comes to that.)
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/07/18.html#a57</guid>
			<pubDate>Fri, 18 Jul 2003 17:35:52 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=57&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F07%2F18.html%23a57</comments>
			</item>
		<item>
			<title>The [L]GPL, Java and Asymmetry</title>
			<link>http://radio.weblogs.com/0122027/2003/07/16.html#a56</link>
			<description>&lt;p&gt;
&lt;a href=&quot;http://linuxintegrators.com/hl30/blog/&quot; title=&quot;Andy Oliver&apos;s Blog&quot;&gt;Andy&lt;/a&gt; has finally &lt;a href=&quot;http://article.gmane.org/gmane.comp.jakarta.poi.devel/5900&quot; title=&quot;poi-dev@jakarta.apache.org: Re: [Followup] RE: Possibly Include HTMLParser Jar in contribcode?&quot;&gt;tracked down&lt;/a&gt; some answers on &lt;a href=&quot;http://linuxintegrators.com/hl30/blog/technology/?permalink=LGPL+in+Java.html&quot; title=&quot;LGPL in Java&quot;&gt;applying the LGPL to Java&lt;/a&gt;.  &lt;a href=&quot;http://www.rollerweblogger.org/page/roller/20030716#for_java_lgpl_is_viral&quot; title=&quot;For Java, LGPL is viral&quot;&gt;Dave&lt;/a&gt; and &lt;a href=&quot;http://www.intertwingly.net/blog/1519.html&quot; title=&quot;Two paths&quot;&gt;Sam&lt;/a&gt; had some additional comments.
&lt;/p&gt;&lt;p&gt;
A few points:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In his &lt;a href=&quot;http://www.rollerweblogger.org/comments/roller/Weblog/for_java_lgpl_is_viral&quot; title=&quot;Comments on For Java, LGPL is viral&quot;&gt;comment thread&lt;/a&gt; Dave suggests that &quot;Class.forName() might also be a workaround&quot;, echoing &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/04/07.html#a12&quot; title=&quot;7 April 2003: A Question on Applying the LGPL to Java&quot;&gt;questions on the LGPL in Java I previously mentioned&lt;/a&gt;.  The answers to those questions still aren&apos;t entirely clear to me, although the position of simply steering clear of LGPL/GPL code for Java is seems increasingly rational.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sam writes &quot;An example of something that does solve the issue: JDBC&quot; but I&apos;m not sure I follow.  Does this mean Class.forName?  In other words, I can use a LGPL&apos;d database code as long as I never directly invoke the LGPL code?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Andy writes &quot;Thus we need a license for Java that guarantees contributors will donate back to the library that does not infect the outside code.&quot;&lt;/p&gt;
&lt;p&gt;Do we?  Why?  I think there is sufficient incentive to release most derivative works anyway, and if someone doesn&apos;t, who cares?  The open source project still gets more users, more support, more field testing, mo&apos; better, than it otherwise would.  If you make a few bucks selling proprietary extensions to my open source code, more power to you.  (You run the threat, of course, of the community re-implementing your proprietary extensions in an open source fashion, thus destroying your business model.  This disincentive to selling proprietary derivatives augments the incentives for releasing those derivatives to the community for further extension, testing, maintenance and support.)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
A big issue I have with the [L]GPL is the asymmetry of the license.  If Company X releases code under the [L]GPL, I&apos;m less troubled by the need to similarly open my derivative works (although the people who sign my paycheck quite reasonably have a different perspective on that--there is some work that is best kept proprietary, if only because it pays the bills) than by the fact that Company X, typically acting as the &quot;umbrella&quot; copyright holder (to both their original work and my contributions) now has more rights to my contributions than I do.  Under the viral GPL, I &lt;i&gt;cannot&lt;/i&gt; use the larger work under any terms but those provided by the GPL, and in isolation my contributions are probably pretty much useless.  Yet Company X (as the holder of the collective copyright) is free to take my (donated) work and theirs and release (or sell) it under whatever terms they choose.  I wonder if Stallman had foreseen this consequence when constructing the GPL.
&lt;/p&gt;&lt;p&gt;
The &quot;umbrella&quot; copyright holder on a BSD- or ASF-type license has the same rights of course, but the license grants me the ability to do pretty much whatever I want with the larger work, short of claiming it all to be my own.  There is very little that the copyright holder can do that I, as a user let alone contributor, cannot also do.  It seems to me that the license with the least restrictive terms is the one that is most &quot;free&quot;.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/07/16.html#a56</guid>
			<pubDate>Wed, 16 Jul 2003 17:35:04 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=56&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F07%2F16.html%23a56</comments>
			</item>
		<item>
			<title>my pet bug, or another example of how sun doesn&apos;t get community development</title>
			<link>http://radio.weblogs.com/0122027/2003/07/15.html#a54</link>
			<description>&lt;p&gt;
I&apos;ve submitted &lt;a href=&quot;http://developer.java.sun.com/developer/bugParade/bugs/4292531.html&quot; title=&quot;Bug Id 4292531: RFE: Undeprecate java.util.Date(String)&quot;&gt;a&lt;/a&gt; &lt;a href=&quot;http://developer.java.sun.com/developer/bugParade/bugs/4354100.html&quot; title=&quot;Bug Id 4354100: Repackage sun.net.www.content.* Classes (java.net.ContentHandler)&quot;&gt;few&lt;/a&gt;
insignificant bugs to Sun&apos;s &lt;a href=&quot;http://developer.java.sun.com/developer/bugParade/&quot; title=&quot;Sun&apos;s Java Bug Database&quot;&gt;Bug Parade&lt;/a&gt; over the years, most recently &lt;a href=&quot;http://developer.java.sun.com/developer/bugParade/bugs/4890211.html&quot; title=&quot;Bug Id 4890211&quot;&gt;&quot;Collections.ReverseOrder.equals method is lacking&quot;&lt;/a&gt;, which I submitted back in January of 2003 and was finally accepted yesterday (14 July).
&lt;/p&gt;&lt;p&gt;
This isn&apos;t a critical bug, of course: It&apos;s easy to work around (that is, replace) and frankly it&apos;s been an annoyance but not a real problem in my development efforts.  Moreover, it seems like Sun has been pretty busy over the last few months working on &lt;a href=&quot;http://java.net/&quot; title=&quot;java.net&quot;&gt;other things&lt;/a&gt;.  Nevertheless, this whole experience has been frustrating.
&lt;/p&gt;&lt;p&gt;
First, in my limited and anecdotal experience the time to respond to bug reports is getting much worse.  It took six months for the Java team to acknowledge this simple, and if I may say reasonably well documented (including a &quot;patch&quot; and unit test), bug.
&lt;/p&gt;&lt;p&gt;
Second, this is a good if trivial example of how Sun&apos;s community efforts fail in execution.  Here&apos;s a trivially simple (it&apos;s clear from inspection alone) and readily demonstrated (a complete unit test is provided) defect.  A trivially simple (one line, two if you add hashCode()) patch is provided, and yet it took six months to get the issue acknowledged.  Now I&apos;ll wait an indeterminate amount of time to see the problem fixed.  All that and this problem could have been analyzed, patched and regression tested in less time than it took me to write this post.  Even the slowest moving of open source projects would have had this problem patched, if not released, in a matter of weeks.  If Sun can&apos;t find a way to move more quickly (and &lt;a href=&quot;http://jcp.org/en/jsr/detail?id=176&quot; title=&quot;JSR 176: J2SE 1.5 (Tiger) Release Contents&quot;&gt;stop chasing the most superficial features of C#&lt;/a&gt;) Java seems destined to be eclipsed by community developed languages.
&lt;/p&gt;&lt;p&gt;
I&apos;ll uncharacteristically paraphrase Jerry Seinfeld here: &quot;Sun knows how to take community input, they just don&apos;t know what to do with it.  And that&apos;s really the most important part of community: the doing.&quot; (&lt;a href=&quot;http://tomsquotes.amhosting.net/sitcom/seinfeld/jerry/jerry2.htm&quot;&gt;text&lt;/a&gt;, &lt;a href=&quot;http://tomsquotes.amhosting.net/sitcom/seinfeld/jerry/reserve.wav&quot; title=&quot;.wav file&quot;&gt;audio&lt;/a&gt;)
&lt;/p&gt;
&lt;p&gt;
PS: Also note that the second bug I linked to above, &lt;a href=&quot;http://developer.java.sun.com/developer/bugParade/bugs/4354100.html&quot; title=&quot;Bug Id 4354100&quot;&gt;&quot;Repackage sun.net.www.content.* Classes (java.net.ContentHandler)&quot;&lt;/a&gt;, was already addressed by the time I submitted it, I personally added a comment to this effect nearly two years ago, and yet the bug sits marked &quot;In progress&quot; (and with 3 votes, none of them mine).
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/07/15.html#a54</guid>
			<pubDate>Tue, 15 Jul 2003 20:02:07 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=54&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F07%2F15.html%23a54</comments>
			</item>
		<item>
			<title>Axion 1.0 Milestone 2 Released</title>
			<link>http://radio.weblogs.com/0122027/2003/07/11.html#a50</link>
			<description>&lt;p&gt;
It seems Friday is a &lt;a href=&quot;http://www.zonic-temple.org/zonic-temple/Main/blog/permalink?fn=perpojo_release&quot; title=&quot;Today is release day for PerPOJO&quot;&gt;good&lt;/a&gt; &lt;a href=&quot;http://blogs.werken.com/people/bob/archives/000218.html&quot; title=&quot;drools 2.0-beta-11&quot;&gt;day&lt;/a&gt; for &lt;a href=&quot;http://blogs.codehaus.org/projects/aspectwerkz/archives/000097.html&quot; title=&quot;AspectWerkz 0.7.2 is released&quot;&gt;releases&lt;/a&gt;:
&lt;/p&gt;&lt;p&gt;
&lt;a href=&quot;http://axion.tigris.org/index.html&quot; title=&quot;Axion: Java RDBMS&quot;&gt;Axion&lt;/a&gt; has released their &lt;a href=&quot;http://axion.tigris.org/releases/1.0M2/index.html&quot; title=&quot;Axion: Releases: 1.0 Milestone 2&quot;&gt;third binary distribution&lt;/a&gt;, just one year after their first release, and only three months since &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/03/29.html#a4&quot; title=&quot;29 March 2003: Axion 1.0 Milestone 1 Released&quot;&gt;their previous one&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
This release adds &lt;a href=&quot;http://axion.tigris.org/releases/1.0M2/release-notes.html&quot; title=&quot;Axion: Releases: 1.0 Milestone 2: Release Notes&quot;&gt;several new features&lt;/a&gt;, including the DML and BTree performance tuning I &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/05/05.html#a29&quot; title=&quot;5 May 2003: The Pleasures of Profiling&quot;&gt;previously described&lt;/a&gt;, as well as support for OUTER JOINs, LIKE clauses and JDBC 3.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/07/11.html#a50</guid>
			<pubDate>Fri, 11 Jul 2003 22:24:45 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=50&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F07%2F11.html%23a50</comments>
			</item>
		<item>
			<title>Wanted: Modular/Extensible Parser Generator</title>
			<link>http://radio.weblogs.com/0122027/2003/07/07.html#a41</link>
			<description>&lt;p&gt;
Over at the &lt;a href=&quot;http://axion.tigris.org/&quot; title=&quot;Axion: Open Source Java RDBMS&quot;&gt;Axion&lt;/a&gt; project, we&apos;re using a &lt;a href=&quot;http://javacc.dev.java.net/&quot; title=&quot;JavaCC:  Java Compiler Compiler&quot;&gt;JavaCC&lt;/a&gt; &lt;a href=&quot;http://axion.tigris.org/source/browse/axion/grammars/AxionSqlParser.jj&quot; title=&quot;Axion&apos;s AxionSqlParser.jj&quot;&gt;grammar&lt;/a&gt; to implement the SQL parser.
&lt;/p&gt;&lt;p&gt;
One of things we&apos;ve found Axion to be good for is unit testing database applications.  In other words, one can use an in-memory, in-process Axion database as a &quot;mock&quot; replacement for a regular production database.  In this case, it&apos;s quite useful to have Axion closely mimic the syntax of other RDBM systems.  For example, Axion supports &lt;code&gt;LIMIT&lt;/code&gt; and &lt;code&gt;OFFSET&lt;/code&gt; clauses like &lt;a href=&quot;http://www.postgresql.com/&quot; title=&quot;PostgeSQL open source database&quot;&gt;PostgeSQL&lt;/a&gt; and &lt;a href=&quot;http://www.mysql.com/&quot; title=&quot;MySQL open source database&quot;&gt;MySQL&lt;/a&gt; as well as a &lt;code&gt;ROWNUM&lt;/code&gt; pseudo-column like &lt;a href=&quot;http://www.oracle.com/&quot; title=&quot;Oracle closed source database&quot;&gt;Oracle&lt;/a&gt;.  Similarly, Axion supports the ISO SQL 99 syntax for outer joins (&lt;code&gt;FROM a LEFT OUTER JOIN b ON a.id = b.id&lt;/code&gt;) , but it would be nice to support Oracle&apos;s custom syntax (&lt;code&gt;FROM a, b WHERE a.id = b.id(+)&lt;/code&gt;) as well.
&lt;/p&gt;&lt;p&gt;
Supporting the idiosyncrasies of several of the popular database engines in a single grammar file seems cumbersome at best. and probably impossible. It tends to bloat our keyword namespace.  Eventually, it must lead to conflicts.  (For example, if I&apos;m trying to unit test code that eventually interacts with an Oracle database, then the &quot;mock&quot; database shouldn&apos;t accept LIMIT and OFFSET clauses, and shouldn&apos;t consider those to be keywords either.)
&lt;/p&gt;&lt;p&gt;
Axion&apos;s design is modular enough to allow for pluggable parser implementations.  Indeed, anything that implements:
&lt;/p&gt;
&lt;pre&gt;interface Parser {
  AxionCommand parse(String sql) throws AxionException;
}&lt;/pre&gt;
&lt;p&gt;

can be dropped right in.  Hence it is straightforward to define, for example, MySqlSyntax.jj, OracleSyntax.jj, SqlServerSyntax.jj, etc. to support a specific SQL dialect.  The trouble is, each of those files is going to be 90% or more the same.  What I&apos;d like is a clean mechanism for either:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;declaring SpecializedGrammar to extend from GeneralizedGrammer, perhaps with abstract productions and the like, or&lt;/li&gt;
&lt;li&gt;declaring SpecializedGrammar to be the composition of SubGrammarA and SubGrammarB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
or both.  I&apos;m especially interested in being able to combine grammars at runtime.  Anyone have any suggestions?  Can you point to an example?
&lt;/p&gt;
&lt;p&gt;
(I&apos;ll be honest, I&apos;m not much of a *CC expert.  This might be straightforward in JJTree or ANTLR, I just haven&apos;t dug into it much.  I&apos;m pretty sure it&apos;s not straightforward in plain old JavaCC.)
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/07/07.html#a41</guid>
			<pubDate>Mon, 07 Jul 2003 20:02:31 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=41&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F07%2F07.html%23a41</comments>
			</item>
		<item>
			<title>Re: Test Driven Development versus Component Reuse</title>
			<description>&lt;p&gt;
Over on the &lt;a href=&quot;http://www.softwarecraftsmen.com/blog/&quot; title=&quot;Software Craftsmen&quot;&gt;Software Craftsmen blog&lt;/a&gt;, Mike Hogan &lt;a href=&quot;http://www.softwarecraftsmen.com/blog/archives/000003.html&quot; title=&quot;Test Driven Development versus Component Reuse&quot;&gt;asks&lt;/a&gt; what is meant by &quot;the simplest thing that could possibly work&quot;.  For what it&apos;s worth, Beck actually addresses this point directly in &lt;i&gt;Extreme Programming Explained&lt;/i&gt; [&lt;a href=&quot;http://www.amazon.com/exec/obidos/ASIN/0201616416/rodsradiowebl-20&quot; title=&quot;details at amazon (via my associates id)&quot;&gt;ISBN:0201616416&lt;/a&gt;]:
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here is what I mean by simplest--four constraints, in priority order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The system (code and tests together) must communicate everything you want to communicate.&lt;/li&gt;
&lt;li&gt;The system must contain no duplicate code. (1 and 2 together constitute the Once and Only Once Rule).&lt;/li&gt;
&lt;li&gt;The system should have the fewest possible classes.&lt;/li&gt;
&lt;li&gt;The system should have the fewest possible methods.&lt;/li&gt;
&lt;/ol&gt;
[...]
&lt;p&gt;If you view the design as a communication medium, then you will have objects or methods for every important concept.  You will choose the names of the classes and methods to work together.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
I have my own issues with that definition that I hope to pick up in a later post. (For starters, define &quot;everything you want to communicate&quot;.) 
&lt;/p&gt;
&lt;p&gt;
Mike goes on to question whether there are times when TSTTCPW conflicts with design for reuse.
&lt;/p&gt;&lt;p&gt;
I think this misses the test first aspect.  Consider approaching the Grep example test first.  A small set of tests that might lead to the first Grep implementation is:
&lt;/p&gt;
&lt;pre&gt;static final String TEXT = &quot;This is\na simple test&quot;;
Grep grep = null;
BufferedReader reader = null;
&amp;nbsp;
void setUp() {
  grep = new Grep();
  reader = new BufferedReader(new StringReader(TEXT));
}
&amp;nbsp;
void testDoesContain() {
  assertTrue(grep.contains(reader,&quot;is&quot;);
}
&amp;nbsp;
void testDoesNotContain() {
  assertFalse(grep.contains(reader,&quot;is not&quot;);
}
&amp;nbsp;
void testPatternsSplitAcrossMultipleLinesAreNotFound() {
  assertFalse(grep.contains(reader,&quot;is*a&quot;);
}&lt;/pre&gt;
&lt;p&gt;
Mike asserts that the Grep implementation would be more useful if it could interoperate with multiple regular expression frameworks, and provides an example &quot;Inversion of Control&quot; approach for doing so.  Want to make that Grep implementation work with multiple regular expression frameworks?  Great.  First, write a test that fails:
&lt;/p&gt;
&lt;pre&gt;void testGrepWithJakartaRegexp() {
   RegexpProvider rep = new RegexpRegexpProvider();
   ReusableGrep grep = new ReusableGrep(rep);
   assertTrue(grep.contains(reader,&quot;is&quot;);
   assertFalse(grep.contains(reader,&quot;is not&quot;);
}
&amp;nbsp;
void testGrepWithJakartaOro() {
   RegexpProvider rep = new OroRegexpProvider();
   ReusableGrep grep = new ReusableGrep(rep);
   assertTrue(grep.contains(reader,&quot;is&quot;);
   assertFalse(grep.contains(reader,&quot;is not&quot;);
}&lt;/pre&gt;
&lt;p&gt;
(Alternatively, (1) define a &quot;mock&quot; instance of RegexpProvider for the purpose of this test rather than using specific implementations and (2) define an abstract getRegexpProvider method in your test class, an implement these tests as concrete extensions of that abstract test case, but I digress.)
&lt;/p&gt;&lt;p&gt;
Now we can justify the creation of the RegexpProvider interface, and ReusableGrep still meets the &quot;simplest&quot; criteria.  (Ignoring that ORO and Regexp likely support slightly different syntaxes.) 
&lt;/p&gt;&lt;p&gt;
I think Mike&apos;s first instinct--simple is &quot;the smallest amount of code&quot; that will &quot;get the test case[s] running and refuses to concern itself with any potential future requirement&quot; is the right one.  Have additional requirements you&apos;d like to assert? Then express them as tests and this simple rule allows you to support them.  When approaching development test first I think a lot these questions about &quot;what is simple&quot; simply fade away, as does much premature generalization.  (And I say that without taking a position on whether ReusableGrep represents premature generalization or not.  I recognize that it&apos;s meant as a trivial example.) 
&lt;/p&gt;&lt;p&gt;
PS: I can&apos;t resist the tempation to plug a &lt;a href=&quot;http://jakarta.apache.org/commons/sandbox/functor&quot; title=&quot;Apache&apos;s Jakarta-Commons Functor&quot;&gt;commons-functor&lt;/a&gt; approach to this Grep implementation.  How about something like:&lt;p&gt;
&lt;pre&gt;Lines.from(reader).contains(RegexpMatch.of(&quot;my expression&quot;))&lt;/pre&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/07/01.html#a39</guid>
			<pubDate>Tue, 01 Jul 2003 22:01:22 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=39&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F07%2F01.html%23a39</comments>
			</item>
		<item>
			<title>Like Clover? Check out JCoverage</title>
			<description>&lt;p&gt;
Like &lt;a href=&quot;http://www.thecortex.net/clover/&quot; title=&quot;Clover: a code coverage tool for Java&quot;&gt;Clover&lt;/a&gt;, &lt;a href=&quot;http://jcoverage.com/&quot; title=&quot;JCoverage: a code coverage tool for Java&quot;&gt;JCoverage&lt;/a&gt; is a code coverage analyzer for Java.  &quot;Instrument&quot; your code with either of these tools, run your unit test suite (really, execute the code in any way), and one can generate a report on what was executed (lines, methods, branches, etc.), and more importantly, what wasn&apos;t.
&lt;/p&gt;&lt;p&gt;
Unlike Clover:
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;JCoverage is &lt;a href=&quot;http://www.gnu.org/copyleft/gpl.html&quot; title=&quot;GNU General Public License&quot;&gt;GPL&lt;/a&gt;&apos;ed&lt;/li&gt;
&lt;li&gt;JCoverage instruments the byte code (via &lt;a href=&quot;http://jakarta.apache.org/bcel/&quot; title=&quot;Apache&apos;s BCEL: Byte Code Engineering Library&quot;&gt;BCEL&lt;/a&gt;) rather than the source, which seems substantially faster, at least under casual observation.&lt;/li&gt;
&lt;li&gt;JCoverage is clever enough to not instrument select lines--lines that invoke &lt;a href=&quot;http://jakarta.apache.org/log4j/&quot; title=&quot;Apache&apos;s Log4J&quot;&gt;log4j&lt;/a&gt; for example--which means that logging calls don&apos;t pollute your coverage metrics, whether or not you run the test suite with logging on.&lt;/li&gt;
&lt;li&gt;JCoverage can generate a complete, parsable coverage report in XML from which you can render custom reports or derived statistics.&lt;/li&gt;
&lt;li&gt;JCoverage includes custom &lt;a href=&quot;http://ant.apache.org/&quot; title=&quot;Apache Ant: a Java-based build tool&quot;&gt;Ant&lt;/a&gt; tags for instrumentation, reporting and even asserting levels of coverage at a fine grained level.&lt;/li&gt;
&lt;li&gt;JCoverage makes it easy to merge coverage databases across several runs--for unit and functional tests, for example, or to create a single report for independently built components. (Of course, given the XML report, it may be tedious but shouldn&apos;t be difficult to do this sort of merge on &quot;manually&quot; either.)&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;
With JCoverage, I think I&apos;ll need to reconsider &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/06/23.html#a32&quot; title=&quot;23 June 2003: A Frog Boiling Approach to Increasing Test Coverage&quot;&gt;my position&lt;/a&gt; that coverage analysis may be too slow to execute with every continuous integration build.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/06/30.html#a37</guid>
			<pubDate>Mon, 30 Jun 2003 14:59:57 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=37&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F06%2F30.html%23a37</comments>
			</item>
		<item>
			<title>Re: Why Java is not Open Source</title>
			<description>&lt;p&gt;
The CTO for Sun&apos;s Desktop Division &lt;a href=&quot;http://today.java.net/pub/au/16&quot; title=&quot;Hans Muller&apos;s bio on java.net&quot;&gt;Hans Muller&lt;/a&gt; &lt;a href=&quot;http://weblogs.java.net/pub/wlg/202&quot; title=&quot;Why Java is not Open Source: One Cowboy&apos;s Opinion&quot;&gt;writes&lt;/a&gt;:
&lt;/p&gt;
&lt;blockquote&gt;&lt;i&gt;I think that one of the primary reasons that Java is not an open source project is that given the size of the developer community, forks are unacceptable. In other words the millions of developers who build software on top of Java value its stability more than they value the right to get under the hood and fix it.&lt;/i&gt;&lt;/blockquote&gt;
&lt;p&gt;
Hrrrm.  That seems like a moderately controversial statement to me, for several reasons:
&lt;ol&gt;
&lt;li&gt;The community&apos;s experience with &lt;a href=&quot;http://www.python.org/&quot;&gt;Python&lt;/a&gt; (&lt;a href=&quot;http://sourceforge.net/cvs/?group_id=5470&quot; title=&quot;Python&apos;s page at Sourceforge&quot;&gt;source&lt;/a&gt;), &lt;a href=&quot;http://www.ruby-lang.org/en/&quot;&gt;Ruby&lt;/a&gt; (&lt;a href=&quot;http://www.ruby-lang.org/en/cvsrepo.html&quot; title=&quot;Ruby CVS Repository Guide&quot;&gt;source&lt;/a&gt;), &lt;a href=&quot;http://www.perl.com/&quot;&gt;Perl&lt;/a&gt; (&lt;a href=&quot;http://www.perl.com/pub/a/language/info/software.html#sourcecode&quot; title=&quot;Perl Source Code Distribution&quot;&gt;source&lt;/a&gt;) (and others) might be actively proving otherwise.&lt;/li&gt;
&lt;li&gt;The metaphor about cowboys and power plants, like many physical metaphors for software development, simply doesn&apos;t work.  A version control system alone would alleviate this problem, as would a &quot;gatekeeper&quot; as Muller himself describes in the proceeding paragraphs.&lt;/li&gt;
&lt;li&gt;Why not just define a specification and a &lt;a href=&quot;http://jcp.org/en/introduction/glossary#T&quot; title=&quot;Technology Compatibility Kit&quot;&gt;TCK&lt;/a&gt;, hang on to the Java trademark and make folks pay to describe their JRE as such.  It&apos;s precisely the same strategy used for the J2EE brand, isn&apos;t it?  Oh, &lt;a href=&quot;http://www.google.com/search?q=sun+jboss&quot;&gt;now I get it&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Simply adding a patch mechanism to the &lt;a href=&quot;http://developer.java.sun.com/developer/bugParade/&quot; title=&quot;developer.java.sun.com&apos;s Bug Database&quot;&gt;Bug Parade&lt;/a&gt; and actually accepting them once in a while would seem to be a dramatic step forward, giving Sun many of the benefits of open source (and the development community a few) with little or no risk.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
I didn&apos;t and still don&apos;t expect Sun to open source Java, although not for any of the reasons Muller describes.  Yet not having followed the &lt;a href=&quot;http://java.net/&quot; title=&quot;java.net - the Source for Java(tm) Technology Collaboration&quot;&gt;java.net&lt;/a&gt; phenomenon very closely, I had took it to be a sign that Sun is getting more clueful about the role of the developer community, and of the open source developer community in particular, in the success of Java, especially relative to the &lt;a href=&quot;http://jcp.org&quot; title=&quot;The Java Community Process(SM) Program&quot;&gt;Java Community Process&lt;/a&gt;.  Perhaps I was wrong.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/06/26.html#a36</guid>
			<pubDate>Thu, 26 Jun 2003 22:47:03 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=36&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F06%2F26.html%23a36</comments>
			</item>
		<item>
			<title>Experimenting with Jester</title>
			<description>&lt;p&gt;
In a &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/06/24.html#a34&quot; title=&quot;24 June 2003: Testing Testing&quot;&gt;previous post&lt;/a&gt; I alluded to the use of mutation testing to evaluate the completeness of a test suite, rather than relying upon pure test coverage metrics.  In a &lt;a href=&quot;http://radiocomments2.userland.com/comments?u=122027&amp;p=34&quot; title=&quot;comments on &amp;quot;Testing Testing&amp;quot;&quot;&gt;comment&lt;/a&gt; to that post &lt;a href=&quot;http://www.oshineye.com/&quot; title=&quot;Adewale Oshineye&apos;s homepage&quot;&gt;Adewale Oshineye&lt;/a&gt; suggested that I check out Ivan Moore&apos;s &lt;a href=&quot;http://jester.sourceforge.net/&quot; title=&quot;Jester: the JUnit test tester&quot;&gt;Jester&lt;/a&gt;, a Java/JUnit based mutation testing tool.  I&apos;d seen Jester before, but I&apos;d never used it nor looked at it in much detail.  The anecdote about &lt;a href=&quot;http://groups.yahoo.com/group/extremeprogramming/message/32277&quot; title=&quot;jester shows bowling scoring could be simpler&quot;&gt;what Jester uncovered&lt;/a&gt; in Bob Martin&apos;s and Robert Koss&apos;s &lt;a href=&quot;http://www.objectmentor.com/resources/articles/xpepisode.htm&quot; title=&quot;Engineer Notebook: An Extreme Programming Episode&quot;&gt;test driven bowling score calculator example&lt;/a&gt; was certainly interesting, so this morning I bit the bullet and downloaded a copy.  
&lt;/p&gt;&lt;p&gt;
Getting Jester up and running was a minor hassle (and it seems like much of that hassle could be alleviated), but I&apos;ve written my share of open source projects with quirky configuration and installation, so I&apos;ll leave that alone.  Once my files were placed in the proper position and after tweaking the python scripts to get them to run on whatever version of python I&apos;ve got on my RedHat box, Jester ran slowly (waiting on javac) but well.  It ran much faster once I figured out how to tell Jester to stop mutating my comments (set &lt;code&gt;shouldRemoveComments=true&lt;/code&gt; in &lt;code&gt;jester.cfg&lt;/code&gt;).  The result was a basic HTML report like &lt;a href=&quot;http://jester.sourceforge.net/jester.html&quot; title=&quot;example Jester report&quot;&gt;this one&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
(On an unrelated note, is there something more or less equivalent to &lt;code&gt;python -version&lt;/code&gt;?)
&lt;/p&gt;&lt;p&gt;
As an experiment, I took a small component (196 non-blank, non-comment lines of code spread over 34 methods) I knew to be well tested (100% coverage of statements and conditional expressions) and ran it through Jester.  It found 21 mutations total, 2 of which didn&apos;t lead to a test failure.  Those were (with the modified code in bold):
&lt;/p&gt;
&lt;pre&gt;if(&lt;b&gt;TRUE ||&lt;/b&gt; MESSAGE_LOG.isDebugEnabled()) {
   MESSAGE_LOG.debug(&quot;Broadcasting &quot; + msg);
}&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre&gt;List list = new ArrayList(_listeners.size() + &lt;b&gt;&lt;strike&gt;1&lt;/strike&gt;2&lt;/b&gt;);
list.addAll(_listeners);
list.add(&lt;i&gt;...&lt;/i&gt;);&lt;/pre&gt;
&lt;p&gt;
In the first case, believe it or not, I actually had unit tests that confirm that MESSAGE_LOG generates log events when set to the DEBUG priority, and no log events when set to higher than DEBUG priority.  (I wouldn&apos;t normally do that, except this is the single log message in that component, and I really wanted 100% coverage.  Besides, it wasn&apos;t that hard, I just added a mock Appender to that Category, and checked to see if a message was added or not.)  Of course, both of these tests still pass, even without the isDebugEnabled call, since the debug method won&apos;t generate a log event when using a higher priority.  Adding a test that fails as a result of this mutation isn&apos;t particularly useful, but it isn&apos;t difficult either--I just pass in a mock instance of the &lt;i&gt;msg&lt;/i&gt; object and check whether or not the toString method is invoked.  Not invoking toString is indeed the reason for this if(isDebugEnabled()) block, so maybe that&apos;s not such an odd test to have after all.
&lt;/p&gt;&lt;p&gt;
The second case is the kind of thing Ivan Moore describes as a &quot;false positive&quot; in his &lt;a href=&quot;http://www.xp2001.org/xp2001/conference/papers/Chapter20-Moore.pdf&quot; title=&quot;Jester - a JUnit test tester&quot;&gt;writeup on Jester&lt;/a&gt;.  This code initializes that ArrayList to the precise size it knows will need.  Allocating it a little bit bigger or a little bit smaller doesn&apos;t alter the functional behavior of the method (although it will be slightly less efficient).  Maybe that indicates a premature optimization on my part, but it seems like a pretty small one.  In any event I don&apos;t see any way to confirm that that List was allocated to precisely the right size without breaking encapsulation profoundly, so I think I&apos;ll let that one go.
&lt;/p&gt;&lt;p&gt;
I had hoped to run Jester on some larger, more complicated but less well tested code (3,287 nc,nb lines, roughly 77% coverage) to get a feel for how it works in a more useful scenario, but I&apos;ve been unable to get it to complete a run on the this larger component.  I may poke around with something in-between, but 4,000 lines is on the smallish side for the kinds of modules I&apos;d want to run this on.  I may have better luck mutating a single class at a time.
&lt;/p&gt;&lt;p&gt;
In short, I think Jester meets &lt;a href=&quot;http://www.intertwingly.net/blog/&quot; title=&quot;intertwingly.net: Sam Ruby&apos;s Weblog&quot;&gt;Sam Ruby&lt;/a&gt;&apos;s criteria for a successful open source project--it&apos;s a good idea with a bad implementation.  I have some thoughts on how to improve that implementation (mainly obvious ones--e.g., use a ClassLoader and an actual parser, or consider mutating the byte code rather than the source) that maybe I&apos;ll cover in a later post.  All in all, Jester is an interesting project, and like a lot of things, I wish it worked a bit better.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/06/25.html#a35</guid>
			<pubDate>Wed, 25 Jun 2003 19:29:35 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=35&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F06%2F25.html%23a35</comments>
			</item>
		<item>
			<title>Testing Testing</title>
			<description>&lt;p&gt;
My fear, and perhaps it&apos;s not a well founded one, is that &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/06/23.html#a32&quot; title=&quot;23 June 2003: A Frog Boiling Approach to Increasing Test Coverage&quot;&gt;the pursuit of pure test coverage&lt;/a&gt;--the percentage of lines, statements, methods, etc. tested--will provide a false sense of completeness.  If &quot;percent executed by test code&quot; is your sole metric, it&apos;s easy to write superficial tests that execute statements, but actually &quot;test&quot; very little.
&lt;/p&gt;&lt;p&gt;
For example, a couple of weeks ago I added the following test to one of our suites:
&lt;/p&gt;
&lt;pre&gt;public void testStartStop() {
  AppMain app = new AppMain();
  assertFalse(app.isStarted());
  app.start();
  assertTrue(app.isStarted());
  app.stop();
  assertFalse(app.isStarted());
}&lt;/pre&gt;
&lt;p&gt;
This single test--directly invoking just four distinct methods and comprising only three assertions--executed an additional 1,500 lines or so, roughly 10% of the code for this module.  You can be sure that the bulk of the functionality provided by those 1,500 lines is not actually tested here.  Indeed, the following (test first) implementation would suffice:
&lt;/p&gt;
&lt;pre&gt;class AppMain {
  void start() {
    started = true;
  }
  void stop() {
    started = false;
  }
  boolean isStarted() {
    return started;
  }
  boolean started = false;
}&lt;/pre&gt;
&lt;p&gt;
Is this test useless?  At this point I&apos;ll argue it isn&apos;t.  Superficial testing of these 1,500 lines is better than no testing at all.  This test at least confirms that we&apos;ve got the classpath right (including any resources loaded on application startup) and that there aren&apos;t any uncaught exceptions being thrown on startup.  (When better tests are in place, this superficial test may indeed become useless.) But the resulting test coverage metric is certainly misleading. 
&lt;/p&gt;&lt;p&gt;
One solution, probably the right one, is to simply &lt;a href=&quot;http://www.junit.org/news/article/test_first/index.htm&quot; title=&quot;JUnit.org: Test First Articles&quot;&gt;develop the code test first&lt;/a&gt;.  If every change to production code was made to address a failing test (or to refactor under a unchanging test suite) then one certainly wouldn&apos;t find himself in this situation.  But this solution doesn&apos;t address my (our) current situation, in which we have 100,000 lines of &quot;legacy&quot; code and perhaps 60% of that code was developed &quot;test last&quot; if test at all.  The lack of tests has become a drag on our ability to refactor or simply work with that code.  If it was sufficient to simply tell folks to develop test first, I wouldn&apos;t be as concerned with measuring test coverage in the first place.
&lt;/p&gt;&lt;p&gt;
Mutation testing--in which we randomly change some piece of production code and check to see if our test suite detects the change--is another approach I&apos;ve seen proposed before, but I&apos;m having trouble buying into that.  If we start with poorly factored code, it seems likely that a random change is going to break something, probably profoundly (like leading to an exception being thrown).  Even superficial testing will detect those sort of problems.
&lt;/p&gt;&lt;p&gt;
Alternative but indirect metrics may be a better approach.  Tracking the number of distinct tests or facts being asserted might give a rough idea of how robust the test suite is.  To do this right I think I&apos;d need some numbers from well tested portions of the code base that correlate size or complexity metrics with the number of tests or assertions in the test suite.  These might be interesting numbers to collect.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/06/24.html#a34</guid>
			<pubDate>Tue, 24 Jun 2003 15:09:46 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=34&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F06%2F24.html%23a34</comments>
			</item>
		<item>
			<title>Re: Liskov&apos;s Substitution Principle and JUnit Testing</title>
			<description>The author of &lt;a href=&quot;http://roller.anthonyeden.com/page/ceperez/&quot; title=&quot;::Manageability::&quot;&gt;Manageability&lt;/a&gt; has &lt;a href=&quot;http://roller.anthonyeden.com/page/ceperez/20030624#liskov_s_substitution_principle_and&quot; title=&quot;Liskov&apos;s Substitution Principle and JUnit Testing&quot;&gt;discovered&lt;/a&gt; the technique of inheriting test cases.  This testing strategy is extremely useful when testing multiple implementations of some interface, and &lt;a href=&quot;http://cvs.apache.org/viewcvs/jakarta-commons/collections/src/test/org/apache/commons/collections/TestCollection.java?rev=HEAD&amp;content-type=text/vnd.viewcvs-markup&quot; title=&quot;org.apache.commons.collections.TestCollection&quot;&gt;is&lt;/a&gt;
&lt;a href=&quot;http://cvs.apache.org/viewcvs/jakarta-commons/pool/src/test/org/apache/commons/pool/TestObjectPool.java?rev=HEAD&amp;content-type=text/vnd.viewcvs-markup&quot; title=&quot;org.apache.commons.pool.TestObjectPool&quot;&gt;actually&lt;/a&gt;
&lt;a href=&quot;http://cvs.apache.org/viewcvs/jakarta-commons-sandbox/functor/src/test/org/apache/commons/functor/BaseFunctorTest.java?rev=HEAD&amp;content-type=text/vnd.viewcvs-markup&quot; title=&quot;org.apache.commons.functor.BaseFunctorTest&quot;&gt;fairly&lt;/a&gt;
&lt;a href=&quot;http://axion.tigris.org/source/browse/axion/test/org/axiondb/functional/TestDQL.java?rev=1.28&amp;content-type=text/x-cvsweb-markup&quot; title=&quot;org.axiondb.functional.TestDQL&quot;&gt;common&lt;/a&gt;.
In fact, there&apos;s not &lt;a href=&quot;http://jakarta.apache.org/commons/sandbox/jux/&quot; title=&quot;Apache Jakarta Commons JUX: JUnit Extensions&quot;&gt;one&lt;/a&gt; but &lt;a href=&quot;http://sourceforge.net/projects/junit-addons&quot; title=&quot;JUnit-addons&quot;&gt;two&lt;/a&gt; (if not more) general purpose libraries supporting this approach.  I distinctly remember seeing this strategy written up in pattern form.  You can find similiar write-ups &lt;a href=&quot;http://c2.com/cgi/wiki?AbstractTest&quot; title=&quot;Ward&apos;s Wiki: AbstractTest&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;http://www.cs.clemson.edu/~johnmc/new/pact/node10.html&quot; title=&quot;Pattern: Create hierarchies of parallel components&quot;&gt;here&lt;/a&gt;, but neither of those are the one I&apos;m thinking of.</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/06/24.html#a33</guid>
			<pubDate>Tue, 24 Jun 2003 13:58:20 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=33&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F06%2F24.html%23a33</comments>
			</item>
		<item>
			<title>A Frog Boiling Approach to Increasing Test Coverage</title>
			<description>&lt;p&gt;
Some thinking out loud about concrete goals for increasing test coverage.
&lt;/p&gt;&lt;p&gt;
The production (i.e., non test) Java code base at my day job consists of roughly 103,000 non-comment, non-blank lines of code, split over 132 &quot;modules&quot;.  Our automated unit test suite exercises roughly 29% of those lines.
&lt;/p&gt;&lt;p&gt;
(That 29% figure sounds a little bit worse than it feels to me.  Some areas of the code base are well tested, several are even at 100% coverage.  Others have few if any tests, but as a result of remaining essentially untouched since before a formal unit testing initiative was launched 30 months or so ago.  Yet many modules are woefully undertested, and probably not coincidentally several of those have substantial bloat--the number of lines in those modules is way out of proportion with the functionality they provide.)
&lt;/p&gt;&lt;p&gt;
Whether that 29% figure is indicative or not, it&apos;s clearly much lower than desirable.  (Personally I&apos;ve been striving for and generally achieving 100% coverage for new development.)   I&apos;ve been thinking a bit about laying out concrete goals for increasing this coverage.
&lt;/p&gt;&lt;p&gt;
We&apos;ve talked a bit about simply targeting some figure, say 80% coverage, and perhaps some intermediate goals (for example, 40%, then 60%, then 80%).
&lt;/p&gt;&lt;p&gt;
While the &quot;frog boiling&quot; approach--slowly raising the temperature on test coverage--appeals to me, something about the arbitrary &quot;percent coverage&quot; goals doesn&apos;t seem right.  I think I&apos;d prefer goals that call for complete (100%) coverage of something, perhaps with different values of &quot;something&quot;.  I&apos;m not entirely sure why.
&lt;/p&gt;&lt;p&gt;
Specifically, I&apos;m thinking of the following stages: 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All modules have tests.  Conveniently, this can be easily and quickly tested at build time.  We can make the absence of tests a build failure.  It is possible to programmatically evaluate the remaining goals, but not as quickly.  We&apos;d have to execute the test coverage check on every continuous integration build, something that may take too much time.&lt;/li&gt;
&lt;li&gt;All packages have tests.  This should be relatively easy to achieve once the first goal is reached.&lt;/li&gt;
&lt;li&gt;All classes have tests.&lt;/li&gt;
&lt;li&gt;All methods have tests.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
I&apos;m not sure where to go from that point.  Complete coverage of conditionals (every boolean expression is evaluated at least once to true and at least once to false) may be a good next step, but isn&apos;t as pithy as the other goals.  It may be that once we&apos;ve reached 100% method coverage, 100% line/statement coverage is within easy reach.  I suspect that once we&apos;ve reached that fourth goal, the next step will be pretty clear.
&lt;/p&gt;&lt;p&gt;
I wonder if any reader has some experience with similar strategies for increasing test coverage through a series of concrete goals.  What goals did you select, and why?  Did a given step turn out to be too large or too small?
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/06/23.html#a32</guid>
			<pubDate>Mon, 23 Jun 2003 17:28:51 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=32&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F06%2F23.html%23a32</comments>
			</item>
		<item>
			<title>the fixmeister role, or &apos;&apos;you, help me&apos;&apos;</title>
			<link>http://radio.weblogs.com/0122027/2003/06/17.html#a31</link>
			<description>&lt;p&gt;
In some &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/04/28.html#a26&quot; title=&quot;28 April 2003: A Little Background on our Continuous Integration Setup&quot;&gt;previous&lt;/a&gt; &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/04/29.html#a27&quot; title=&quot;29 April 2003: build cycles, development cycles, and the nag server&quot;&gt;posts&lt;/a&gt;, I discussed some of the challenges we&apos;ve experienced maintaining a &lt;a href=&quot;http://www.martinfowler.com/articles/continuousIntegration.html&quot; title=&quot;Continuous Integration by Martin Fowler and Matthew Foemmel&quot;&gt;continuous integration&lt;/a&gt; discipline at my day job.  In my last post on this topic, I alluded to &quot;additional measures&quot; which we adopted.  Time to describe what I was talking about.
&lt;/p&gt;&lt;p&gt;
Although I hadn&apos;t seen it at the time of the events described below, I recently ran across a comment on &lt;a href=&quot;http://c2.com/cgi/wiki&quot; title=&quot;Ward&apos;s Wiki: Front Page&quot;&gt;Ward&apos;s Wiki&lt;/a&gt; that accurately captures the problem we encountered and its solution:
&lt;/p&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;i&gt;There was an interesting psych study along these lines. There is one &quot;victim&quot; and several &quot;bystanders&quot;. Each of the bystanders individually would be perfectly capable of helping the victim, but since they &lt;a href=&quot;http://c2.com/cgi/wiki?NeverVolunteer&quot; title=&quot;Ward&apos;s Wiki: Never Volunteer&quot;&gt;NeverVolunteer&lt;/a&gt;, none of them do. This happens in real life situations. If you are the victim and want help, what you need to do is to pick one person from the bystanders and say to them specifically &quot;you help me&quot;. If you just do &quot;somebody help me&quot; it won&apos;t work. -- &lt;a href=&quot;http://c2.com/cgi/wiki?AndyPierce&quot; title=&quot;Ward&apos;s Wiki: Andy Pierce&quot;&gt;AndyPierce&lt;/a&gt;&lt;/i&gt; [from &lt;a href=&quot;http://c2.com/cgi/wiki?NeverVolunteer&quot; title=&quot;Ward&apos;s Wiki: Never Volunteer&quot;&gt;Never Volunteer&lt;/a&gt;]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
Toward the end of April, in the midst of one of the longer low points in our &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/04/29.html#a27&quot; title=&quot;29 April 2003: build cycles, development cycles, and the nag server&quot;&gt;development cycle&lt;/a&gt;, I sent the following (slightly edited) email to my peers on the technology management team.  At the time it felt a bit like a failure.
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
&lt;b&gt;Subject:&lt;/b&gt; build failures, and what to do about them
&lt;br /&gt;
&lt;b&gt;Sent:&lt;/b&gt; Wed 4/23/2003 10:29 AM
&lt;/p&gt;&lt;p&gt;
There was a time, not so long ago, when we would regularly see a dozen or more good integration builds per day. In fact the vast majority of builds were clean ones. (See &lt;i&gt;[internal link to an historical report on continuous integration builds]&lt;/i&gt;.)  Recently (meaning the past few months) we&apos;re lucky to see a dozen good builds in a week.  
&lt;/p&gt;&lt;p&gt;
As we&apos;ve seen rather directly the past couple of weeks, our inability to regularly integrate changes across the entire code base slows our development process, delays production releases and may threaten our ability to deliver products according to schedule.  Moreover, integration problems compound themselves.  When we go several hours (let alone several days) without a clean build, it&apos;s no longer just one problem we need to fix, but several problems that are hidden behind the first one, masked because problems in some dependent library stops the build before it discovers the later problems.
&lt;/p&gt;&lt;p&gt;
These integration problems are real problems.  A &quot;broken build&quot; means that there is some code that either doesn&apos;t work at all, doesn&apos;t work in relation to other libraries, or doesn&apos;t work outside a particular developer&apos;s (or developers&apos;) sandbox.  These problems may not impact every developer at all times, but it is quite likely they impact some developer.  It is guaranteed that they will impact the entire technology team and for that matter the entire enterprise when it comes time to release a product (and as I understand it, we have a few of those queued up in the near future).  By and large, the way in which developers avoid this problem is to simply not update their local repositories.  That&apos;s a false sense of progress if there ever was one.
&lt;/p&gt;&lt;p&gt;
Some developers have complained about this problem.  Some managers have as well.  We&apos;ve made increasingly obnoxious efforts (&lt;i&gt;[internal link to our nag servlet, as described in a &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/04/29.html#a27&quot; title=&quot;29 April 2003: build cycles, development cycles, and the nag server&quot;&gt;previous entry&lt;/a&gt;]&lt;/i&gt;) to increase the visibility of this problem, but it&apos;s not getting better.  And due to the compounding behavior described above, when it&apos;s not getting better, it&apos;s getting worse.
&lt;/p&gt;&lt;p&gt;
I propose we do the following:  For each series of build failures (that is, for every continuous sequence of failures, no matter how many underlying causes they might have) we name one arbitrarily selected developer to be &quot;on point&quot; for achieving a clean build.  Achieving a clean build becomes this developer&apos;s top priority (if they need to weasel out of it in order to something that is &quot;more important&quot;, they do that by finding someone else willing to trade slots with them).  In exchange for this responsibility, we give this developer the authority to grab whomever then need to do whatever they need to accomplish this goal.  If Alice, being on point, needs Jose&apos;s help to diagnose a problem, or needs Jose to make changes to some library in order to bring said library into sync, then this becomes Jose&apos;s top priority as well (see the &quot;weaseling out of it&quot; strategy above).  Similarly, if Alice, being on point, needs Jose to take over some task Alice would otherwise be working on, she is empowered to do that as well.
&lt;/p&gt;&lt;p&gt;
Why?
&lt;/p&gt;&lt;p&gt;
1) Having a code base that is not integrated is costing us a substantial amount of developer time, which means it&apos;s costing the company a substantial amount of money and threatening release schedules.
&lt;/p&gt;&lt;p&gt;
2) Things that are everyone&apos;s responsibility become no one&apos;s responsibility.  Actually, this isn&apos;t really it.  More accurately, when we fail to send a message that things that are everyone&apos;s responsibility are important, those things become the responsibility of a handful of truly responsible people.  There are developers who take build failures seriously, and make a well above average effort to address them.  These efforts are undermined by those who don&apos;t take build failures seriously (or insufficiently seriously), and eventually, the patience of those good Samaritans wears thin.  I know mine did several weeks ago and I&apos;ve notice a degradation in the integration quality since that time.  It was my hope that others would step up to take greater responsibility for integration builds, some did, but seemingly not enough.
&lt;/p&gt;&lt;p&gt;
&lt;i&gt;[It may seem that I&apos;m overestimating my contribution there, but I literally, personally, addressed perhaps 30% of the build failures for several months.  I looked at each and every build failure, and when it seemed no one was making progress in addressing it, I&apos;d fix it myself.  Frankly, I did this because (a) when our CI process was first initiated, there were a number of detractors that claimed this simply wouldn&apos;t work, and (b) it seems like this simply the right approach to a CI process--I&apos;d expect everyone to do more or less the same thing.]&lt;/i&gt;
&lt;/p&gt;&lt;p&gt;
3) Making fixing the build a top priority sends the message that we take continuous integration seriously, as a management team, as a development team, and as an enterprise.
&lt;/p&gt;&lt;p&gt;
4) Selecting an arbitrary developer to be on point offers a number of advantages:
&lt;/p&gt;&lt;p&gt;
a) It increases the visibility of build issues, the kinds of problems that cause them, and an effective strategy for resolving them, across the whole team.  Folks who may have never before thought about how to diagnose an arbitrary problem reported by the CI server are forced to do so.  Folks who may have never reflected on the kinds of changes that are problematic, or how to make changes in an incremental and backwards compatible way are exposed to those sorts of issues and those sorts of solutions.
&lt;/p&gt;&lt;p&gt;
b) It applies stronger peer pressure.  For quite some time I would personally &quot;nag&quot; folks to fix build issues, even sit down with them to explain the nature or the problem and the needed fix.  After a while, this nagging decreases in effectiveness, since &quot;Rod&apos;s always complaining about the build&quot;.  When several different folks in a week are nagging you to fix problems you&apos;ve caused, the pressure not to cause such problems (or to fix them on you own initiative) is increased.  When several different folks find themselves nagging the same person over and over again, the pressure on that person to improve their personal process is increased.
&lt;/p&gt;&lt;p&gt;
c) It causes greater knowledge sharing.  When put on point to fix a problem in some otherwise unknown library, a developer is forced to learn something about it, probably by pairing with someone more knowledgeable about it.  When a developer finds that they are consistently being &quot;bothered&quot; to update a library because they are the only ones that understand it, the pressure to make it more understandable or to share some of that understanding is increased.
&lt;/p&gt;&lt;p&gt;
d) Indirectly, it sends the message that fixing the build really is everyone&apos;s responsibility.  The arbitrary developer &quot;on point&quot; is simply putting a face on the team&apos;s concerns.
&lt;/p&gt;&lt;p&gt;
I&apos;d very much like to start putting people &quot;on point&quot; for fixing the build today, probably by calling an all developer meeting to explain this protocol.  I&apos;d also very much like to not have this protocol undermined by some direct or indirect message of &quot;well, that&apos;s important, but this is more important&quot; (where &quot;this&quot; is some more urgent, but not necessarily more important task).  We have more than enough developers to manage both the urgent and important tasks on our plate, and I&apos;ll argue that an approach that doesn&apos;t make integration a top if not the top priority is going to cost us in the long run.  If anyone has objections or an alternative strategy, I&apos;d love to hear about it.
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;
This strategy was well received by the management team, and was implemented almost immediately.  This strategy was less well received by some members of the development team, but there was at least grudging acceptance from everyone.
&lt;/p&gt;&lt;p&gt;
The team has come to call this role the &quot;fixmeister&quot; (a name which I&apos;m personally not very fond of).  The first fixmeister had the excellent suggestion that each subsequent fixmeister be selected by the current one, which has led to an interesting variety of selection algorithms, some whimsical, some instructional, some a bit malicious.
&lt;/p&gt;&lt;p&gt;
In the eight weeks or so since this process was initiated, we&apos;ve been around the team slightly more than once.  It&apos;s been effective in achieving the primary goal--increasing the ratio of build successes to build failures.  I&apos;d like to think it&apos;s been effective in achieving some of the harder-to-measure goals as well. (It&apos;s certainly increased awareness of the CI process among the less process oriented members of the team, and perhaps taken away some of the mystery of the process.)  Maybe time will tell on the other points.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/06/17.html#a31</guid>
			<pubDate>Tue, 17 Jun 2003 20:12:10 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=31&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F06%2F17.html%23a31</comments>
			</item>
		<item>
			<title>The Pleasures of Profiling</title>
			<description>&lt;p&gt;
Prompted by &lt;a href=&quot;http://www.nicklothian.com/&quot; title=&quot;BadMagicNumber, Nick&apos;s Weblog&quot;&gt;Nick&lt;/a&gt;&apos;s &lt;a href=&quot;http://www.nicklothian.com/blog/2003/04/29/#axion1&quot; title=&quot;29 Apr 2003: Axion&quot;&gt;post&lt;/a&gt; about &lt;a href=&quot;http://axion.tigris.org/&quot; title=&quot;Axion, an Open Source Java Relational Database Engine&quot;&gt;Axion&lt;/a&gt;&apos;s insert performance and some internal product delivery schedules, I&apos;ve been doing some profiling and tuning of Axion&apos;s performance (with some &lt;a href=&quot;http://axion.tigris.org/servlets/ReadMsg?list=dev&amp;msgNo=471&quot; title=&quot;Performance of Axion inserts&quot;&gt;good&lt;/a&gt; &lt;a href=&quot;http://axion.tigris.org/servlets/ReadMsg?list=dev&amp;msgNo=478&quot; title=&quot;btree index performance improved by ~100x&quot;&gt;results&lt;/a&gt;).  I&apos;m reminded of how much I truly enjoy this activity. 
&lt;/p&gt;&lt;p&gt;
I can tell you don&apos;t believe me, so I took some notes and wrote up &lt;a href=&quot;http://radio.weblogs.com/0122027/stories/2003/05/05/thePleasuresOfProfiling.html&quot; title=&quot;the full article&quot;&gt;a brief account&lt;/a&gt;.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/05/05.html#a29</guid>
			<pubDate>Mon, 05 May 2003 21:52:21 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=29&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F05%2F05.html%23a29</comments>
			</item>
		<item>
			<title>Unit tests with log statements are a code smell</title>
			<description>&lt;p&gt;
While this is not an earth shattering realization, I&apos;ve come hold the opinion that log statements (&lt;a href=&quot;http://jakarta.apache.org/log4j/&quot; title=&quot;jakarta.apache.org/log4j&quot;&gt;log4j&lt;/a&gt;, &lt;a href=&quot;http://avalon.apache.org/logkit/&quot; title=&quot;avalon.apache.org/logkit&quot;&gt;logkit&lt;/a&gt;, &lt;a href=&quot;http://java.sun.com/j2se/1.4.1/docs/api/java/util/logging/package-summary.html&quot; title=&quot;javadocs for java.util.logging&quot;&gt;java.util.logging&lt;/a&gt;, &lt;a href=&quot;http://jakarta.apache.org/commons/logging/&quot; title=&quot;jakarta.apache.org/commons/logging&quot;&gt;commons-logging&lt;/a&gt;, what have you) within unit tests are a &lt;a href=&quot;http://c2.com/cgi/wiki?CodeSmell&quot; title=&quot;Ward&apos;s Wiki: CodeSmell&quot;&gt;code smell&lt;/a&gt;, perhaps universally.  
&lt;/p&gt;&lt;p&gt;
While I&apos;ll sometimes add a few System.out.println calls to a unit test while I&apos;m trying to diagnose a particular failure, configuring a full-blown logging setup within a unit test always seemed like more time and trouble than it was worth. From time to time I&apos;ll encounter a heavily logged TestCase in some code base I&apos;m working with.  The more I work with such TestCases, the more I find this to be an indication that something is not right.
&lt;/p&gt;&lt;p&gt;
Here&apos;s why:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I find it hard to imagine a test first/test driven development approach that leads to log statements within unit tests (but I can imagine &quot;test last&quot; approaches that will). The presence of logging strongly suggests that the tested code was not developed in a test driven fashion.&lt;/li&gt;
&lt;li&gt;The role of logging frameworks and that of automated unit testing frameworks are at odds.  Logging calls provide persistent, if only intermittently used, diagnostic and informational messages, typically intended for manual inspection &lt;sup&gt;&lt;a href=&quot;#n28.1&quot;&gt;*&lt;/a&gt;&lt;/sup&gt;.  Automated unit tests are meant to be self-interpreting, success or failure should be obvious without manual inspection.  The use of diagnostic or informational log messages within unit tests suggests your tests aren&apos;t sufficiently self-interpreting.&lt;/li&gt;
&lt;li&gt;Anecdotally, the objects being tested by these cases are brittle in the face of change.  This may stem from poor factoring: there are too many subtle and perhaps unplanned interactions between methods, or methods aren&apos;t well focused enough to allow for orthogonal changes.&lt;/li&gt;
&lt;li&gt;Anecdotally, test failures remain difficult to diagnose and fix despite the log messages. This also stems from poor factoring: the individual test cases and assertions are too coarse grained to help identify the root cause of a test failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;footnote&quot;&gt;&lt;p&gt;&lt;a name=&quot;n28.1&quot;&gt;*&lt;/a&gt; If you find yourself wanting programmatic inspection of log messages, I&apos;ll suggest you&apos;re looking for messaging, not logging.&lt;/p&gt;&lt;/div&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/05/02.html#a28</guid>
			<pubDate>Fri, 02 May 2003 18:15:02 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=28&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F05%2F02.html%23a28</comments>
			</item>
		<item>
			<title>build cycles, development cycles, and the nag server</title>
			<link>http://radio.weblogs.com/0122027/2003/04/29.html#a27</link>
			<description>&lt;p&gt;
One thing I&apos;ve noticed about &lt;a href=&quot;http://radio.weblogs.com/0122027/2003/04/28.html#a26&quot; title=&quot;28 April 2003: A Little Background on our Continuous Integration Setup&quot;&gt;our continuous integration process&lt;/a&gt; and its meta-process is that both are cyclical.  Here&apos;s three examples:
&lt;/p&gt;
&lt;a name=&quot;whenItRains&quot;&gt;&lt;/a&gt;&lt;h3&gt;..FF...FFFFFFFFFF...., or when it rains, it pours&lt;/h3&gt;
&lt;p&gt;
One of the first things you notice when applying a continuous integration process to parallel development is that integration problems compound themselves.  (This isn&apos;t a side effect of continuous integration, CI simply makes this point clear.)
&lt;/p&gt;&lt;p&gt;
On most days we&apos;ll have (indeed, we expect) the occasional build failure--someone neglected to check in a file here, or forgot that component was using this method whose signature has changed, etc.  On good days, the team is on its collective toes and responds quickly to the failure notice.  The problems are resolved in a build or two and we&apos;re right back on track.  On bad days, an integration problem will persist for several builds, and as yet undiscovered and unreported problems will begin to queue up behind the first one as folks continue to make commits.  The longer the queue of integration problems get, the longer it gets.  As a result, bad days have a nasty habit of turning into bad weeks.
&lt;/p&gt;&lt;p&gt;
Anecdotally, the tipping point seems to be around three consecutive build failures.  When we hit the third consecutive failure, the odds of hitting a fourth, a fifth, or even a tenth failure seems to increase dramatically.  I think there are at least two reasons for this:  (1) Unless the developers notice and fix the problem on their own--independent of the CI build failure notifications--failures will almost always come in pairs.  By the time the nag email is delivered, let alone diagnosed and fixed, a second build will already be in progress.  If the problem is going to be fixed &quot;immediately&quot;, then it will be fixed for the third build, but generally not before it. (2) Depending upon the specific component that encounters problems, a failed build takes 20 to 40 minutes.  Three consecutive failures means its been an hour, maybe two, since our last complete build.  On a busy day we can have quite a few commits in an hour, so the number of unintegrated changes grows quickly.  All of these changes need to be addressed before we reach a successful build.
&lt;/p&gt;
&lt;a name=&quot;twoStepsForward&quot;&gt;&lt;/a&gt;&lt;h3&gt;two steps forward, one step back&lt;/h3&gt;
&lt;p&gt;
We&apos;ve found that our CI process doesn&apos;t progress monotonically.  We&apos;re constantly trying to strike a balance between the functionality provided by the CI builds, the time it takes to complete a build cycle, and the likelihood of extraneous build failures.  Often we find that we&apos;ve stretched a bit too far and need to pull back.
&lt;/p&gt;&lt;p&gt;
Often the time it takes to complete a build is a driving factor.  For a time we generated and published JavaDoc documentation and various source code and test coverage metrics following every successful build, but we found this added too much time to the build cycle.  (As discussed &lt;a href=&quot;#whenItRains&quot; title=&quot;when it rains, it pours&quot;&gt;above&lt;/a&gt;, the longer changes wait to be integrated, the greater our exposure to risk.)  Instead, we rely upon cron-driven or manual processes to generate these artifacts.
&lt;/p&gt;&lt;p&gt;
At times, and to my great frustration, we&apos;ve had to remove aspects of the build that were simply too brittle for continuous use.  Our &lt;a href=&quot;http://jakarta.apache.org/commons/latka&quot; title=&quot;Apache&apos;s Jakarta Commons Latka&quot;&gt;Latka&lt;/a&gt;-based functional test suite, which tests a number of our web applications, was largely removed from the CI builds largely because of test rot and the instabilities introduced by being too dependent upon external services that change outside of the build process (database servers are one, although not the only example here).  The CI process still deploys our web based applications, but leaves most of the functional testing to manual invocation.
&lt;/p&gt;
&lt;h3&gt;the nag server&lt;/h3&gt;
&lt;p&gt;
From time to time we find that the discipline of continuous integration begins to slip: successful builds become less frequent and broken builds are fixed more slowly.  The team gets used to seeing frequent build failures, begins ignoring nag messages, becomes complacent, and tends to look for local workarounds rather than addressing the global integration issues.  (This is an instance of the &lt;a href=&quot;http://www.c2.com/cgi/wiki?FixBrokenWindows&quot; title=&quot;Ward&apos;s Wiki: FixBrokenWindows&quot;&gt;fix broken windows&lt;/a&gt; pattern.)  Despite what Fowler will tell you, in my experience there are some developers who are more than happy to give up the benefits of a continuous integration process, or who fail to recognize what those benefits are in the first place.  (Perhaps not coincidentally, many of these developers haven&apos;t been working here as long as the CI process has.)  In part these cycles are an extension of the cycles above--cruft and insufficiently considered work-arounds build up until the code base is fundamentally brittle.   In part these cycles are related to the evolution of the code base--major, cross-component refactorings and shotgun maintenance sometimes lead to periods of build instability.  We&apos;ve found that whatever the cause sometimes the team needs a little kick to get back on track.  
&lt;/p&gt;&lt;p&gt;
&lt;a href=&quot;http://radio.weblogs.com/0116794/&quot; title=&quot;Weblog: Morgan Delagrange&quot;&gt;Morgan&lt;/a&gt; recently suggested one pleasingly simple kick of this sort.  While discussing a low point in our CI cycle, Morgan half-jokingly suggested that what we needed was a &quot;nag server&quot;--a giant, prominently located monitor that displays the status of the current build.  We jumped on it literally immediately, grabbed the biggest monitor we could find and an underused server; and set them up in the hallway in front of the primary development cube farm with a web browser continuously refreshing a simplier, bigger and bolder version of our build status page.  Morgan later added an automated count of the number of consecutive build failures or successes (replacing a flip chart we manually updated for a while).
&lt;/p&gt;&lt;p&gt;
The nag server worked rather well for a while--it improved the build success:failure ratio and increased the visibility of the continuous integration process both within the development team and among the &quot;customer&quot; team.  We often find developers gathered around the nag server discussing the current integration problem or checking to see if their changes made it into the current build.  Unfortunately, the nag server eventually became less effective as a motivational tool.  Additional measures seemed necessary.  More on that in a later post.
&lt;/p&gt;</description>
			<guid isPermaLink="false">http://radio.weblogs.com/0122027/categories/java/2003/04/29.html#a27</guid>
			<pubDate>Wed, 30 Apr 2003 01:32:15 GMT</pubDate>
			<comments>http://radiocomments2.userland.com/comments?u=122027&amp;amp;p=27&amp;amp;link=http%3A%2F%2Fradio.weblogs.com%2F0122027%2F2003%2F04%2F29.html%23a27</comments>
			</item>
		</channel>
	</rss>
