<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><id>tag:blogger.com,1999:blog-6500374844252313496</id><updated>2008-05-14T21:08:19.895+01:00</updated><title type="text">The Build Doctor</title><link rel="alternate" type="text/html" href="http://www.build-doctor.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default?start-index=26&amp;max-results=25&amp;redirect=false" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.build-doctor.com/feeds/posts/default" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>44</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><logo>http://creativecommons.org/images/public/somerights20.gif</logo><link rel="self" href="http://feeds.feedburner.com/TheBuildDoctor" type="application/atom+xml" /><feedburner:emailServiceId>1516867</feedburner:emailServiceId><feedburner:feedburnerHostname>http://www.feedburner.com</feedburner:feedburnerHostname><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-7952133083453237827</id><published>2008-05-14T16:08:00.006+01:00</published><updated>2008-05-14T21:08:20.464+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="visual studio" /><category scheme="http://www.blogger.com/atom/ns#" term="ci" /><category scheme="http://www.blogger.com/atom/ns#" term="build" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><title type="text">Unclean.  (does your CI server have an IDE installed on it?)</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_-rlZcQ-7nAM/SCtF0NXoo5I/AAAAAAAAAEI/IePBdGVLp3s/s1600-h/291408024_26fbf43fa3_o.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_-rlZcQ-7nAM/SCtF0NXoo5I/AAAAAAAAAEI/IePBdGVLp3s/s400/291408024_26fbf43fa3_o.png" alt="" id="BLOGGER_PHOTO_ID_5200326957973676946" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;(image taken from &lt;a href="http://flickr.com/photos/subflux/archives/date-posted/2006/11/07/"&gt;&lt;span style="font-size:85%;"&gt;SubFlux's photostream&lt;/span&gt;&lt;/a&gt;)&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Your build shouldn't depend on an IDE.  I've been saying that for a long time.  It doesn't matter that all the developers use the same IDE on your project.  At least in the Java world that I have inhabited for most of the past 8 years, you absolutely should not need an IDE installed on your build server.&lt;br /&gt;&lt;br /&gt;Yesterday I installed an IDE on the build server.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blog.goinsane.co.uk/2008/01/28/TeamCityOnACleanBuildCIServer.aspx"&gt;Casey Charlton&lt;/a&gt; and I both agree that in an ideal world, there's no connection between the build and the IDE.  I've been trying to find a reference to the "thou shalt not install an IDE on the damn build server" rule.  I've found a pretty authoritative quote from &lt;a href="http://www.amazon.com/Continuous-Integration-Improving-Addison-Wesley-Signature/dp/0321336380"&gt;Paul Duvall's book&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;You should avoid coupling your build scripts with an IDE.  An IDE may be dependent on a build script, but &lt;span style="font-style: italic;"&gt;a build script shouldn't be dependent on your IDE&lt;/span&gt;.  ....  Creating a seperate build script is important for two reasons:&lt;br /&gt;&lt;br /&gt;1. Each developer may be using a different IDE, and it can be difficult to to account for configuration differences in each IDE.&lt;br /&gt;&lt;br /&gt;2. A CI server must execute an automated build without human intervention.  Therefore, the same automated build script used by developers can and should be used by the CI server...&lt;/blockquote&gt;As usual, Paul is bang on.  But my issue at the moment is Visual Studio.  Not that I can't write code in it (I haven't really tried), but the fact that it's actually more than an IDE in the traditional sense.  It's also the container for the testing framework.  It's almost the entire stack.  It comes with Crystal Reports (which I'm happy to say I didn't install), and other stacks of middleware.  Which you need to build your app.  Ever tried to build a VSTO app?  You need Visual Studio.&lt;br /&gt;&lt;br /&gt;In theory, you don't need it, because the build tool for Microsoft Products (MSBuild) comes with the .NET framework.  But it seems like in practice, you do.&lt;br /&gt;&lt;br /&gt;So I installed it.  And the build works, without me fiddling with the GAC.  I can live with that. What works for you?&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=WyBH8H"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=WyBH8H" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=KsAJHh"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=KsAJHh" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=gTn7gh"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=gTn7gh" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=e7Vtfh"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=e7Vtfh" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/290415577/unclean-does-your-ci-server-have-ide.html" title="Unclean.  (does your CI server have an IDE installed on it?)" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=7952133083453237827" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/7952133083453237827/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/7952133083453237827" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/7952133083453237827" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/05/unclean-does-your-ci-server-have-ide.html</feedburner:origLink></entry><entry><title type="text">Links for 2008-05-13 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/289929855/www_build_doctor_com" /><updated>2008-05-14T00:00:00-05:00</updated><id>http://del.icio.us/www_build_doctor_com#2008-05-13</id><summary type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/rjacobs/archive/2008/05/12/living-through-the-change.aspx?CommentPosted=true#commentmessage"&gt;Ron Jacobs : Living through &amp;quot;The Change&amp;quot;&lt;/a&gt;&lt;br/&gt;
Dealing with change.  Planning for it, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://channel9.msdn.com/wiki/default.aspx/MSBuild.EquivalentTasks"&gt;Channel9 Wiki: EquivalentTasks&lt;/a&gt;&lt;br/&gt;
nant vs. msbuild:&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msbuildtasks.tigris.org/"&gt;MSBuild Community Tasks&lt;/a&gt;&lt;br/&gt;
The MSBuild  tasks that Microsoft didn't make.&lt;/li&gt;
&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/rjacobs/archive/2008/05/12/living-through-the-change.aspx?CommentPosted=true#commentmessage"&gt;Ron Jacobs : Living through &amp;quot;The Change&amp;quot;&lt;/a&gt;&lt;br/&gt;
Dealing with change.  Planning for it, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://channel9.msdn.com/wiki/default.aspx/MSBuild.EquivalentTasks"&gt;Channel9 Wiki: EquivalentTasks&lt;/a&gt;&lt;br/&gt;
nant vs. msbuild:&lt;/li&gt;
&lt;li&gt;&lt;a href="http://msbuildtasks.tigris.org/"&gt;MSBuild Community Tasks&lt;/a&gt;&lt;br/&gt;
The MSBuild  tasks that Microsoft didn't make.&lt;/li&gt;
&lt;/ul&gt;</content><feedburner:origLink>http://del.icio.us/www_build_doctor_com#2008-05-13</feedburner:origLink></entry><entry><title type="text">Links for 2008-05-12 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/289187937/www_build_doctor_com" /><updated>2008-05-13T00:00:00-05:00</updated><id>http://del.icio.us/www_build_doctor_com#2008-05-12</id><summary type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.thecrumb.com/wiki/Ant"&gt;ant [thecrumb wiki]&lt;/a&gt;&lt;br/&gt;
Jim Priest's collection of Ant resources, including his own blog posts.&lt;/li&gt;
&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.thecrumb.com/wiki/Ant"&gt;ant [thecrumb wiki]&lt;/a&gt;&lt;br/&gt;
Jim Priest's collection of Ant resources, including his own blog posts.&lt;/li&gt;
&lt;/ul&gt;</content><feedburner:origLink>http://del.icio.us/www_build_doctor_com#2008-05-12</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-535294612067962429</id><published>2008-05-12T22:59:00.003+01:00</published><updated>2008-05-12T23:10:00.025+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="best practices" /><category scheme="http://www.blogger.com/atom/ns#" term="dependencies" /><category scheme="http://www.blogger.com/atom/ns#" term="build" /><category scheme="http://www.blogger.com/atom/ns#" term="ant" /><title type="text">Ant Best Practices: Define Proper Target Dependencies</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_-rlZcQ-7nAM/SCi_WtXoo4I/AAAAAAAAAEA/cdu6IrGdfDA/s1600-h/280662707_5d335ac808.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_-rlZcQ-7nAM/SCi_WtXoo4I/AAAAAAAAAEA/cdu6IrGdfDA/s320/280662707_5d335ac808.jpg" alt="" id="BLOGGER_PHOTO_ID_5199616166655992706" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;(Image taken from &lt;a href="http://flickr.com/photos/nicksieger/"&gt;Nick Sieger's Photostream&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;Wondering what this post is about?  Have a look &lt;a href="http://www.build-doctor.com/2008/04/ant-best-practices-series.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Last time I wrote, it was about &lt;a href="http://www.build-doctor.com/2008/05/ant-best-practices-define-and-reuse.html"&gt;reusing paths&lt;/a&gt;.  Tonight, it's about the dependency graph. My &lt;a href="http://www.build-doctor.com/2008/02/antcall-is-evil.html"&gt;[N]Antcall is evil&lt;/a&gt; post goes into some detail about dependency graphs.  Let's just agree here that Ant targets tend to accumulate dependencies.  The point that Eric makes is that the dependency graph (otherwise known as the dependency tree) grows over time as you add targets.  Being a thing that accumulates over time, the graph can get crufty.  That target that was just a short term thing while Bob worked on a refactoring exercise (oh, the irony) is now central to your build.  So from time to time you need to clean the dependencies out, like that burned cheese that melts off of pizzas and sticks to the bottom of the oven.&lt;br /&gt;&lt;br /&gt;Some projects seem to run into trouble and throw dependencies out completely.  Umm, good luck with that.  Eric suggests a half-way house approach: a few well known targets that contain dependencies on lesser known but functional targets for the more experienced to use at their own risk.  I can go along with that.&lt;br /&gt;&lt;br /&gt;My last thought is this: your default build should never depend on a &lt;a href="http://www.build-doctor.com/2008/04/ant-best-practices-provide-clean-target.html"&gt;clean target&lt;/a&gt;.  Leave it to the compiler to have a go at working out what it should do.  If you use Continuous Integration, you can make a little target that depends on clean just for that case.  Your fellow developers will thank you.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=wU6THH"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=wU6THH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=GAfWPh"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=GAfWPh" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=VvwFGh"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=VvwFGh" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=EqHQYh"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=EqHQYh" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/288993275/ant-best-practices-define-proper-target.html" title="Ant Best Practices: Define Proper Target Dependencies" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=535294612067962429" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/535294612067962429/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/535294612067962429" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/535294612067962429" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/05/ant-best-practices-define-proper-target.html</feedburner:origLink></entry><entry><title type="text">Links for 2008-05-10 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/287870592/www_build_doctor_com" /><updated>2008-05-11T00:00:00-05:00</updated><id>http://del.icio.us/www_build_doctor_com#2008-05-10</id><summary type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://testerbydaydeveloperbynight.blogspot.com/2008/05/automated-deployment-why-it-is-good.html"&gt;I've come up with a quick test you can do to see if you should automate your deployment process.&lt;/a&gt;&lt;br/&gt;
Cautionary tales&lt;/li&gt;
&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://testerbydaydeveloperbynight.blogspot.com/2008/05/automated-deployment-why-it-is-good.html"&gt;I've come up with a quick test you can do to see if you should automate your deployment process.&lt;/a&gt;&lt;br/&gt;
Cautionary tales&lt;/li&gt;
&lt;/ul&gt;</content><feedburner:origLink>http://del.icio.us/www_build_doctor_com#2008-05-10</feedburner:origLink></entry><entry><title type="text">Links for 2008-05-09 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/287298244/www_build_doctor_com" /><updated>2008-05-10T00:00:00-05:00</updated><id>http://del.icio.us/www_build_doctor_com#2008-05-09</id><summary type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://modrails.com/"&gt;Phusion Passenger (a.k.a. mod_rails) - apache module for rails&lt;/a&gt;&lt;br/&gt;
When did this arrive?  Being able to roll out apaches that just know how to talk to rails could be the thing. This could be huge.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.testearly.com/2007/06/20/running-mstest-against-net-20-on-cruisecontrolnet/"&gt;Test Early &amp;raquo; Running MSTest against .NET 2.0 on CruiseControl.NET&lt;/a&gt;&lt;br/&gt;
This does point to the fact that you either need to install the whole MS toolchain on your build server, or spend a day cheerfully sticking dependencies in the GAC or on Program Files dir. Eeek.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2007/04/26/get-a-build-server-and-keep-it-clean.aspx"&gt;Get a Build Server and Keep it Clean - Jeremy D. Miller -- The Shade Tree Developer&lt;/a&gt;&lt;br/&gt;
sadly this may no longer be feasible.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www-128.ibm.com/developerworks/java/library/j-ap09056/index.html"&gt;Automation for the people: Choosing a Continuous Integration server&lt;/a&gt;&lt;br/&gt;
Paul Duvall article on choosing a CI server.  How far things have come in 2 years....&lt;/li&gt;
&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://modrails.com/"&gt;Phusion Passenger (a.k.a. mod_rails) - apache module for rails&lt;/a&gt;&lt;br/&gt;
When did this arrive?  Being able to roll out apaches that just know how to talk to rails could be the thing. This could be huge.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.testearly.com/2007/06/20/running-mstest-against-net-20-on-cruisecontrolnet/"&gt;Test Early &amp;raquo; Running MSTest against .NET 2.0 on CruiseControl.NET&lt;/a&gt;&lt;br/&gt;
This does point to the fact that you either need to install the whole MS toolchain on your build server, or spend a day cheerfully sticking dependencies in the GAC or on Program Files dir. Eeek.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2007/04/26/get-a-build-server-and-keep-it-clean.aspx"&gt;Get a Build Server and Keep it Clean - Jeremy D. Miller -- The Shade Tree Developer&lt;/a&gt;&lt;br/&gt;
sadly this may no longer be feasible.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www-128.ibm.com/developerworks/java/library/j-ap09056/index.html"&gt;Automation for the people: Choosing a Continuous Integration server&lt;/a&gt;&lt;br/&gt;
Paul Duvall article on choosing a CI server.  How far things have come in 2 years....&lt;/li&gt;
&lt;/ul&gt;</content><feedburner:origLink>http://del.icio.us/www_build_doctor_com#2008-05-09</feedburner:origLink></entry><entry><title type="text">Links for 2008-05-08 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/286579035/www_build_doctor_com" /><updated>2008-05-09T00:00:00-05:00</updated><id>http://del.icio.us/www_build_doctor_com#2008-05-08</id><summary type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://open.controltier.com/"&gt;Open Source Tools for IT Automation&lt;/a&gt;&lt;br/&gt;
Anyone ever tried this?&lt;/li&gt;
&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://open.controltier.com/"&gt;Open Source Tools for IT Automation&lt;/a&gt;&lt;br/&gt;
Anyone ever tried this?&lt;/li&gt;
&lt;/ul&gt;</content><feedburner:origLink>http://del.icio.us/www_build_doctor_com#2008-05-08</feedburner:origLink></entry><entry><title type="text">Links for 2008-05-07 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/285842660/www_build_doctor_com" /><updated>2008-05-08T00:00:00-05:00</updated><id>http://del.icio.us/www_build_doctor_com#2008-05-07</id><summary type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.perfectapi.com/2008/05/how-building-bridge-is-same-as-building.html"&gt;Thoughts in the Wilderness: How building a bridge is the same as building software&lt;/a&gt;&lt;br/&gt;
I was about to scream: &amp;quot;the civil engineering metaphor is not appropriate for software engineering&amp;quot;!. But that would just make me sound shrill, and the man does have a point about the deployment being where the rubber hits the road.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.build-doctor.com/2008/05/git-coming-to-windows-computer-near-you.html"&gt;Git - coming to a Windows computer near you?&lt;/a&gt;&lt;br/&gt;
The skinny is that there's a Google Summer of Code project to implement (i read that this meant, not port) Git to C# to support windows and mono. sweet.&lt;/li&gt;
&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.perfectapi.com/2008/05/how-building-bridge-is-same-as-building.html"&gt;Thoughts in the Wilderness: How building a bridge is the same as building software&lt;/a&gt;&lt;br/&gt;
I was about to scream: &amp;quot;the civil engineering metaphor is not appropriate for software engineering&amp;quot;!. But that would just make me sound shrill, and the man does have a point about the deployment being where the rubber hits the road.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.build-doctor.com/2008/05/git-coming-to-windows-computer-near-you.html"&gt;Git - coming to a Windows computer near you?&lt;/a&gt;&lt;br/&gt;
The skinny is that there's a Google Summer of Code project to implement (i read that this meant, not port) Git to C# to support windows and mono. sweet.&lt;/li&gt;
&lt;/ul&gt;</content><feedburner:origLink>http://del.icio.us/www_build_doctor_com#2008-05-07</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-2448701593626971550</id><published>2008-05-07T09:27:00.003+01:00</published><updated>2008-05-07T09:33:51.241+01:00</updated><title type="text">Git - coming to a Windows computer near you?</title><content type="html">&lt;a href="http://www.mono-project.com/"&gt;Mono&lt;/a&gt; founder Miguel de Icaza just &lt;a href="http://twitter.com/migueldeicaza/statuses/805262145"&gt;twittered&lt;/a&gt; about a Google &lt;a href="http://code.google.com/soc/2008/"&gt;Summer of Code&lt;/a&gt; project called Git# - implemented in C#, with no platform dependencies.  Git is a powerful &lt;a href="http://en.wikipedia.org/wiki/Distributed_revision_control"&gt;Distributed Version Control&lt;/a&gt; system that came from &lt;a href="http://kerneltrap.org/node/4982"&gt;Linus Torvalds&lt;/a&gt;.  While you can convince it to run on Windows, it has dependencies on the Unix toolchain.  This project could change all that.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=Z2sSwH"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=Z2sSwH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=IMczch"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=IMczch" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=5ZMhRh"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=5ZMhRh" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=BW3Jjh"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=BW3Jjh" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/285229261/git-coming-to-windows-computer-near-you.html" title="Git - coming to a Windows computer near you?" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=2448701593626971550" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/2448701593626971550/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/2448701593626971550" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/2448701593626971550" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/05/git-coming-to-windows-computer-near-you.html</feedburner:origLink></entry><entry><title type="text">Links for 2008-05-06 [del.icio.us]</title><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/285118940/www_build_doctor_com" /><updated>2008-05-07T00:00:00-05:00</updated><id>http://del.icio.us/www_build_doctor_com#2008-05-06</id><summary type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://gojko.net/fitnesse/dbfit/"&gt;Gojko Adzic &amp;raquo; DbFit: Test-driven database development&lt;/a&gt;&lt;br/&gt;
Got a testing framework that's all row and column oriented?  Got sprocs that are hard to test? You need this.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://tsqlunit.sourceforge.net/"&gt;TSQLUnit testing framework&lt;/a&gt;&lt;br/&gt;
How to unit tests sprocs in SQL Server.&lt;/li&gt;
&lt;/ul&gt;</summary><content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href="http://gojko.net/fitnesse/dbfit/"&gt;Gojko Adzic &amp;raquo; DbFit: Test-driven database development&lt;/a&gt;&lt;br/&gt;
Got a testing framework that's all row and column oriented?  Got sprocs that are hard to test? You need this.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://tsqlunit.sourceforge.net/"&gt;TSQLUnit testing framework&lt;/a&gt;&lt;br/&gt;
How to unit tests sprocs in SQL Server.&lt;/li&gt;
&lt;/ul&gt;</content><feedburner:origLink>http://del.icio.us/www_build_doctor_com#2008-05-06</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-7055857001074514735</id><published>2008-05-05T22:15:00.006+01:00</published><updated>2008-05-05T22:35:10.721+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="paths" /><category scheme="http://www.blogger.com/atom/ns#" term="best practices" /><category scheme="http://www.blogger.com/atom/ns#" term="build" /><category scheme="http://www.blogger.com/atom/ns#" term="ant" /><category scheme="http://www.blogger.com/atom/ns#" term="fileset" /><title type="text">Ant Best Practices: Define and Reuse Paths</title><content type="html">&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_-rlZcQ-7nAM/SB99L3DartI/AAAAAAAAAD4/eTVVT0jBpWo/s1600-h/839051567_dd38dc0fb3.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_-rlZcQ-7nAM/SB99L3DartI/AAAAAAAAAD4/eTVVT0jBpWo/s320/839051567_dd38dc0fb3.jpg" alt="" id="BLOGGER_PHOTO_ID_5197010137719156434" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:85%;"&gt;(image taken from &lt;a href="http://www.flickr.com/photos/10483052@N00/"&gt;justpic's photostream&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;a href="http://www.build-doctor.com/2008/04/ant-best-practices-manage-dependencies.html"&gt;Last time&lt;/a&gt;, we discussed dependencies.  Today's installment of &lt;a href="http://www.build-doctor.com/2008/04/ant-best-practices-series.html"&gt;Ant Best Practices&lt;/a&gt; is purportedly about resusing filesets by reference ID, but it's really another way to avoid duplication.  The title of Eric's original article is 'Define and Reuse Paths'.  The same advice works for paths, filesets, and filtersets.  Here's an example:&lt;br /&gt; &lt;pre&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;project&lt;/span&gt; &lt;span class="attribute"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;OnceAndOnlyOnce&lt;span class="punct"&gt;"&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;fileset&lt;/span&gt; &lt;span class="attribute"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;&lt;span class="string"&gt;output_files&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="attribute"&gt;dir&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;&lt;span class="string"&gt;${build.dir}&lt;/span&gt;&lt;span class="punct"&gt;"&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;include&lt;/span&gt; &lt;span class="attribute"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;&lt;span class="string"&gt;duplicato-*.jar&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="punct"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;fileset&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;target&lt;/span&gt; &lt;span class="attribute"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;&lt;span class="string"&gt;copy_stuff&lt;/span&gt;&lt;span class="punct"&gt;"&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;copy&lt;/span&gt; &lt;span class="attribute"&gt;todir&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;&lt;span class="string"&gt;${special.shiny.dir}&lt;/span&gt;&lt;span class="punct"&gt;"&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;fileset&lt;/span&gt; &lt;span class="attribute"&gt;refid&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;&lt;span class="string"&gt;output_files&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="punct"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;copy&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;project&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt; You can see that any other use of the fileset will be able to refer to it by ID, rather than explicitly declare it again.  One of the scariest builds that I ever saw was 4,000 lines of XML in a single file.  One of my erstwhile colleagues spent a morning going through it and replacing filterset declarations with references to one filterset.  It's such a useful feature to have in a build tool, and a fine piece of advice to give to someone who just started out writing build scripts.&lt;br /&gt;&lt;br /&gt;The other point from the original article is that you need to use this technique alongside some modular approach to handling paths.  You just can't really get away with having a path named '&lt;span style="font-weight: bold;"&gt;standard.jars.classpath.without.selenium&lt;/span&gt;' (and yes, that's almost directly lifted from the build of a large Java project).  You're much better off trying to split things like classpaths into categories like build-time and runtime.  That's something I touched on in my article for the ThoughtWorks Anthology.  I'm thinking of expanding on it in a future post.  You like that idea?  &lt;a href="http://www.build-doctor.com/2008/04/how-to-get-repeat-prescriptions-from.html"&gt;Let me know&lt;/a&gt;.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=tCloRH"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=tCloRH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=thT1Ah"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=thT1Ah" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=rYw5ch"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=rYw5ch" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=6lI4Vh"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=6lI4Vh" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/284203067/ant-best-practices-define-and-reuse.html" title="Ant Best Practices: Define and Reuse Paths" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=7055857001074514735" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/7055857001074514735/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/7055857001074514735" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/7055857001074514735" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/05/ant-best-practices-define-and-reuse.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-9187825611696143825</id><published>2008-04-28T22:45:00.006+01:00</published><updated>2008-04-29T20:43:16.186+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="scm" /><category scheme="http://www.blogger.com/atom/ns#" term="perforce" /><category scheme="http://www.blogger.com/atom/ns#" term="vcs" /><title type="text">How to find out what files aren't added in your Perforce client</title><content type="html">&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_-rlZcQ-7nAM/SBcJD3DarsI/AAAAAAAAADw/ff8yzz-9F8Q/s1600-h/183855514_2952baadf2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_-rlZcQ-7nAM/SBcJD3DarsI/AAAAAAAAADw/ff8yzz-9F8Q/s320/183855514_2952baadf2.jpg" alt="" id="BLOGGER_PHOTO_ID_5194630657117695682" border="0" /&gt;&lt;/a&gt;(image taken from &lt;a href="http://flickr.com/photos/jparise/"&gt;jparise's photstream&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;I've first used Perforce in 2002.  At the time we were using another product.  Perforce was about 10 times as fast and 10 times less likely to make me want to storm into the comms room, rip the source code server out the rack and drop it off the fire escape into the street.  It was also atomic.&lt;br /&gt;&lt;br /&gt;A lot has changed in the intervening years.  Subversion has come of age, distributed version control has become the next new thing, and I don't have access to the comms room any more.  Oh, and I'm using Perforce again.  One thing I miss is Subversion's ability to tell you the status of all files in the sandbox (which is roughly equivalent to a P4 client), including unversioned ones:&lt;br /&gt;&lt;blockquote&gt;graham-tackleys-mac-mini:~/Documents/workspace/playpen jsimpson$ svn st&lt;br /&gt;?      a.html&lt;br /&gt;?      pack.sh&lt;/blockquote&gt;In this instance, you can tell that 'a.html' and 'pack.sh' aren't versioned in Subversion because they have a status of '?'.&lt;br /&gt;&lt;br /&gt;What do you do for the Perforce command line client?  If you're a Windows user, you can do this:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;dir /s/b/a-d | p4 -x- have &gt; nul: 2&gt;missing.txt &lt;/blockquote&gt;&lt;br /&gt;The part to the left of the pipe  (the '|' symbol) gives you a list of all the file in your current working directory.  The part to the right of the pipe queries perforce to see if the files are in the repository.  Any files that are in the repository get binned, whereas any files that aren't get written to the missing.txt file with the dreaded Perforce error message:  &lt;span style="font-style: italic;"&gt;file(s) not on client.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Unix users can try this one:&lt;br /&gt;&lt;blockquote&gt;find . -type f | p4 -x- have &gt; /dev/null 2&gt;missing.txt&lt;/blockquote&gt;&lt;br /&gt;This valuable snippet comes from Laura Wingerd's &lt;a href="http://books.google.co.uk/books?id=mlm61wb2v3MC&amp;amp;dq=practical+perforce&amp;amp;pg=PP1&amp;amp;ots=IWq5ASOnSC&amp;amp;sig=-mHsA7zM-Hh7Jt71RPn2w0y9E1Y&amp;amp;hl=en&amp;amp;prev=http://www.google.co.uk/search?q=practical+perforce&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;rls=org.mozilla:en-GB:official&amp;amp;client=firefox-a&amp;amp;sa=X&amp;amp;oi=print&amp;amp;ct=title&amp;amp;cad=one-book-with-thumbnail"&gt;definitive work&lt;/a&gt; on Perforce.  Is there another Perforce one-liner that you can't live without? &lt;a href="http://www.build-doctor.com/2008/04/how-to-get-repeat-prescriptions-from.html"&gt;Let us know&lt;/a&gt;!&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=CDTsRG"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=CDTsRG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=Gvgymg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=Gvgymg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=7joeAg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=7joeAg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=I8d3vg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=I8d3vg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/280046079/how-to-find-out-what-files-arent-added.html" title="How to find out what files aren't added in your Perforce client" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=9187825611696143825" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/9187825611696143825/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/9187825611696143825" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/9187825611696143825" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/04/how-to-find-out-what-files-arent-added.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-2200789020016118142</id><published>2008-04-28T21:59:00.003+01:00</published><updated>2008-04-28T22:35:35.718+01:00</updated><title type="text">How to get repeat prescriptions from the Build Doctor</title><content type="html">&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_-rlZcQ-7nAM/SBZAEXDarrI/AAAAAAAAADo/r_JPplkKUkM/s1600-h/463482776_f68f8a7be8.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_-rlZcQ-7nAM/SBZAEXDarrI/AAAAAAAAADo/r_JPplkKUkM/s320/463482776_f68f8a7be8.jpg" alt="" id="BLOGGER_PHOTO_ID_5194409663870447282" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:85%;"&gt;(image taken from &lt;a href="http://flickr.com/photos/trvr3307/"&gt;Tevor's Photostream&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Thanks for all your comments so far. It's nice to know that people are reading and (in just a few cases) correcting me.  I do appreciate feedback - of all kinds.  Here's an outline of the ways you could track what's going on here, and get in touch.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;How to keep up to date:&lt;/span&gt;&lt;br /&gt;&lt;a href="http://feedburner.com/TheBuildDoctor"&gt;RSS Feed&lt;/a&gt;. If you already use RSS feeds, then perhaps the most sensible thing is to subscribe to the feed for the blog.  We publish a &lt;a href="http://feedburner.com/TheBuildDoctor"&gt;full feed&lt;/a&gt; which gets you ever article published, as well as daily build and deploy links from &lt;a href="http://del.icio.us/www_build_doctor_com"&gt;del.icio.us&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.feedburner.com/fb/a/emailverifySubmit?feedId=1516867&amp;amp;loc=en_US"&gt;Email Subscriptions&lt;/a&gt;. Every page on Build Doctor has a link for subscribing by email.  I take privacy seriously, and will not disclose your email to anybody. If your internet access is restricted, this could be an option.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://twitter.com/simpsonjulian"&gt;Twitter&lt;/a&gt;. Twitter is a great way to keep in touch with people, that seems to be quickly gaining traction.  I'm going to announce new posts on Twitter.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Talk to the doctor:&lt;/span&gt;&lt;br /&gt;You can email the surgery at 'medic (at) build (dash) doctor (dot) com'&lt;br /&gt;&lt;br /&gt;Every Build Doctor blog post has a comment section.  I approve comments before they are published, so feel free to drop me a comment.  Tell me if you'd like to be emailed back, and I can delete the comment before it gets published.&lt;br /&gt;&lt;br /&gt;Twitter is also a good way to get in touch.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tell your friends:&lt;/span&gt;&lt;br /&gt;Every article also has links to social bookmarking sites at the bottom.  If yours isn't there, tell me and I'll try and squeeze it in.&lt;br /&gt;&lt;br /&gt;Thanks to the hipsters at the &lt;a href="http://thediscoblog.com/"&gt;Disco Blog&lt;/a&gt; for the title gag.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=f65vEG"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=f65vEG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=I3nyXg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=I3nyXg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=NtBSYg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=NtBSYg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=KpevTg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=KpevTg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/279658558/how-to-get-repeat-prescriptions-from.html" title="How to get repeat prescriptions from the Build Doctor" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=2200789020016118142" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/2200789020016118142/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/2200789020016118142" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/2200789020016118142" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/04/how-to-get-repeat-prescriptions-from.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-7870092676374831270</id><published>2008-04-24T21:58:00.004+01:00</published><updated>2008-04-24T22:13:37.485+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dependencies" /><category scheme="http://www.blogger.com/atom/ns#" term="build" /><category scheme="http://www.blogger.com/atom/ns#" term="ant" /><title type="text">Ant Best Practices: Manage Dependencies Using Ant</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_-rlZcQ-7nAM/SBD263DarqI/AAAAAAAAADg/-qM-B_3adwU/s1600-h/351347005_753e2e1d1c_o.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_-rlZcQ-7nAM/SBD263DarqI/AAAAAAAAADg/-qM-B_3adwU/s320/351347005_753e2e1d1c_o.jpg" alt="" id="BLOGGER_PHOTO_ID_5192921861429309090" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;(image taken from &lt;a href="http://flickr.com/photos/cote/archives/date-posted/2007/01/08/"&gt;cotes' photostream&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In the &lt;a href="http://www.build-doctor.com/2008/04/ant-best-practices-provide-clean-target.html"&gt;last post&lt;/a&gt;, we discussed the importance of a clean target.   Is it your first time? Have a look at the &lt;a href="http://www.build-doctor.com/2008/04/ant-best-practices-series.html"&gt;index page&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Today, I want to talk about managing dependencies with Ant.  What does that mean?  In this case, it means managing the dependencies on code within your project: dependencies in code, third party libraries, etc.  I want to cover dependencies between other projects in another post.&lt;br /&gt;&lt;br /&gt;The advice is to start from the very bottom up.  You have a bunch of common utility files?  Compile them up in one target.  And make sure that target outputs one thing and one thing only: a jar file called &lt;span style="font-style: italic;"&gt;common.jar&lt;/span&gt;.  Now, that file isn't going to be your enterprise application on it's own, so do the same to the code that references the classes inside &lt;span style="font-style: italic;"&gt;common.jar&lt;/span&gt;.  Make sure that each one of those outputs a single artifact, and that each one of them depends on the target for &lt;span style="font-style: italic;"&gt;common.jar&lt;/span&gt;.  Now, you probably have a web application or two that depends on a jar file of business code, which depends on a bunch of common files that nobody can decide where to put - &lt;span style="font-style: italic;"&gt;common.jar&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;What if there's a separate project for the front-end project, vs. the back-end?  You still want to package up the code as jar files for consumption by the other project.  But for the love of God try to resist doing that.  Most projects really only have one product that they make.  To split them up into different, smaller projects adds a whole world of complexity.&lt;br /&gt;&lt;br /&gt;What we just did was stop anybody from breaking the build by making the back-end code depend on the front-end code.  Which is quite easy to do when your IDE allows you to do that in a few keystrokes.&lt;br /&gt;&lt;br /&gt;This technique will create some good karma for your project, as long as you follow the sane practice of making every developer run the Ant build before they check in.  For me, this is critical.  Nice one, Eric.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=u4DVruG"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=u4DVruG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=kuSsj7g"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=kuSsj7g" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=jhgspSg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=jhgspSg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=uPJywog"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=uPJywog" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/277173611/ant-best-practices-manage-dependencies.html" title="Ant Best Practices: Manage Dependencies Using Ant" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=7870092676374831270" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/7870092676374831270/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/7870092676374831270" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/7870092676374831270" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/04/ant-best-practices-manage-dependencies.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-6098234719205425994</id><published>2008-04-20T21:46:00.005+01:00</published><updated>2008-04-20T22:17:59.094+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ci" /><category scheme="http://www.blogger.com/atom/ns#" term="studios" /><category scheme="http://www.blogger.com/atom/ns#" term="cruisecontrol" /><category scheme="http://www.blogger.com/atom/ns#" term="thoughtworks" /><category scheme="http://www.blogger.com/atom/ns#" term="cruise" /><category scheme="http://www.blogger.com/atom/ns#" term="continuous integration" /><title type="text">Cruise: the newest CI server from ThoughtWorks</title><content type="html">ThoughtWorks Studios has announced it's latest product: a Continuous Integration server called &lt;a href="http://studios.thoughtworks.com/cruise"&gt;Cruise&lt;/a&gt;.  It's derived from the open source project &lt;a href="http://cruisecontrol.sf.net/"&gt;CruiseControl&lt;/a&gt; with many new features promised.  Jez Humble &lt;a href="http://article.gmane.org/gmane.comp.java.cruise-control.devel/11076"&gt;announced it &lt;/a&gt;to the CruiseControl developers on April 15.  Presumably this will replace CruiseControl Enterprise, which was announced about a year ago.&lt;br /&gt;&lt;br /&gt;Call me shallow, but I do like the name.  CruiseControl always gets abbreviated to 'Cruise': why not give it the name that sticks?&lt;br /&gt;&lt;br /&gt;The list of features looks impressive.  I'm particularly interested in having a look at the Build Pipeline support.  The idea of the pipeline is nice, but I'm still waiting to see a good implementation; and I'd like to see how it works in practice - I've been &lt;a href="http://www.juliansimpson.org/2007/07/pipeline-of-doom.html"&gt;less than impressed&lt;/a&gt; in the past.&lt;br /&gt;&lt;br /&gt;The support for Java, .NET and Ruby out of the box is a good thing.  The 3 different CruiseControls that we all ended up with each have some great features. With each project being run separately, innovations tend to stick to the CruiseControl fork that they originated in.&lt;br /&gt;&lt;br /&gt;You can read up on the rest of the feature list for yourself - click the link at the top of this article.&lt;br /&gt;&lt;br /&gt;What will be interesting is how it's going to fit into the CI marketplace.  The first movers in the commercial CI tools space like have been carving out market share.  Microsoft &lt;a href="http://msdn2.microsoft.com/en-us/library/ms364045.aspx"&gt;offers&lt;/a&gt; CI tools.  There's a load more of open source &lt;a href="http://sourceforge.net/search/index.php?words=%28%2B%22continuous+integration%22%29+AND+trove%3A%2846%29&amp;amp;sort=score&amp;amp;sortdir=desc&amp;amp;offset=0&amp;amp;type_of_search=soft&amp;amp;pmode=0"&gt;contenders&lt;/a&gt; now than there was a couple of years ago.  Having said all that, ThoughtWorks are the people who put CI on the map.  I think they will generate a lot of interest.&lt;br /&gt;&lt;br /&gt;It's a growing market.  Let's see what happens.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://studios.thoughtworks.com/cruise"&gt;Link&lt;/a&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=RSAhFPG"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=RSAhFPG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=tgSeLwg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=tgSeLwg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=oBYqdzg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=oBYqdzg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=vyMXUmg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=vyMXUmg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/274276579/cruise-newest-ci-server-from.html" title="Cruise: the newest CI server from ThoughtWorks" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=6098234719205425994" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/6098234719205425994/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/6098234719205425994" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/6098234719205425994" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/04/cruise-newest-ci-server-from.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-6366949235862799400</id><published>2008-04-08T22:29:00.006+01:00</published><updated>2008-04-08T22:54:21.636+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="highlighting" /><category scheme="http://www.blogger.com/atom/ns#" term="build" /><category scheme="http://www.blogger.com/atom/ns#" term="nant" /><category scheme="http://www.blogger.com/atom/ns#" term="ant" /><category scheme="http://www.blogger.com/atom/ns#" term="textmate" /><category scheme="http://www.blogger.com/atom/ns#" term="syntax" /><title type="text">How to add Ant and NAnt support to TextMate</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_-rlZcQ-7nAM/R_voS4PocrI/AAAAAAAAADY/Sf3vOYNeh4A/s1600-h/482059395_f0bfd09b27.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_-rlZcQ-7nAM/R_voS4PocrI/AAAAAAAAADY/Sf3vOYNeh4A/s320/482059395_f0bfd09b27.jpg" alt="" id="BLOGGER_PHOTO_ID_5186994806880498354" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;(image taken from  &lt;a href="http://flickr.com/photos/dmitry-baranovskiy/"&gt;Dmitry Baranovskiy's photostream&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;The moment my 30 day evaluation of &lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt;  expired, I ordered a copy.  The last time I got so  enthused about an application that I stumped up the cash for it was about 3 years ago, with &lt;a href="http://www.delicious-monster.com/"&gt;Delicious Library&lt;/a&gt;.  Today I used it to edit some &lt;a href="http://nant.sourceforge.net/"&gt;NAnt&lt;/a&gt; files.  Here's how.&lt;br /&gt;&lt;br /&gt;My ancient little Mac Mini already had &lt;a href="http://subversion.tigris.org/project_packages.html"&gt;Subversion&lt;/a&gt;.  I installed &lt;a href="http://www.go-mono.com/mono-downloads/download.html"&gt;Mono&lt;/a&gt; so I could get a working copy of NAnt.  You'll need both.&lt;br /&gt;&lt;br /&gt;You need to run this in a Terminal window to enable syntax highlighting for both tools:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;export LC_CTYPE=en_US.UTF-8&lt;br /&gt;mkdir -p /Library/Application\ Support/TextMate/Bundles&lt;br /&gt;cd /Library/Application\ Support/TextMate/Bundles&lt;br /&gt;svn co http://macromates.com/svn/Bundles/trunk/Review/Bundles/C%23.tmbundle&lt;br /&gt;svn co http://macromates.com/svn/Bundles/trunk/Review/Bundles/Ant.tmbundle/&lt;br /&gt;osascript -e 'tell app "TextMate" to reload bundles'&lt;/blockquote&gt;The TextMate bundles repository has some non-ASCII encodings, so the first line just ensures that you have a UTF-8 encoding selected.  The middle 4 lines make a directory, and put the Ant and NAnt bundles in that directory.  The last line  reloads the bundles for you if TextMate is already running.  What a pleasant way to do .NET.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=MxmZ9eG"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=MxmZ9eG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=T47N2Pg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=T47N2Pg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=6Gk8gDg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=6Gk8gDg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=O1LDuHg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=O1LDuHg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/266620070/how-to-add-ant-and-nant-support-to.html" title="How to add Ant and NAnt support to TextMate" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=6366949235862799400" title="2 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/6366949235862799400/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/6366949235862799400" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/6366949235862799400" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/04/how-to-add-ant-and-nant-support-to.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-7295314205132223181</id><published>2008-04-06T21:17:00.004+01:00</published><updated>2008-04-06T22:19:11.190+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="best practices" /><category scheme="http://www.blogger.com/atom/ns#" term="build" /><category scheme="http://www.blogger.com/atom/ns#" term="ant" /><title type="text">Ant Best Practices: Provide a clean target</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_-rlZcQ-7nAM/R_k934PocqI/AAAAAAAAADQ/rGUHFoLXlrE/s1600-h/83440865_0dc185dc7d.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_-rlZcQ-7nAM/R_k934PocqI/AAAAAAAAADQ/rGUHFoLXlrE/s320/83440865_0dc185dc7d.jpg" alt="" id="BLOGGER_PHOTO_ID_5186244476093887138" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;(image taken from &lt;a href="http://flickr.com/photos/bobjagendorf/"&gt;Bob Jagendorf's photostream&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In the last post, we discussed the importance of &lt;a href="http://www.build-doctor.com/2008/03/ant-best-practices-provide-good-help.html"&gt;good help&lt;/a&gt;.  Today, the best practice we're going to review (just joined us? have a &lt;a href="http://www.build-doctor.com/2008/04/ant-best-practices-series.html"&gt;look here&lt;/a&gt;) is &lt;span style="font-style: italic;"&gt;provide a clean target&lt;/span&gt;.  It's pretty straightforward.   As you change code (especially renaming source files), you'll need to delete old files.  You might as well automate the process.&lt;br /&gt;&lt;br /&gt;I have seen builds that don't use a clean target.  But then generally these builds are relying on some other process, like nuking the entire checkout and starting again.  It's easier to have a clean target, honest.&lt;br /&gt;&lt;br /&gt;You'd think that would be the end of it.  Make a target called 'clean'.  Make it clobber some compiled code and generated artifacts.  But while you go creating your new target, think about a couple of things:&lt;br /&gt;&lt;br /&gt;- How many different files and directories do you need to delete?  Ideally, it should be one directory.  Life becomes very simple when you have a single tree to clean.  Especially as you often end up making the opposite of a clean target to add directories back in.&lt;br /&gt;&lt;br /&gt;- Did I say delete?  If you have a single directory that the rest of the build depends on, check in into source control.  You can often configure your VCS to ignore the contents (like &lt;a href="http://ximbiot.com/cvs/manual/cvs-1.11.22/cvs_18.html#SEC180"&gt;cvsignore&lt;/a&gt; or &lt;a href="http://www.petefreitag.com/item/662.cfm"&gt;svn:ignore&lt;/a&gt;) of the build directory. Then you can guarantee that it's always there, but not have to worry about the built artifacts showing up when you go to commit.&lt;br /&gt;&lt;br /&gt;Here's one that I prepared earlier:&lt;br /&gt;&lt;br /&gt; &lt;pre&gt;&lt;span class="punct"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;project&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;target&lt;/span&gt; &lt;span class="attribute"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;&lt;span class="string"&gt;clean&lt;/span&gt;&lt;span class="punct"&gt;"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;delete&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;fileset&lt;/span&gt; &lt;span class="attribute"&gt;dir&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;&lt;span class="string"&gt;${build.dir}&lt;/span&gt;&lt;span class="punct"&gt;"&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;include&lt;/span&gt; &lt;span class="attribute"&gt;name&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;&lt;span class="string"&gt;**/*&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="punct"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;fileset&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;delete&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;project&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span class="punct"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Eric.  You're on the money again.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=dLvye5G"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=dLvye5G" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=sh60W6g"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=sh60W6g" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=rsezaog"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=rsezaog" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=fqzBjwg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=fqzBjwg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/265256733/ant-best-practices-provide-clean-target.html" title="Ant Best Practices: Provide a clean target" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=7295314205132223181" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/7295314205132223181/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/7295314205132223181" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/7295314205132223181" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/04/ant-best-practices-provide-clean-target.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-1775782293110489643</id><published>2008-04-02T22:13:00.007+01:00</published><updated>2008-04-02T23:01:58.879+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ci" /><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><category scheme="http://www.blogger.com/atom/ns#" term="conference" /><category scheme="http://www.blogger.com/atom/ns#" term="build" /><title type="text">CITCON Europe 2008, Amsterdam - registration is open</title><content type="html">&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_-rlZcQ-7nAM/R_QBUYPocpI/AAAAAAAAADI/6Hf9ERUvqlc/s1600-h/264279686_0d92cb1949.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_-rlZcQ-7nAM/R_QBUYPocpI/AAAAAAAAADI/6Hf9ERUvqlc/s320/264279686_0d92cb1949.jpg" alt="" id="BLOGGER_PHOTO_ID_5184770520627311250" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:85%;"&gt;(Photo taken from &lt;a href="http://www.flickr.com/photos/87709569@N00/"&gt;Copabella's photostream&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Citcon is one of my favourite conferences.  A free, &lt;a href="http://www.openspaceworld.org/"&gt;open space&lt;/a&gt; conference about Continuous Integration and Testing.  I like it because you get to meet other Build Managers and see where things are headed.  Registration opened today. Numbers are limited.&lt;br /&gt;&lt;br /&gt;Amsterdam, Holland October 3 and 4. &lt;a href="http://www.citconf.com/amsterdam2008/"&gt;Link&lt;/a&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=fCMlepG"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=fCMlepG" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=pCl5wrg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=pCl5wrg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=heVxk7g"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=heVxk7g" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=kzggwHg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=kzggwHg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/262929988/citcon-europe-2008-amsterdam.html" title="CITCON Europe 2008, Amsterdam - registration is open" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=1775782293110489643" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/1775782293110489643/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/1775782293110489643" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/1775782293110489643" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/04/citcon-europe-2008-amsterdam.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-9093523526769747588</id><published>2008-04-02T21:32:00.010+01:00</published><updated>2008-05-12T23:12:06.349+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="best practices" /><category scheme="http://www.blogger.com/atom/ns#" term="build" /><category scheme="http://www.blogger.com/atom/ns#" term="ant" /><category scheme="http://www.blogger.com/atom/ns#" term="apache" /><title type="text">The Ant Best Practices Series</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_-rlZcQ-7nAM/R_Pzf4PocoI/AAAAAAAAADA/fhvzKclQbyM/s1600-h/16449595_361f189688.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_-rlZcQ-7nAM/R_Pzf4PocoI/AAAAAAAAADA/fhvzKclQbyM/s320/16449595_361f189688.jpg" alt="" id="BLOGGER_PHOTO_ID_5184755325033017986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;(Photo taken from &lt;a href="http://flickr.com/photos/33mhz/"&gt;33mhz's photostream&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In 2003, Eric M. Burke published an article at &lt;a href="http://www.onjava.com/"&gt;OnJava&lt;/a&gt; called &lt;a href="http://www.onjava.com/pub/a/onjava/2003/12/17/ant_bestpractices.html"&gt;Top 15 Ant Best Practices&lt;/a&gt;. Are the practices still relevant?  What has changed in the last 4 years?  In this series I'll be reviewing each one and trying to find out.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.build-doctor.com/2008/03/ant-best-practices-adopt-consistent.html"&gt;1 of 15: Adopt consistent style&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.build-doctor.com/2008/02/put-build-file-at-root-of-your-project.html"&gt;2 of 15: Put the build file at the root of your project&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.build-doctor.com/2008/03/ant-best-practices-prefer-single.html"&gt;3 of 15: Prefer a single buildfile&lt;/a&gt;&lt;a href="http://www.build-doctor.com/2008/03/ant-best-practices-provide-good-help.html"&gt;&lt;br /&gt;4 of 15: Provide good help&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.build-doctor.com/2008/04/ant-best-practices-provide-clean-target.html"&gt;5 of 15: Provide a clean target&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.build-doctor.com/2008/04/ant-best-practices-manage-dependencies.html"&gt;6 of 15: Manage dependencies with Ant&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.build-doctor.com/2008/05/ant-best-practices-define-and-reuse.html"&gt;7 of 15: Define and reuse paths&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.build-doctor.com/2008/05/ant-best-practices-define-proper-target.html"&gt;8 of 15: Define Proper Target Dependencies&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This page is updated every time there's a new article.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=yJnSm4G"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=yJnSm4G" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=HoGA95g"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=HoGA95g" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=YCm68ng"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=YCm68ng" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=zVrr30g"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=zVrr30g" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/263366059/ant-best-practices-series.html" title="The Ant Best Practices Series" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=9093523526769747588" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/9093523526769747588/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/9093523526769747588" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/9093523526769747588" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/04/ant-best-practices-series.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-4654500825274343714</id><published>2008-04-01T22:38:00.006+01:00</published><updated>2008-04-21T18:22:16.775+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ci" /><category scheme="http://www.blogger.com/atom/ns#" term="practices" /><category scheme="http://www.blogger.com/atom/ns#" term="cruisecontrol" /><title type="text">The CruiseControl Best Practices Series</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_-rlZcQ-7nAM/R_KsdoPocnI/AAAAAAAAAC4/SLZ1G5bYKrQ/s1600-h/223011082_584909b4b5.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_-rlZcQ-7nAM/R_KsdoPocnI/AAAAAAAAAC4/SLZ1G5bYKrQ/s320/223011082_584909b4b5.jpg" alt="" id="BLOGGER_PHOTO_ID_5184395746076029554" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;(Image taken from &lt;a href="http://www.flickr.com/photos/igb/"&gt;igb's photostream&lt;/a&gt; on flickr)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;Here's the index of all the CruiseControl Best Practice blogs.  I'll be updating this as I publish more.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://studios.thoughtworks.com/2007/8/15/cruisecontrol-enterprise-best-practises"&gt;Part 1: Publish with a publisher&lt;/a&gt; &lt;a href="http://www.blogjava.net/chelsea/archive/2007/10/12/152185.html"&gt;[Chinese translation]&lt;/a&gt;&lt;br /&gt;&lt;a href="http://studios.thoughtworks.com/2007/9/24/keep-your-dependencies-to-yourself"&gt;Part 2: Keep your dependencies to yourself&lt;/a&gt;&lt;a href="http://www.blogjava.net/chelsea/archive/2007/10/15/153125.html"&gt; [Chinese translation]&lt;/a&gt;&lt;br /&gt;&lt;a href="http://studios.thoughtworks.com/2007/11/8/configuring-cruisecontrol-the-cruisecontrol-way"&gt;Part 3:Configuration the CruiseControl way&lt;/a&gt;&lt;a href="http://www.blogjava.net/chelsea/archive/2007/11/09/159226.html"&gt; [Chinese &lt;/a&gt;&lt;a href="http://www.blogjava.net/chelsea/archive/2007/10/15/153125.html"&gt;translation&lt;/a&gt;&lt;a href="http://www.blogjava.net/chelsea/archive/2007/11/09/159226.html"&gt;]&lt;/a&gt;&lt;br /&gt;&lt;a href="http://studios.thoughtworks.com/2008/1/24/bootstrap-with-a-bootstrapper"&gt;Part 4: Bootstrap with a bootstrapper&lt;/a&gt;&lt;a href="http://www.blogjava.net/chelsea/archive/2008/02/17/180326.html"&gt; [Chinese &lt;/a&gt;&lt;a href="http://www.blogjava.net/chelsea/archive/2007/10/15/153125.html"&gt;translation&lt;/a&gt;&lt;a href="http://www.blogjava.net/chelsea/archive/2008/02/17/180326.html"&gt;]&lt;/a&gt;&lt;a href="http://media.build-doctor.com/cruise-validator-0.1.zip"&gt; [Config Validator]&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.build-doctor.com/2008/02/refactor-your-configuration-file.html"&gt;Part 5: Refactor your configuration file&lt;/a&gt;&lt;a href="http://www.blogjava.net/chelsea/archive/2008/03/06/184374.html"&gt; [Chinese &lt;/a&gt;&lt;a href="http://www.blogjava.net/chelsea/archive/2007/10/15/153125.html"&gt;translation&lt;/a&gt;&lt;a href="http://www.blogjava.net/chelsea/archive/2008/03/06/184374.html"&gt;]&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.build-doctor.com/2008/03/cruisecontrol-enterprise-best-practices.html"&gt;Part 6: Scaling up&lt;/a&gt; &lt;a href="http://www.blogjava.net/chelsea/archive/2008/04/12/192481.html"&gt;[Chinese translation]&lt;br /&gt;&lt;/a&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=aVaRT8G"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=aVaRT8G" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=nYhmong"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=nYhmong" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=vE7d8eg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=vE7d8eg" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=gYp5dlg"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=gYp5dlg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/262237113/cruisecontrol-best-practices-series.html" title="The CruiseControl Best Practices Series" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=4654500825274343714" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/4654500825274343714/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/4654500825274343714" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/4654500825274343714" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/04/cruisecontrol-best-practices-series.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-4353980856867934827</id><published>2008-03-28T23:20:00.005Z</published><updated>2008-03-30T23:14:57.900+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cruisecontrol cce practices" /><title type="text">CruiseControl Enterprise Best Practices, Part 6: Scaling up</title><content type="html">&lt;p&gt;You just started out with Continuous Integration. You're building your project in CruiseControl. Great. Now, it's time you started to plan ahead.  This post is about scaling up CruiseControl. The tool can scale up to many projects, but you have to know a few things.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The very first thing to do is make sure that you can simultaneously build your projects. CruiseControl uses Java threads to manage builds and projects. Each project has it's own thread. There is a least one Builder thread that will actually run a build, and there is a Build Queue, which mediates the requests from the project threads to the builder thread. You need to give CruiseControl enough builder threads to work with: by default it gives you one thread. The impact of this is that if you have 5 projects configured, you'll only ever build one at a time. This could be good if you have a tiny build server, or projects that don't play nicely together.&lt;br /&gt;  &lt;/p&gt;On the other hand, if you have plenty of capacity to use, you will get a boost from the extra builder threads. The right setting for the number of threads will change over time; don't hesitate to do some performance management and find the right value for your server.&lt;br /&gt;&lt;pre&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;cruisecontrol&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;system&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;configuration&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt;&lt;span class="tag"&gt;threads&lt;/span&gt; &lt;span class="attribute"&gt;count&lt;/span&gt;&lt;span class="punct"&gt;="&lt;/span&gt;&lt;span class="string"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="punct"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;configuration&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;system&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;&amp;lt;!-- rest of config file suppressed --&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="tag"&gt;cruisecontrol&lt;/span&gt;&lt;span class="punct"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Jeffrey Frederick &lt;a href="http://www.nabble.com/Cruisecontrol-2.7.1---Maximum-number-of-Threads-to15133223.html"&gt;wisely points out&lt;/a&gt; that it is useless to set the number of builder threads to be higher than the number of projects that you have.&lt;br /&gt;  &lt;p&gt;&lt;/p&gt;There are plenty of other factors to consider when scaling up your Continuous Integration service: the speed of your Version Control System, where you store artifacts, logs, etc. One factor that I will mention today is disk bandwidth. Building software is a disk-intensive process.  Even when a build is done compiling Java code and making archives like jars, CruiseControl has to write logfiles. It's very easy to overload a single disk with all this activity.  Ideally you want to make sure that your machine can build several projects at once. &lt;p&gt;On one of my very first projects at ThoughtWorks, the team was running two CruiseControl servers, apparently because the first Solaris server was too slow. That didn't seem right to me, so I dug deeper. With my systems administration background I was able to see that a single disk was 100% busy running the operating system, CruiseControl and the build. I spread the workload across the four disks in the system and the machine was able to manage many more projects.&lt;br /&gt;  &lt;/p&gt;This pattern has repeated itself on many of my subsequent projects. In my experience not many CI servers are constrained by processor overhead.  Unfortunately, it's often painful to rectify disk issues once a system is up and running. Make yourself some luck and order plenty of fast disk drives before you scale up and people start to complain about the slow build.&lt;br /&gt;  &lt;br /&gt;The way to implement this is to use the configuration file.  The &lt;i&gt;log&lt;/i&gt; element is used to tell CruiseControl where to write logfiles.  By default it's a suubdirectory of the CruiseControl installation.  But if you change the value of the &lt;i&gt;dir&lt;/i&gt; attribute of the logfile, you can make sure that the logs are being written to a disk that isn't already running CruiseControl.  If you're using Ant to build your code, you can use the &lt;i&gt;antWorkingDir&lt;/i&gt; attribute on the &lt;i&gt;ant&lt;/i&gt; element in the config file to make sure that your projects are built on another disk.&lt;br /&gt;&lt;br /&gt;I can't really do a good example for this one as each CruiseControl instance is so different.  &lt;a href="http://buildix.thougtworks.com/"&gt;Buildix&lt;/a&gt; is an attempt to make many installs more homogenous.  If you look at the way things are laid out on the disk, you'll see that the CruiseControl install is in &lt;i&gt;/usr/share/cruisecontrol&lt;/i&gt;, but the projects and logs are installed in &lt;i&gt;/var/spool/cruisecontrol&lt;/i&gt;: the reason we did this was so that you could mount the &lt;i&gt;/var&lt;/i&gt; directory on another disk if things got busy.  Drop me a comment if you want to know more.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=oT3SR5F"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=oT3SR5F" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=qAlKr7f"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=qAlKr7f" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=lRbDktf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=lRbDktf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=xrLsnIf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=xrLsnIf" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/260927519/cruisecontrol-enterprise-best-practices.html" title="CruiseControl Enterprise Best Practices, Part 6: Scaling up" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=4353980856867934827" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/4353980856867934827/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/4353980856867934827" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/4353980856867934827" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/03/cruisecontrol-enterprise-best-practices.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-7886938361898235281</id><published>2008-03-27T10:13:00.002Z</published><updated>2008-03-27T10:18:39.363Z</updated><title type="text">New, shiny Rake support in Team City</title><content type="html">You couldn't pay me to run CruiseControl.rb now.  Oh wait.  You probably could.&lt;br /&gt;&lt;br /&gt;Anyway, now that Team City has a 'Rake Runner', you can build your Ruby projects with Rake.  It understands Test::Unit and Rspec test output as well.  The runner gives you test timings, both for that build and a graph of timings in recent builds.  It also gives you Rcov support as well.  You can have a look on their public demo server.&lt;br /&gt;&lt;br /&gt;It's available as an EAP.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.jetbrains.com/teamcity/2008/03/27/teamcity-rake-build-runner-eap-is-open/"&gt;Link&lt;/a&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=X8oouNF"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=X8oouNF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=jleAJCf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=jleAJCf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=6RSTu6f"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=6RSTu6f" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=BXYOpRf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=BXYOpRf" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/258891021/new-shiny-rake-support-in-team-city.html" title="New, shiny Rake support in Team City" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=7886938361898235281" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/7886938361898235281/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/7886938361898235281" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/7886938361898235281" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/03/new-shiny-rake-support-in-team-city.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-519196482749571137</id><published>2008-03-26T12:22:00.005Z</published><updated>2008-03-26T20:03:55.457Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="nant build" /><title type="text">New colourized Logger for Nant</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_-rlZcQ-7nAM/R-pBjIPocmI/AAAAAAAAACk/bv1QLcFReIE/s1600-h/ConsoleColorLogger.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_-rlZcQ-7nAM/R-pBjIPocmI/AAAAAAAAACk/bv1QLcFReIE/s320/ConsoleColorLogger.gif" alt="" id="BLOGGER_PHOTO_ID_5182026393007452770" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update: &lt;/span&gt;It was of course Eric Liu who wrote the logger.  Stephen Chu wrote &lt;a href="http://feeds.stephenchu.com/%7Er/stephenchu/%7E3/258034988/paramsfu-3-using-fieldsfor-and-index.html"&gt;this adjacent post&lt;/a&gt; about Rails.  Sorry, Eric and Stephen.  Thanks to the people who left comments pointing  this out.&lt;br /&gt;&lt;br /&gt;I spent several years being sysadmin at one project.  Possibly the most popular thing I ever did there was enable the Ant &lt;a href="http://ant.apache.org/manual/listeners.html#AnsiColorLogger"&gt;AnsiColorLogger&lt;/a&gt; for all the developers, giving them highlighting in the IDE and the build.&lt;br /&gt;&lt;br /&gt;Anyway, Stephen Chu from ThoughtWorks just wrote the same for Nant.  Nice work.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://twericliu.blogspot.com/2008/03/colorized-nant-console-output.html"&gt;Link&lt;/a&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=1vEVpDF"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=1vEVpDF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=Chv1f5f"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=Chv1f5f" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=lUEGSZf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=lUEGSZf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=LPP6m1f"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=LPP6m1f" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/258282881/new-colourized-logger-for-nant.html" title="New colourized Logger for Nant" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=519196482749571137" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/519196482749571137/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/519196482749571137" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/519196482749571137" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/03/new-colourized-logger-for-nant.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-1241126423298199469</id><published>2008-03-23T20:25:00.004Z</published><updated>2008-03-24T22:58:28.641Z</updated><title type="text">Ant Best Practices: Provide good help</title><content type="html">This is the fourth post in my series of posts examining Eric M Burke's&lt;br /&gt;&lt;a href="http://www.onjava.com/pub/a/onjava/2003/12/17/ant_bestpractices.html"&gt;Top 15 Ant Best Practices &lt;/a&gt;from December 2003. The last one I covered was '&lt;a href="http://www.build-doctor.com/2008/03/ant-best-practices-prefer-single.html"&gt;Prefer a single buildfile&lt;/a&gt;'.  Today's is 'Provide good help'.  Eric starts by suggesting that you should make use of public targets to document the targets that you should be able to invoke.&lt;br /&gt;&lt;br /&gt;Now, the distinction between a public and a private target in [N]Ant is pretty subtle: If the target has a descrption, it's public and will show up when you call Ant with the -p or the -projecthelp option.  If a target has no description, it's private.  So, the &lt;span style="font-style: italic;"&gt;description&lt;/span&gt; attribute signifies that the target is for public consumption; and also has the side effect of telling you what you can do with it.  Using this mechanism is a no-brainer - but how do you protect a private,  or internal target?  There's no way that you can declare a target as private, but you can stop the target from being called from the command line by prefixing it with a hyphen.&lt;br /&gt;&lt;br /&gt;For example, if you have a target called &lt;span style="font-style: italic;"&gt;start-weblogic&lt;/span&gt; that you don't want called from the command line, you can call it &lt;span style="font-style: italic;"&gt;-start-weblogic.&lt;/span&gt;  If you try and invoke it, look what happens:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;graham-tackleys-mac-mini:~ jsimpson$ ant -start-weblogic&lt;br /&gt;Unknown argument: -start-weblogic&lt;br /&gt;ant [options] [target [target2 [target3] ...]]&lt;br /&gt;Options:&lt;br /&gt; -help, -h              print this message&lt;br /&gt; -projecthelp, -p       print project help information&lt;br /&gt; -version               print the version information and exit&lt;/blockquote&gt;Eric also suggests 2 other things: using XML comments to provide more detail, and making a &lt;span style="font-style: italic;"&gt;help&lt;/span&gt; target that echoes out some useful help messages.  I don't think I'd ever disagree with a help target.  I might disagree about the XML comments.  Generally I use XML comments as temporary notes to myself.  It's nicer to use the &lt;span style="font-style: italic;"&gt;description&lt;/span&gt; attribute on elements in build.xml files: just about every element will accept one, and you can make sure that the text always matches the element.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&amp;lt;project name="MyGreatProject" default="test"&amp;gt;&lt;br /&gt;       &amp;lt;property environment="env" /&amp;gt;&lt;br /&gt;       &amp;lt;property file="override.properties" description="this gets all the special properties"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;So far, that's about 4 out of 4 practices that have held up.  Next: clean targets.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=DlAMovF"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=DlAMovF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=5UF2aff"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=5UF2aff" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=gjxUlzf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=gjxUlzf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=BSITg5f"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=BSITg5f" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/257301646/ant-best-practices-provide-good-help.html" title="Ant Best Practices: Provide good help" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=1241126423298199469" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/1241126423298199469/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/1241126423298199469" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/1241126423298199469" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/03/ant-best-practices-provide-good-help.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-3938443516687488418</id><published>2008-03-23T16:39:00.003Z</published><updated>2008-03-23T17:00:25.514Z</updated><title type="text">My article on Refactoring Ant Builds is published</title><content type="html">The Pragmatic Programmers have just published the first volume of the ThoughtWorks Anthology!  My article on Refactoring in Ant is included: I distilled my experiences fixing broken Ant builds for ThoughtWorks into a collection of refactorings that can be applied to a crufty build.  You can buy PDF or paper copies via the Prags, but if you want to buy it via Amazon, there's a link on &lt;a href="http://www.build-doctor.com"&gt;Build Doctor&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'll write more about the process of writing an article on my &lt;a href="http://juliansimpson.blogspot.com"&gt;personal blog&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.pragprog.com/titles/twa"&gt;Link&lt;/a&gt; (via &lt;a href="http://grahamis.com/blog/2008/03/23/thoughtworks-anthology/"&gt;Josh Graham&lt;/a&gt;)&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=T7SHhWF"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=T7SHhWF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=HlkHcjf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=HlkHcjf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=unkaTxf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=unkaTxf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=upEzXkf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=upEzXkf" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/256591045/my-article-on-refactoring-ant-builds-is.html" title="My article on Refactoring Ant Builds is published" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=3938443516687488418" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/3938443516687488418/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/3938443516687488418" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/3938443516687488418" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/03/my-article-on-refactoring-ant-builds-is.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-2525491159099799158</id><published>2008-03-19T13:21:00.002Z</published><updated>2008-03-19T13:33:57.987Z</updated><title type="text">renaming multiple files in Perforce with the help of Ruby</title><content type="html">Half an hour ago, I had about 60 files that had the same irritating prefix to the filename.  I wanted to drop the prefix so the reader could see the significant portion of the filename first.  There is no way that I would rename that many files by hand and not mess one up.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;bad_path=/my_redundant_path/&lt;br /&gt;&lt;br /&gt;def rename(file,path)&lt;br /&gt;  new_file = file.sub(path,'')&lt;br /&gt;  system("p4 integrate #{file} #{new_file}")&lt;br /&gt;  system("p4 delete #{file}")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Dir["*.build"].each do |old_file|&lt;br /&gt;  rename(old_file,bad_path) if old_file.match(bad_path)&lt;br /&gt;end&lt;/blockquote&gt;&lt;br /&gt;Two minutes spent playing with ruby goes a long way.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=tWgAf5F"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=tWgAf5F" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=idTCFUf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=idTCFUf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=Y5KyD2f"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=Y5KyD2f" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=BSQsu2f"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=BSQsu2f" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/254293509/renaming-multiple-files-in-perforce.html" title="renaming multiple files in Perforce with the help of Ruby" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=2525491159099799158" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/2525491159099799158/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/2525491159099799158" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/2525491159099799158" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/03/renaming-multiple-files-in-perforce.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-5809618512190157627</id><published>2008-03-19T12:26:00.003Z</published><updated>2008-03-19T20:56:51.567Z</updated><title type="text">Ant Best Practices: Prefer a single buildfile</title><content type="html">This is the third post in my series about Eric M Burke's &lt;a href="http://www.onjava.com/pub/a/onjava/2003/12/17/ant_bestpractices.html"&gt;Top 15 Ant Best Practices&lt;/a&gt; from December 2003.  Today's practice is "Prefer a single buildfile".  To paraphrase Eric,  it's easier to understand a single file rather than a clever hierarchy of files.  Having presided over several multi-file builds, I'm only too aware that you can easily hang yourself.  On the other hand, sometimes it makes sense to extract something to a different file to achieve a separation of concerns. &lt;br /&gt;&lt;br /&gt;If you are trying to map complex dependencies across many build files, or do amazing things in Ant or Nant, then perhaps you need to try and simplify things in your project.  I once worked on a project where the frontend was written by my team, and the backend by other.  The frontend team branched the work of the backend team, and the backend team kept on trucking with their work.  I came to the belated conclusion that we had fallen prey to &lt;a href="http://en.wikipedia.org/wiki/Conway%27s_Law"&gt;Conway's Law&lt;/a&gt;; really we had one project, and we should have written it like that.  The build on that project was a nightmare: two projects pretending they were free agents, but in reality hopelessly dependent on each other. &lt;br /&gt;&lt;br /&gt;I'm torn on this practice, but I'm going to agree with Eric.  Ideally you shouldn't need multiple files.  Though it does keep me in a job.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=FQeb32F"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=FQeb32F" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=9t9GSkf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=9t9GSkf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=0GIiXbf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=0GIiXbf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=7J4k1Wf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=7J4k1Wf" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/254522253/ant-best-practices-prefer-single.html" title="Ant Best Practices: Prefer a single buildfile" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=5809618512190157627" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/5809618512190157627/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/5809618512190157627" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/5809618512190157627" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/03/ant-best-practices-prefer-single.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-4217617110399724869</id><published>2008-03-17T21:36:00.004Z</published><updated>2008-03-17T22:50:13.636Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="build ant bestpractices" /><title type="text">Ant Best Practices: Adopt consistent style</title><content type="html">In my &lt;a href="http://www.build-doctor.com/2008/02/put-build-file-at-root-of-your-project.html"&gt;first post&lt;/a&gt; reviewing Eric Burke's &lt;a href="http://www.onjava.com/pub/a/onjava/2003/12/17/ant_bestpractices.html"&gt;Ant Best Practices article&lt;/a&gt; from 2003, we looked at putting the build file at the root of the project tree.  I had a bee in my bonnet about that one; and so I skipped Eric's first point, which is to adopt a consistent style.&lt;br /&gt;&lt;br /&gt;The man had a point, and it's still true.  Some build files would appear to be an amalgam of different styles.  Maybe I've been doing this too long, but I could tell who wrote certain parts of the build at my last project without looking at the version control system to find out.  Just like Java code, you need to decide on tabs or spaces to indent with, and how many tabstops/spaces to set.  If you're using Eclipse, you can configure this, and check the &lt;span style="font-style: italic;"&gt;.project&lt;/span&gt; file back into your project's source repository so any Eclipse user can automatically use the same settings:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_-rlZcQ-7nAM/R97rsVyYavI/AAAAAAAAACU/quZr1DeGXxs/s1600-h/Picture+1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_-rlZcQ-7nAM/R97rsVyYavI/AAAAAAAAACU/quZr1DeGXxs/s320/Picture+1.png" alt="" id="BLOGGER_PHOTO_ID_5178835768517880562" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;What's changed in the intervening few years between the publication of Eric's post and this one is just how much better IDE support for Ant has gotten.  As long as you don't do anything odd (there's several posts in that one alone) to your build, you should be able to navigate through your build using Eclipse or IDEA.  Control-clicking on a target reference will take you to that target's definition, and you can get an outline view, amongst others.  You can also run and debug the build from the IDE, which is awfully convenient.&lt;br /&gt;&lt;br /&gt;For me, it's a good reason not to put enormous XML comments in the build, like this:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&amp;lt;!-- =================================&lt;br /&gt;     target: name             &lt;br /&gt;    ================================= --&amp;gt;&lt;br /&gt;&amp;lt;target name="name" depends="depends" description="--&amp;gt; description"&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;They would be helpful if you're editing your &lt;span style="font-style: italic;"&gt;build.xml&lt;/span&gt; using a monochrome terminal and a text editor like vi (which I have done).   But as IDE's and editors get better, there's less call for such things.  I put my energies into making things consistent and easy to read.  Eric: that's 2.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=LsLz6QF"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=LsLz6QF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=rVgwuuf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=rVgwuuf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=haMQxdf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=haMQxdf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=iCsKAxf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=iCsKAxf" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/253280457/ant-best-practices-adopt-consistent.html" title="Ant Best Practices: Adopt consistent style" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=4217617110399724869" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/4217617110399724869/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/4217617110399724869" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/4217617110399724869" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/03/ant-best-practices-adopt-consistent.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-170019068498776181</id><published>2008-03-16T15:35:00.001Z</published><updated>2008-03-16T15:31:46.934Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby cruisecontrol" /><title type="text">Graphing your CruiseControl build times with Gruff</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_-rlZcQ-7nAM/R4UON2XbtII/AAAAAAAAABs/lTZDurIdcsM/s1600-h/blob.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_-rlZcQ-7nAM/R4UON2XbtII/AAAAAAAAABs/lTZDurIdcsM/s320/blob.png" alt="" id="BLOGGER_PHOTO_ID_5153540979690288258" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;There had been some concern on my last project about build times.  My erstwhile colleague Ben started graphing the builds on a sheet of paper and posting it in the kitchen so everybody in the team could see it.  When the sheet fell of the wall and the cleaners threw it away, I knew it was time to do something.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cruise Publisher&lt;/span&gt;&lt;br /&gt;How do you get the build time in the first place?  I wrote a CruiseControl publisher that called some Ruby  code to extract the build duration from the CruiseControl log, which is an XML file.  It was a very simple script that matched duration of the Ant build in the XML file, converted the text to a number of seconds, and then made an HTTP POST to a Rails application.  The build duration got passed as a POST argument.&lt;br /&gt;&lt;br /&gt;We had a Rails application to display other project information.  So for us, this was a convenient way to store the information, with the date coming from the database.  You could use a text file to store this information instead.  Once everything was in place it was easy to write some more Ruby to make the graph appear.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Code&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;require 'chart'&lt;br /&gt;require 'gruff'&lt;br /&gt;&lt;br /&gt;data = { "count" =&gt; [ 3, 5, 2 ] }&lt;br /&gt;g = Gruff::Line.new 640&lt;br /&gt;g.title = "Usages of the word 'foo'"&lt;br /&gt;g.labels = { 0 =&gt; 'Monday', 1 =&gt; 'Tuesday', 2 =&gt; 'Wednesday'}&lt;br /&gt;g.theme_rails_keynote&lt;br /&gt;data.each_pair {|k, v| g.data(k, v)}&lt;br /&gt;blob = g.to_blob&lt;br /&gt;&lt;br /&gt;out = File.new("blob.png","w+")&lt;br /&gt;out &amp;lt; blob&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This code uses &lt;a href="http://nubyonrails.com/pages/gruff"&gt;Gruff&lt;/a&gt; to actually generate the chart, and you'll need to install this separately.  Pass it some data and it will build a PNG file with your graph.  By plumbing it into the radiator, the trend in build times is visible to the entire room. It really helped to keep the team focussed on the length of the build  - especially for browser based tests that can easy start to slow things down.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=PEjwi7F"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=PEjwi7F" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=jXMNq7f"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=jXMNq7f" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=GD4G6xf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=GD4G6xf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=6YF6cxf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=6YF6cxf" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/252496330/graphing-your-cruisecontrol-build-times.html" title="Graphing your CruiseControl build times with Gruff" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=170019068498776181" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/170019068498776181/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/170019068498776181" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/170019068498776181" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/03/graphing-your-cruisecontrol-build-times.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-1496467756189782164</id><published>2008-03-13T22:48:00.000Z</published><updated>2008-03-13T22:47:10.380Z</updated><title type="text">[ant]call is evil</title><content type="html">When you're writing a .NET or Java build file, consider this: &lt;span style="font-style: italic;"&gt;antcall&lt;/span&gt; and it's cousin &lt;span style="font-style: italic;"&gt;call&lt;/span&gt; are evil.  I'm going to tell you why. First I need to give you a short history lesson.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt; &lt;span style="font-weight: bold;"&gt;A brief introduction to make&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Make is the daddy of the Ant and Nant build tools.  It originally came from the Unix world but it has been ported to just about every computer system, as it's the de facto way to build c code.  Make reads &lt;span style="font-style: italic;"&gt;makefiles,&lt;/span&gt; which tell make how to do your bidding.  Inside the makefile, you declare targets, declare their dependencies, and let make do all the work.  Here's a simple example of a makefile:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;jsimpson$ cat Makefile&lt;br /&gt;a: b c&lt;br /&gt;   echo "A: I depend on b and c "&lt;br /&gt;&lt;br /&gt;b:&lt;br /&gt;   echo "B: I depend on nothing"&lt;br /&gt;&lt;br /&gt;c: d&lt;br /&gt;   echo "C: I depend on d"&lt;br /&gt;&lt;br /&gt;d:&lt;br /&gt;   echo "D: I depend on nothing"&lt;/blockquote&gt;The format of the makefile is simple. A target begins with a &lt;span style="font-style: italic;"&gt;dependency line&lt;/span&gt; containing a name, a colon and an optional list of dependencies.  The dependency line is followed by one or more &lt;span style="font-style: italic;"&gt;command lines&lt;/span&gt; that are indented with a tab.  The command lines do the work.  In the example above you can see that target A depends on targets B and C, and that target C depends on target D.  When we execute the makefile, make determines the order in which it should execute the targets to do the work.  Have a look:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;jsimpson$ make&lt;br /&gt;echo "B: I depend on nothing"&lt;br /&gt;B: I depend on nothing&lt;br /&gt;echo "D: I depend on nothing"&lt;br /&gt;D: I depend on nothing&lt;br /&gt;echo "C: I depend on d"&lt;br /&gt;C: I depend on d&lt;br /&gt;echo "A: I depend on b and c "&lt;br /&gt;A: I depend on b and c &lt;/blockquote&gt;&lt;br /&gt;The make that is installed on my Mac decided that the appropriate order in which to execute the targets was B, D, C and then A.  It could have chosen D, C, B and then A.  It &lt;span style="font-style: italic;"&gt;doesn't matter&lt;/span&gt; because &lt;span style="font-style: italic;"&gt;you tell make the dependency rules&lt;/span&gt; and then make satisfies them.  This approach has been working for authors of Unix software since  1977 , thanks to Stuart Feldman at Bell Labs, who wrote the original make.  Make is still actively used on many projects today, but for the bulk of Java and .NET projects, you'll be using Ant and NAnt.  This is okay.  Make isn't exactly cross-platform, and the two tools are evolved with support for building their platforms.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;How does this help me write good Nant or Ant buildfiles?&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;What you are doing when you write a makefile, or build.xml or project.build is declaring dependencies.  What the build tool (make, Ant or Nant) does with those dependencies is create a dependency graph.  We can visualize the dependency graph of our simple build:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_-rlZcQ-7nAM/R9W1LVyYauI/AAAAAAAAACI/JezZ6mBXcyo/s1600-h/test.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_-rlZcQ-7nAM/R9W1LVyYauI/AAAAAAAAACI/JezZ6mBXcyo/s320/test.gif" alt="" id="BLOGGER_PHOTO_ID_5176242553163901666" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;It becomes very important to specify the dependencies of each target correctly.  If you write a build target that doesn't declare it's dependencies fully or correctly (say, it actually depends on the output of another target, which is run sometimes) then you end up with a broken or unreliable build.  It's an easy mistake to make, especially as complexity on your project grows.  But how does all this relate to the [n]ant call?&lt;br /&gt;&lt;br /&gt;It seems okay at first glance.  Each task will execute a named target in the same buildfile as the calling element.  Which is really convenient if you explicitly want to invoke a target at a specific point in your buildfile.  But what if that target has dependencies?  The &lt;a href="http://ant.apache.org/manual/CoreTasks/antcall.html"&gt;Ant documentation&lt;/a&gt; hints at the pain:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt; When a target is invoked by antcall, all of its dependent targets will also be called within the context of any new parameters.&lt;/blockquote&gt;If your antcall or Nant call target has no dependencies, then you have done nothing wrong but violate the dependency based style of the tool. If it has dependencies, then they will be relentlessly run every time you call the target.&lt;br /&gt;&lt;br /&gt;One pattern I have seen a lot of is using the [ant]call to specify dependencies in order, rather than declaring them as such:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;    &amp;lt;target name="chico"/&amp;gt;&lt;br /&gt;  &amp;lt;target name="zeppo"/&amp;gt;&lt;br /&gt;  &amp;lt;target name="harpo"/&amp;gt;&lt;br /&gt;   &lt;br /&gt;  &amp;lt;target name="groucho"&amp;gt;&lt;br /&gt;      &amp;lt;antcall target="chico"/&amp;gt;&lt;br /&gt;      &amp;lt;antcall target="zeppo"/&amp;gt;&lt;br /&gt;      &amp;lt;antcall target="harpo"/&amp;gt;&lt;br /&gt;  &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;In a way I can see why the idea is attractive:  You want to be sure of the order of target execution.  To be really sure, you need to specify dependencies on the targets.   So in this case you'd declare that harpo depended on zeppo, for example.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;    &amp;lt;target name="groucho" depends="chico,zeppo,harpo"&amp;gt;&lt;br /&gt;  &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Both Ant and Nant will attempt to preserve the order in which you declared them.  The crucial difference is that should one of those targets depend on something else, it can adjust the order of target execution to accommodate it.&lt;br /&gt;&lt;br /&gt;To give Nant it's due, it does give you a little more room to move: you can set the &lt;span style="font-style: italic;"&gt;cascade&lt;/span&gt; attribute on the &lt;a href="http://nant.sourceforge.net/release/latest/help/tasks/call.html"&gt;call&lt;/a&gt; task to force it not to execute dependencies twice.  Another aspect that I haven't covered yet is reuse.  If you want to try and invoke a target several times with different parameters, the dependency model doesn't really cut it.  Before Ant 1.6 came out, there really was no choice but to use antcall.&lt;br /&gt;&lt;br /&gt;Anyway, my advice for anybody using antcall is to substitute it for &lt;span style="font-style: italic;"&gt;macrodef&lt;/span&gt;, where you really need reuse.  .NET developers will be pleased to hear that there's some macrodef support for Nant as well.  I hope to write about those soon.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Thanks to T Ashitani for the online dot implementation. &lt;a href="http://ashitani.jp/gv/"&gt;Link&lt;/a&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=62IYCrF"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=62IYCrF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=A1C9ZNf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=A1C9ZNf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=wVPalUf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=wVPalUf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=7L7pPAf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=7L7pPAf" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/TheBuildDoctor/~3/251042840/antcall-is-evil.html" title="[ant]call is evil" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6500374844252313496&amp;postID=1496467756189782164" title="3 Comments" /><link rel="replies" type="application/atom+xml" href="http://www.build-doctor.com/feeds/1496467756189782164/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/1496467756189782164" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6500374844252313496/posts/default/1496467756189782164" /><author><name>Julian</name><uri>http://www.blogger.com/profile/06148753904642162513</uri><email>noreply@blogger.com</email></author><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><feedburner:origLink>http://www.build-doctor.com/2008/02/antcall-is-evil.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6500374844252313496.post-4631952766806067007</id><published>2008-03-13T17:26:00.002Z</published><updated>2008-03-13T17:28:57.142Z</updated><title type="text">Jetbrains eat their own dog food</title><content type="html">They develop Team City with Team City, of course.  When you look at the product, you can tell that the developers use it - there are loads of nice little features that will never sell the product, but are immensely helpful to developers. 700 builds a day. &lt;a href="http://blogs.jetbrains.com/teamcity/2008/03/13/concrete-teamcity-use-cases/"&gt;Link&lt;/a&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=DV0rsmF"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=DV0rsmF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/TheBuildDoctor?a=Z2v0jQf"&gt;&lt;img src="http://feeds.feedburner.com/~f/TheBuildDoctor?i=Z2v0jQf" border="0"&gt;&lt;/img&gt;&lt;/a