<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6678855</id><updated>2012-01-08T10:24:47.170-08:00</updated><category term='Continuous Integration'/><category term='Project Management'/><category term='XP'/><category term='Misc'/><category term='Design'/><category term='Web Testing'/><category term='ThoughtWorks'/><category term='Java'/><category term='IDE'/><category term='Test'/><category term='Refactoring'/><category term='Interaction Design'/><category term='SCRUM'/><category term='Story'/><category term='Enterprise'/><category term='Rants'/><category term='Iterative Development'/><category term='Agile'/><category term='Ruby'/><category term='Coach'/><category term='Career'/><category term='Estimation'/><category term='OperSource'/><category term='Energized Work'/><category term='Publications'/><category term='Communication'/><title type='text'>A New Beginning</title><subtitle type='html'>Agile Experiences and Thoughts</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default?start-index=101&amp;max-results=100'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>122</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6678855.post-4919669832979548639</id><published>2011-05-11T13:12:00.001-07:00</published><updated>2011-05-11T13:12:27.129-07:00</updated><title type='text'>Blog of the day</title><content type='html'>Interesting article because it relates exactly to what we are going through.&amp;nbsp; I am only wondering about the stage we are in&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-4919669832979548639?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://stevenmsmith.com/ar-satir-change-model/' title='Blog of the day'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/4919669832979548639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=4919669832979548639' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4919669832979548639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4919669832979548639'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2011/05/blog-of-day.html' title='Blog of the day'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-5185529685347831666</id><published>2010-07-28T10:04:00.000-07:00</published><updated>2010-07-28T10:06:27.148-07:00</updated><title type='text'>Top 10 Reasons for Slow Velocity</title><content type='html'>&lt;a href="http://www.svpg.com/top-10-reasons-for-slow-velocity/"&gt;http://www.svpg.com/top-10-reasons-for-slow-velocity/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;My current challenge at work is to capture velocity reliably, but I am sure this post will come handy sometime down the road.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-5185529685347831666?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.svpg.com/top-10-reasons-for-slow-velocity/' title='Top 10 Reasons for Slow Velocity'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/5185529685347831666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=5185529685347831666' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5185529685347831666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5185529685347831666'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2010/07/top-10-reasons-for-slow-velocity.html' title='Top 10 Reasons for Slow Velocity'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-9208609717231440945</id><published>2009-10-22T22:42:00.000-07:00</published><updated>2009-10-23T22:00:01.933-07:00</updated><title type='text'>Automation of Burn-up and Burn-down charts using GScript and Entrance</title><content type='html'>I have always found that the burn-up and burn-down charts are very informative and fit to the iterative story-based development very well. Every project that I work on, I will try to figure out &lt;a href="http://agileworks.blogspot.com/2009/01/burn-up-and-burn-down-charts.html"&gt;different ways to generate burn-up and burn-down charts&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Two months ago, I took the job on putting Platform on Sprints. After some consideration, I have decided to follow the setup that I have for the AF team, creating the stories &lt;a href="http://agileworks.blogspot.com/2009/02/jira-story-wall.html"&gt;in the form of JIRA issues&lt;/a&gt;. However, the chart generation that I had for AF team was still semi-manual, which means that it takes a couple of minutes to download, and a couple of minutes to update the stats every morning. The worst part is that when I get busy or sick, I will forget.&lt;br /&gt;&lt;br /&gt;So my first action item was to figure out how to generate the same kind of charts with the push of a button. The idea seems to be easy enough:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Figure out the search criteria to retrieve all the JIRA issues of the backlog&lt;/li&gt;&lt;li&gt;Count the issues that are in different states&lt;/li&gt;&lt;li&gt;Update the data with the counts, and check it into Perforce.&lt;/li&gt;&lt;li&gt;Refresh the chart with the updated data&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Number one and two were actually not that hard, because Guidewire GScript has a nice WebServices support. With a few tries, I was able to count the beans.&lt;br /&gt;&lt;br /&gt;Here is an example of the data generated.  I think you get the idea just looking at it.&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;Date,Day,Closed,Deferral Requested,In QA,Open Stories,Open New Features,Open Bugs&lt;br /&gt;10/09/2009,41,55,0,1,13,7,40&lt;br /&gt;10/12/2009,42,55,0,1,14,7,40&lt;br /&gt;10/13/2009,43,56,0,0,14,7,40&lt;br /&gt;10/14/2009,44,56,0,0,16,7,41&lt;br /&gt;10/15/2009,45,56,0,0,21,8,42&lt;br /&gt;10/16/2009,46,58,0,1,19,8,42&lt;br /&gt;10/19/2009,47,58,0,2,28,8,42&lt;br /&gt;10/20/2009,48,58,0,6,26,8,42&lt;br /&gt;10/21/2009,49,58,0,6,26,8,42&lt;br /&gt;10/22/2009,50,58,0,7,25,8,44 &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;Number three took less time but a bit of research because Perforce Java library's API is not exactly straightforward.&lt;br /&gt;&lt;br /&gt;It took me a while to figure out how to do the last one. After looking into &lt;a href="http://www.jfree.org/jfreechart/"&gt;JFreeChart&lt;/a&gt; and &lt;a href="http://code.google.com/apis/chart/"&gt;Google Chart API&lt;/a&gt;, I eventually turned to my dear friend, &lt;a href="http://www.todlandis.com/"&gt;Tod Landis&lt;/a&gt;, who is also my partner at &lt;a href="http://dbentrance.com/"&gt;Entrance&lt;/a&gt;, and he quickly drafted an entrance script for me. Based on it, I was able to write a template that can be used for all teams within a few hours.&lt;br /&gt;&lt;br /&gt;&lt;blockquote  style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;PLOT&lt;br /&gt;very light yellow  area,&lt;br /&gt;   light yellow filled circles and line,&lt;br /&gt;DATALABELS&lt;br /&gt;very light orange  area,&lt;br /&gt;light orange filled circles and line,&lt;br /&gt;very light red  area,&lt;br /&gt;light red filled circles and line,&lt;br /&gt;very light blue area,&lt;br /&gt;light blue filled circles and line,&lt;br /&gt;very light gray area,&lt;br /&gt;dark gray filled circles and line,&lt;br /&gt;very light green area,&lt;br /&gt;dark green filled circles and line,&lt;br /&gt;all AXISLABELS&lt;br /&gt;WITH&lt;br /&gt;ZEROBASED&lt;br /&gt;TITLE "Sprint"&lt;br /&gt;TITLE X "Days"&lt;br /&gt;TITLE Y "Points"&lt;br /&gt;SCALE Y 0 100 0&lt;br /&gt;CLIP&lt;br /&gt;legend&lt;br /&gt;gridlines&lt;br /&gt;collar&lt;br /&gt;no sides&lt;br /&gt;SELECT&lt;br /&gt;   `Open Bugs`,&lt;br /&gt;`Open Bugs`,&lt;br /&gt;date,&lt;br /&gt;`Open New Features`,&lt;br /&gt;`Open New Features`,&lt;br /&gt;`Open Stories`,&lt;br /&gt;`Open Stories`,&lt;br /&gt;`In QA`,&lt;br /&gt;`In QA`,&lt;br /&gt;`Deferral Requested`,&lt;br /&gt;`Deferral Requested`,&lt;br /&gt;`Closed`,&lt;br /&gt;`Closed`,&lt;br /&gt;day&lt;br /&gt;from report;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;Please note this is the final PLOT script, there are other SQLs run before this to import the data into the MySQL database, sum up the data to produce a stacked chart, and even out the labels.&lt;br /&gt;&lt;br /&gt;And I now have this chart generated automatically every morning with the help of a windows scheduler.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_1AIWiix4RXQ/SuFGa1wgfZI/AAAAAAAABHs/6KP6fWhi1h8/s1600-h/entrancechart.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 230px;" src="http://3.bp.blogspot.com/_1AIWiix4RXQ/SuFGa1wgfZI/AAAAAAAABHs/6KP6fWhi1h8/s320/entrancechart.png" alt="" id="BLOGGER_PHOTO_ID_5395671255487643026" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-9208609717231440945?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/9208609717231440945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=9208609717231440945' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/9208609717231440945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/9208609717231440945'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2009/10/automation-of-burn-up-and-burn-down.html' title='Automation of Burn-up and Burn-down charts using GScript and Entrance'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_1AIWiix4RXQ/SuFGa1wgfZI/AAAAAAAABHs/6KP6fWhi1h8/s72-c/entrancechart.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-1919962666284059076</id><published>2009-06-10T10:18:00.000-07:00</published><updated>2009-08-21T23:33:56.228-07:00</updated><title type='text'>Cotta Asserts vs FEST Asserts</title><content type='html'>&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Background&lt;/span&gt;&lt;/b&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Cotta-asserts is a public release of the JUnit 4 assertion adapter that came to as part of the Cotta implementation and my search for a better sematics for assertions in test.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;FEST-Assert is a Java library that provides a &lt;a class="urllink" href="http://martinfowler.com/bliki/FluentInterface.html" rel="nofollow"&gt;fluent interface&lt;/a&gt; for writing assertions. Its main goal is to improve test code readability and make maintenance of tests easier.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Cotta-asserts: &lt;a href="http://cotta.sourceforge.net/assertions.html"&gt;http://cotta.sourceforge.net/assertions.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;FEST-assert: &lt;a href="http://fest.easytesting.org/assert/wiki/pmwiki.php"&gt;http://fest.easytesting.org/assert/wiki/pmwiki.php&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Bottom Line&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The bottom line is that these two libraries are trying to solve the same problem in a different way, so they are both viable solution for writing assertions through fluent interface. Even though personally I like what I have built, I would not argument very hard about using one versus the other, same way as I would never argue between JUnit and TestNG, even though all my projects have been JUnit (And I know some people feel strongly about it).&lt;br /&gt;&lt;br /&gt;I can also say the same thing about Java versus Ruby. When it comes to the bottom line, having a gelling team building high quality software that makes the user happy is all I care.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Why I like FEST asserts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Don't get me wrong, I love FEST asserts.  Their API looks solid and really complete.  Even now, Cotta Asserts still has some way to go to catch up, it is simply not high enough on my list, and I have not found anyone willing to contribute.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Why I like Cotta Asserts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;With that said, I think it is worth it to write down the reason that I like Cotta Asserts.&lt;br /&gt;&lt;br /&gt;First of all, Cotta Asserts is aimed to filling the gap of JUnit and Hamcrest, nothing more.  It is just an API adapter that exposes the assertThat method in JUnit 4 and the matcher classes in Hamcrest.  If one day this fluent API appears on the new JUnit release, I would be happily retire this little side project, and get back to the next item of my long list of things I would like to try as an open-source project.&lt;br /&gt;&lt;br /&gt;Second, you can extend Cotta Assert however you want it to be, because all the classes are open to extension.  You can extend AssertionFactory and add more methods to return other assert objects. You can make your AssertionFactory return different StringAssert.&lt;br /&gt;&lt;br /&gt;For FEST-asserts, I always wonder why they made the classes final. It does not seem to serve any purpose.  Then again, I never asked, so there could be some good reason behind it.&lt;br /&gt;&lt;br /&gt;If you have been using assertThat method in JUnit, chances are that you already have a bunch of matchers lying around, and probably start having trouble remembering where they are. You just need to create your AssertionFactory and Asserts to leverage them and you don't have to throw anything away or even change anything.&lt;br /&gt;&lt;br /&gt;With FEST-asserts, when you look at &lt;a href="http://docs.codehaus.org/display/FEST/Extending+FEST-Assert+with+Custom+Assertions"&gt;an API like this&lt;/a&gt;, something is just not right...&lt;br /&gt;&lt;br /&gt;FEST-asserts requires you to add one assertThat method for each object type that you want to run asserts on, and &lt;a href="http://docs.codehaus.org/display/FEST/Extending+FEST-Assert+with+Custom+Conditions"&gt;one method for each custom condition&lt;/a&gt;.  It can get confusing sometimes if you have different modules that do assertion on different objects in the module.&lt;br /&gt;&lt;br /&gt;With Cotta Asserts, you only need one field declaration from the super test case class, and everything just goes from there.  So it is really easy to set up, and really easy to customize it so that each module can have methods that only create asserts that are applicable to the module.&lt;br /&gt;&lt;br /&gt;So here you are, happy testing!&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-1919962666284059076?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/1919962666284059076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=1919962666284059076' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/1919962666284059076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/1919962666284059076'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2009/06/cotta-asserts-vs-fest-asserts.html' title='Cotta Asserts vs FEST Asserts'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-1700116747253389810</id><published>2009-06-05T11:15:00.000-07:00</published><updated>2009-06-05T12:03:36.201-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Energized Work'/><title type='text'>Touché</title><content type='html'>&lt;div&gt;(This one definitely falls in "&lt;a href="http://jamesshore.com/Agile-Book/energized_work.html"&gt;Energized Work&lt;/a&gt;" category)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;In an email thread with my old XP mentor and a long time friend, &lt;a href="http://www.agileinstitute.com/"&gt;Rob Myers&lt;/a&gt;, about coordinating the next &lt;a href="http://www.bayxp.org"&gt;BayXP&lt;/a&gt; gathering, I mentioned that I have another baby coming soon.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Rob: "... about time!"&lt;/div&gt;&lt;div&gt;Shane: "... are you saying that I should get a life and stop messing with this thing called 'agile'?"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Rob:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;b&gt;"Au contrare my friend. Living 'agile' is supposed to provide you with the opportunity to have a life beyond the office. We should coach through example!  :-)"&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;Shane:&lt;/div&gt;&lt;div&gt;"..."&lt;/div&gt;&lt;div&gt;"..."&lt;/div&gt;&lt;div&gt;"Touché"&lt;/div&gt;&lt;div&gt;"..."&lt;/div&gt;&lt;div&gt;"I think this deserves a blog post"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="font-family:arial;font-size:100%;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px; "&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"   style="font-family:arial;font-size:100%;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-1700116747253389810?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/1700116747253389810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=1700116747253389810' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/1700116747253389810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/1700116747253389810'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2009/06/touche.html' title='Touché'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-4865158285772348362</id><published>2009-06-03T23:04:00.000-07:00</published><updated>2009-06-03T23:21:21.120-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Test'/><title type='text'>JUnit Assertion Adapter</title><content type='html'>I have been trying different assertion styles ever since I read &lt;a href="http://joe.truemesh.com/blog/000511.html"&gt;this blog&lt;/a&gt;, like many others.  If you google "assertThat" you can find many hits.&lt;br /&gt;&lt;br /&gt;With the creation of &lt;a href="http://cotta.sourceforge.net"&gt;Cotta&lt;/a&gt; project, I got a chance to really think hard on simple file operations and tests to see how I can make the API as polite as possible, and I think I have found a good answer.&lt;br /&gt;&lt;br /&gt;With the default JUnit 4 assertion, you still don't get the benefit of a static typed language, in that you have to remember the class to use to create the matcher for a certain type.&lt;br /&gt;&lt;br /&gt;So I created a JUnit assertion adapter that will allow you to type&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;ensure&lt;/span&gt;.that(yourValue)&lt;/blockquote&gt;and get the appropriate assertions object based on the type of the object being passed in.  The type of the returned object will have just the assertion methods that are applicable to the value.&lt;br /&gt;&lt;br /&gt;This also brings an additional benefit.  For example, you can have a list instance and call&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;ensure&lt;/span&gt;.set(list)&lt;/blockquote&gt;and it will automatically convert the list to the set and return the set assertion object.&lt;br /&gt;&lt;br /&gt;I have just made a release under the cotta project for general feedback &lt;br /&gt;&lt;br /&gt;The simple document page is here: &lt;a href="http://cotta.sourceforge.net/assertions.html"&gt;http://cotta.sourceforge.net/assertions.html&lt;/a&gt;&lt;br /&gt;and the jar can be downloaded here:&lt;a href="https://sourceforge.net/project/showfiles.php?group_id=171037"&gt;https://sourceforge.net/project/showfiles.php?group_id=171037&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-4865158285772348362?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://cotta.sourceforge.net/assertions.html' title='JUnit Assertion Adapter'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/4865158285772348362/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=4865158285772348362' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4865158285772348362'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4865158285772348362'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2009/06/junit-assertion-adapter.html' title='JUnit Assertion Adapter'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-4048611040691280647</id><published>2009-03-07T20:44:00.000-08:00</published><updated>2009-03-27T09:38:02.956-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test'/><category scheme='http://www.blogger.com/atom/ns#' term='XP'/><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>Phoenix First Two XP Sprints</title><content type='html'>Phoenix has finished its Sprint 5 and 6, which are the first two XP Sprints.&lt;br /&gt;&lt;br /&gt;An XP team always goes through four stages, "forming, storming, norming, performing". The first Sprint felt like a storming stage, where we are trying to figure out the best way to get the code in without spending too much time on upfront design. At the same time, we are also getting used to paired programming.&lt;br /&gt;&lt;br /&gt;Even though paired-programming has become an old trick for me, I still feel that my pairing skill has gotten worse during the past three years of working solo. The second Sprint felt a lot better, and I am hoping to keep this trend.&lt;br /&gt;&lt;br /&gt;Items that worth noting:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;We modified &lt;a href="http://agileworks.blogspot.com/2009/02/lava-lamp-with-cruisecontrol.html"&gt;the lava lamp&lt;/a&gt; to have a green light on when everything is good. Even though it is redundant, it has very positive effect among us. The only thing we might need to watch out is that someone mentioned that they could be fire hazard because the lamp gets very hot at the end of the day. So we are going to turn them off by the end of the day. This is when I found out that the X10 remote controller does not work, so they are back for replacement now.&lt;/li&gt;&lt;li&gt;The lava lamps are helping us getting on the habit of treating broken tests as the highest priority. Due to the nature of Phoenix, we got some interesting test breakage already. We got tests that only break on the server, tests that only break on Linux, and a test that hung. One interesting discovery is that each time we are forced to figure out what is wrong and fix them, our tests ended up making better sense and being more like behavior driven, and I was planning on settling for hacks to keep the test passing!&lt;/li&gt;&lt;li&gt;At the beginning of the project, we chose to create just enough stories to get us through the first Sprint, then created a few more for the second Sprint.  Looking back, I think that is a good choice.  The kind of stories that we create now are so much different but better from the earlier ones.  I think that is because at the beginning, your system has literally nothing.  It would take a very good story writer to come up with a list stories that really fit into the "&lt;a href="http://xp123.com/xplor/xp0308/index.shtml"&gt;INVEST&lt;/a&gt;" category of the story.  I am not saying it is impossible, I just think that two Sprints of bad stories is not a bad price to pay to get the ball rolling as early as possible and avoid lots of hassle to learn and teach and debate about good stories vs bad stories.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-4048611040691280647?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/4048611040691280647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=4048611040691280647' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4048611040691280647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4048611040691280647'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2009/03/phoenix-first-two-xp-sprints.html' title='Phoenix First Two XP Sprints'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-3331199979525325611</id><published>2009-02-23T12:35:00.001-08:00</published><updated>2009-02-24T10:01:53.081-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>Lava Lamp with CruiseControl</title><content type='html'>As we are getting Phoenix project under way, I am trying to get it started right by introducing more XP practices.  The first three things that we are trying to do are Paired-Programming, Test-Driven Development, Continuous Integration.&lt;br /&gt;&lt;br /&gt;Actually, Guidewire has already built an internal tool, ToolsHarness, to handle continuous integration, as I have written in "&lt;a href="http://agileworks.blogspot.com/2008/02/enterprise-agile-testing-part-iii.html"&gt;Managing Tests with ToolsHarness, Individually&lt;/a&gt;".  The only difference that I want to introduce for Phoenix project is to fix broken tests &lt;span style="font-weight: bold;"&gt;AS SOON AS POSSIBLE&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;What this means is that I want the testing status of our branch to show right in out faces, without us having to launch a browser, so that we know to take action the moment a test is broken.&lt;br /&gt;&lt;br /&gt;I talked to the developer who manages ToolsHarness, and he wrote a servlet that serves information about broken tests and test status like &lt;a href="http://4.bp.blogspot.com/_1AIWiix4RXQ/R70liXxfSpI/AAAAAAAAARs/WErlafsJPlQ/s1600-h/trackingtests.jpg"&gt;this picture&lt;/a&gt;, except in one HTTP GET.  Then I set up &lt;a href="http://cruisecontrol.sourceforge.net/"&gt;CruiseControl&lt;/a&gt;(version 2.8.2) with X10 publisher, following the setup described on this blog post &lt;a href="http://pragmaticautomation.com/cgi-bin/pragauto.cgi/Monitor/Devices/BubbleBubbleBuildsInTrouble.rdoc"&gt;"Bubble, Bubble, Build's In Trouble&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;One thing about the normal lava lamp setup has always bugged me in the past, which is when the continuous integration server is in the "testing" state.  When you have test broken, the red lava lamp will be on, and you just have to remind yourself that the fix is in and test is running.  In some projects, I have used "&lt;a href="http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Monitor/ListeningToComplexSystems.rdoc"&gt;project soundscape&lt;/a&gt;", so that when tests finishe but are still broken, you will know about it.  But if you happen to step outside, you will miss it.  Or if you just came in, you have to check the browser or ask others.&lt;br /&gt;&lt;br /&gt;So this time, I have done it a little differently, taking advantage of the fact that CruiseControl is not the process running the tests.  I bought two lava lamp, one kind of in the red color and the other in blue.  I set it up so that when there are two independent lava lamps:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Red Lava Lamp for broken tests: When there are broken tests, it will be on, otherwise, it will be off&lt;/li&gt;&lt;li&gt;Blue Lava Lamp for testing status: When there are tests running, it will be on, otherwise it will be off&lt;/li&gt;&lt;/ul&gt;In this way, you have four state to display:&lt;ul&gt;&lt;li&gt;Neither is on: All tests pass and the tests are up-to-date&lt;/li&gt;&lt;li&gt;Blue is on and red is off: All tests pass so far, but there are tests running against newer changes&lt;/li&gt;&lt;li&gt;Blue is off and red is on (see below): You have broken tests, and no code checked in to fix it&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_1AIWiix4RXQ/SaMIr9kfv0I/AAAAAAAAA2k/KxHujNPrzkw/s1600-h/broken.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_1AIWiix4RXQ/SaMIr9kfv0I/AAAAAAAAA2k/KxHujNPrzkw/s400/broken.jpg" alt="" id="BLOGGER_PHOTO_ID_5306094337327611714" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Both blue and red are on (see below): You have broken tests and someone has cheked in new code (hopefully to fix it)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_1AIWiix4RXQ/SaMIsNJ2z9I/AAAAAAAAA2s/OR9YclXjdmU/s1600-h/fixing.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_1AIWiix4RXQ/SaMIsNJ2z9I/AAAAAAAAA2s/OR9YclXjdmU/s400/fixing.jpg" alt="" id="BLOGGER_PHOTO_ID_5306094341510844370" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The setup is pretty straightforward, except CruiseControl 2.8.2 release is missing two crucial files, "lib/win32com.dll" and "lib/javax.comm.properties", for X10 publisher to work.  That, and me missing a tiny but also crucial detail in the documentation, caused my three-hour-hair-pulling experience, and that was with &lt;a href="http://blog.jeffreyfredrick.com/"&gt;Jeffrey&lt;/a&gt; coming to rescue through GTalk.  I am going to submit the patch for the release script to include those two files, and documentation with the following checklist:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You should provide all &lt;span style="font-weight: bold;"&gt;FOUR&lt;/span&gt; attributes related to X10 for the &lt;x10&gt; element, so that you are aware of them and make sure they are correct.  These four attributes are as following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;"houseCode" and "deviceCode" are for X10 module configuration.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;"port", with the value of COM1, COM2, etc., to match the place you plugin the COM module.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The last one is "interfaceModel", which you should really double check with the COM module that you have.&lt;/li&gt;&lt;/ul&gt;&lt;/x10&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Make sure "javax.comm.properties" is in your CruiseControl lib directory (should be there after 2.8.3)&lt;/li&gt;&lt;li&gt;Make sure you copy "win32com.dll" from CruiseControl lib directory (should be there after 2.8.3) to your Java bin directory&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;In the end, I would like to say that I am a satisfied &lt;a href="http://the.ci-guys.com/"&gt;ci-guys&lt;/a&gt; customer!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-3331199979525325611?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/3331199979525325611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=3331199979525325611' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/3331199979525325611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/3331199979525325611'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2009/02/lava-lamp-with-cruisecontrol.html' title='Lava Lamp with CruiseControl'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_1AIWiix4RXQ/SaMIr9kfv0I/AAAAAAAAA2k/KxHujNPrzkw/s72-c/broken.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-4917064712858834653</id><published>2009-02-22T12:44:00.000-08:00</published><updated>2009-02-22T12:47:30.848-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XP'/><title type='text'>Greate Article on Pair-Programming</title><content type='html'>All I can say is that this article says &lt;span style="font-weight: bold;"&gt;EXACTLY&lt;/span&gt; how I feel.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.nomachetejuggling.com/2009/02/21/i-love-pair-programming/"&gt;http://www.nomachetejuggling.com/2009/02/21/i-love-pair-programming/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;One thing to add is James Shore's &lt;a href="http://jamesshore.com/Blog/Whats-Pair-Programming-Really-Like.html"&gt;Programmer Man's Theme Song&lt;/a&gt; (see end of the post)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-4917064712858834653?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.nomachetejuggling.com/2009/02/21/i-love-pair-programming/' title='Greate Article on Pair-Programming'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/4917064712858834653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=4917064712858834653' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4917064712858834653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4917064712858834653'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2009/02/greate-article-on-pair-programming.html' title='Greate Article on Pair-Programming'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-8595592247833978378</id><published>2009-02-08T21:09:00.000-08:00</published><updated>2009-02-09T21:30:55.629-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Story'/><category scheme='http://www.blogger.com/atom/ns#' term='Project Management'/><title type='text'>JIRA Story Wall</title><content type='html'>With the "shared dashboard" feature of JIRA, we have been experimenting a shared dashboard that can be served as a virtual story wall that can be useful to us.  And here is one version.&lt;br /&gt;&lt;br /&gt;AF stories are in the form of JIRA items, in this way, JIRAs created by other teams for bug fixese or support can be rolled into one backlog.  Creating stories in the form of JIRA is not nearly as trivial and easy as creating stories on the index cards.  But once you pass that phase and get yourself used to it, it does bring a lot of benefits of a digital media.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_1AIWiix4RXQ/SY-8ny7TmJI/AAAAAAAAA2U/Ax8BTqAMr9M/s1600-h/af_information_radiator.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 244px;" src="http://4.bp.blogspot.com/_1AIWiix4RXQ/SY-8ny7TmJI/AAAAAAAAA2U/Ax8BTqAMr9M/s400/af_information_radiator.jpg" alt="" id="BLOGGER_PHOTO_ID_5300662678309804178" border="0" /&gt;&lt;/a&gt;On the left, the first section shows the stories for the current Sprint with status and the person who is working on them.  Each person is to finish the JIRAs assigned to him or her, before picking the ones assigned to the general bucket (AF General).&lt;br /&gt;&lt;br /&gt;The section section shows the stories allocated for the next Sprint, grouped by assignees and components. The third section shows the full current backlog by component and priority.  We used it a lot when trying to figure out what to work on next or what to push to next release. The last one is the backlog for the next milestone.&lt;br /&gt;&lt;br /&gt;During the Sprint, some issues will come up.  The most urgent ones will be pulled into the current Sprint to be dealt with right away. The others will either be added to the next Sprint, or add to the appropriate backlog. At the beginning of the Sprint, after counting the JIRAs already added to the Sprint, carrying over the ones from the past Sprint, we will select more JIRAs from the backlog by looking through the components.&lt;br /&gt;&lt;br /&gt;On the right, the first section is the list of the JIRAs that the current user is working on (In Progress).  It has been pretty useful to me to come in and get started right away by looking at this short list.  However, I just learned today that everybody else is just looking at the JIRAs assigned to him or her in the current Sprint.&lt;br /&gt;&lt;br /&gt;The JIRAs in the next list are the ones that have been marked as resolved by developers but not verified by QA.  They are sorted based on the order that QAs would like to process them.  QA team uses this to pick the JIRAs to verify during the Sprint.&lt;br /&gt;&lt;br /&gt;The last section on the right contains the JIRAs that have not been added to any backlog. In this way, all the JIRAs will be looked at before adding to the backlog.  One thing about using JIRA as story is that anyone can create a JIRA and assign it to your team, which mean your backlog can grow without you knowing it.  With this extra step of adding newly created JIRA to the appropriate backlog, we are always aware of any new work coming our way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-8595592247833978378?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/8595592247833978378/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=8595592247833978378' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/8595592247833978378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/8595592247833978378'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2009/02/jira-story-wall.html' title='JIRA Story Wall'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_1AIWiix4RXQ/SY-8ny7TmJI/AAAAAAAAA2U/Ax8BTqAMr9M/s72-c/af_information_radiator.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-6756175825542036830</id><published>2009-01-21T21:35:00.000-08:00</published><updated>2009-01-29T09:46:44.360-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Iterative Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Project Management'/><title type='text'>Burn-up and Burn-down Charts</title><content type='html'>&lt;div&gt;&lt;div&gt;I have always thought Sprint reporting is a major communication tool to be used within the team as well as to the outside.  It is the time for the team to take one step back, look at the project as a whole, comparing notes, and make continuous improvements.  It is also the time for the team to report the progress and any difficulties encountered, so that the stake holders can make plan adjustments and provide help if needed. &lt;/div&gt;&lt;br /&gt;Burn-up and burn-down charts are my favorite report, because they fit very well in the story based iteration model of the project development. Anyone understanding stories and iterations (not that it is always easy to learn) can understand these charts very easily.  I also find that these chart can generate more questions and lead the team in the right direction.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Burn-down Chart&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaPwqrxEI/AAAAAAAAA04/wsSemUJuJgI/s1600-h/pivotal_burndown.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 228px;" src="http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaPwqrxEI/AAAAAAAAA04/wsSemUJuJgI/s400/pivotal_burndown.jpg" alt="" id="BLOGGER_PHOTO_ID_5294362063759197250" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;Burn-down chart is straightforward and easy to understand.  It measures the burn rate of the story in the unit of the story points.  It is really easy to understand different ways of predicting the outcome of the project by predicting the future velocity of the Sprints.&lt;br /&gt;&lt;br /&gt;All the iteration tracking tools that I have tried have this support.  This one is made by &lt;a href="https://www.pivotaltracker.com/"&gt;Pivotal Tracker&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For those who use &lt;a href="http://www.atlassian.com/software/jira/"&gt;JIRA&lt;/a&gt; or good-old story cards to track the iterations, it is not hard to produce this chart as well, with the worst part being figuring out where to use what formula.  The following are from the other two projects, made with Microsoft Excel and Google spreadsheet.  With customized tool, I get to explore different styles.&lt;br /&gt;&lt;br /&gt;In the first one, the stories are divided into "must-have" and "everything else" category, and tracked at the same time.  The prediction lines are shown in different color.  In the second one, the progress is shown along with the burn-down, so that in the case where it is actually "burning up", it shows that it is not caused by losing velocity.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_1AIWiix4RXQ/SXlaQMuzxsI/AAAAAAAAA1A/1Tcn1G2B5oc/s1600-h/excel_burndown.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 250px;" src="http://3.bp.blogspot.com/_1AIWiix4RXQ/SXlaQMuzxsI/AAAAAAAAA1A/1Tcn1G2B5oc/s400/excel_burndown.png" alt="" id="BLOGGER_PHOTO_ID_5294362071292692162" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_1AIWiix4RXQ/SXlaQX7IUCI/AAAAAAAAA1I/ZiVO_iHSq8M/s1600-h/googledoc_burndown.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 224px;" src="http://1.bp.blogspot.com/_1AIWiix4RXQ/SXlaQX7IUCI/AAAAAAAAA1I/ZiVO_iHSq8M/s400/googledoc_burndown.png" alt="" id="BLOGGER_PHOTO_ID_5294362074297159714" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Burn-up Chart&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For a project with just a single coach, burn-up chart can be a great help.  It can explain a lot of concepts in the story based development, iterative development, and can help the coach recognize the patterns in the development and take actions to adjust the direction of the team.&lt;/p&gt;&lt;p&gt;I have found that burn-up chart always a bit harder to understand, and might look intimidating.  So if you are introducing it for the first time, you should not just paste it in a report and email to others.  It is best to show it in person and let the conversation start.&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaZOMeUZI/AAAAAAAAA1Q/hhq3N1pnwPw/s1600-h/excel_burnup.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 292px;" src="http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaZOMeUZI/AAAAAAAAA1Q/hhq3N1pnwPw/s400/excel_burnup.png" alt="" id="BLOGGER_PHOTO_ID_5294362226304373138" border="0" /&gt;&lt;/a&gt;The first chart shows a project where development is fairly smooth, QA can just keep up with the story being finished.  On the other hand, the project requirement is very volatile.  The interesting thing to point out is that because the team is focusing on one Sprint at a time during the release, and one story at a time during the Sprint, the dramatic scope changes did not affect the development at all.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaZtKgmJI/AAAAAAAAA1g/SS4X0aZtBak/s1600-h/googledoc_burnup.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 242px;" src="http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaZtKgmJI/AAAAAAAAA1g/SS4X0aZtBak/s400/googledoc_burnup.png" alt="" id="BLOGGER_PHOTO_ID_5294362234617632914" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The second one is a quite typical burn-up chart, where the team discovers new cases as they go, and adding the understanding to the backlog in the form of the stories.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Sprint Burn-up Chart &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I also found a burn-up chart for the Sprint is useful to figure out what happened during the Sprint.  I think this is what is called "Sprint Signature" in the &lt;a href="http://books.google.com/books?id=hJwMAAAACAAJ&amp;amp;dq=isbn:9780130676344&amp;amp;ei=XeuBSaajEJXSlQS-6qyJCg"&gt;SCRUM book&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A Sprint burn-up chart should be used strictly internally, because only the team who have just been through the Sprint can look at it, talk about it and then draw conclusions.  This should never be used for managerial purpose, in my humble opinion.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaZbdl1eI/AAAAAAAAA1Y/Z7ik6GkxC8g/s1600-h/excel_sprint_burnup.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 264px;" src="http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaZbdl1eI/AAAAAAAAA1Y/Z7ik6GkxC8g/s400/excel_sprint_burnup.png" alt="" id="BLOGGER_PHOTO_ID_5294362229865829858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaZtP4AbI/AAAAAAAAA1o/EE7u6KR_VoU/s1600-h/googledoc_sprint_burnup.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 228px;" src="http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaZtP4AbI/AAAAAAAAA1o/EE7u6KR_VoU/s400/googledoc_sprint_burnup.png" alt="" id="BLOGGER_PHOTO_ID_5294362234640138674" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-6756175825542036830?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/6756175825542036830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=6756175825542036830' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/6756175825542036830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/6756175825542036830'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2009/01/burn-up-and-burn-down-charts.html' title='Burn-up and Burn-down Charts'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_1AIWiix4RXQ/SXlaPwqrxEI/AAAAAAAAA04/wsSemUJuJgI/s72-c/pivotal_burndown.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-4319000460259010693</id><published>2008-11-15T22:16:00.001-08:00</published><updated>2009-01-06T09:16:26.353-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Staying Agile by Going off "Agile"</title><content type='html'>This is a blog post of a statement that I finally made after reading "&lt;a href="http://jamesshore.com/Blog/The-Decline-and-Fall-of-Agile.html"&gt;The Decline and Fall of Agile&lt;/a&gt;"&lt;br /&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;blockquote&gt;I am going off "Agile"&lt;/blockquote&gt;&lt;/span&gt;&lt;/span&gt;No, I am not going to give up test-driven development. In fact, I am doing more of it by adopting more behavior-driven development, which is actually harder at certain cases. It helps me understand the code and verifies the design (I believe it does that rather than "drives" out the design nowadays but that is another post).&lt;br /&gt;&lt;br /&gt;No, I am not going to give up aggressive refactoring. Every time, and I do mean EVERY TIME, I slack on it, I end up paying the price one way or another and kicking myself. I have been proud of every single line of code that I have produced (cannot say that for all the code that I have inherited and worked on), and they always serve me and my team well.&lt;br /&gt;&lt;br /&gt;No, I am not going to give up on iterative development in the form of Iterations or Sprints. They help my teams focus, avoid distractions, and can still response to the request from outside the team with crystal clear transparency.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;So what is it?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I am going to take "agile" off my vocabulary in all communications.&lt;br /&gt;&lt;br /&gt;Rather than saying&lt;br /&gt;&lt;blockquote&gt;"Not able to have QA accepting the stories as soon as they are finished is not agile"&lt;/blockquote&gt;I'll say "We need to get those finished stories accepted as soon as possible, so that we can close the feedback loop. When they are accepted, we know we are doing a good job. And when they are not, we can trace back to our thoughts as we were developing them and understand where it went wrong".&lt;br /&gt;&lt;br /&gt;Rather than saying&lt;br /&gt;&lt;blockquote&gt;"Not setting a goal at the begining of the Sprint and verifying them through the Sprint signature is not agile"&lt;/blockquote&gt;I'll say "We need to establish a way to provide feedback regarding our work and make continuous improvement to the way we work, so that we can provide better value to the people who pay us. One way we can do that is to look back at our progress in the past Sprint, talk about our experiences and thoughts, and come up with action items to make things better"&lt;br /&gt;&lt;br /&gt;Apparently this will make conversation longer, because I have to present proof more than a good book (dozens of good books available as a matter of fact). Sometimes, I will have to wait, patiently, for the opportunity to present itself so that I can use as an example to persuade others to slow down, do it right, and do it well.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Why&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have been thinking along this line for a while.  I read the "&lt;a href="http://steve-yegge.blogspot.com/2006/09/good-agile-bad-agile_27.html"&gt;Good Agile and Bad Agile&lt;/a&gt;", felt annoyed because there is truth in what he is saying. From time to time, I get annoyed by the negative comments that don't even make sense to me. I wrote one post about "&lt;a href="http://agileworks.blogspot.com/2006/09/things-you-cannot-get-certified-for.html"&gt;Things You Cannot Get Certified For&lt;/a&gt;", and argued hard on several news groups that I subscribe.&lt;br /&gt;&lt;br /&gt;Very soon I got tired of it. Using the word "agile" has caused more distraction than its worth. Practices are sometimes picked upon literally and are attacked. Rather than looking at the value something is trying to bring, many seem to tend to look at the cost(time, tools, processes) first. It got attacked, it got debated, and at the end nothing is done and the bad things just keep going. And you get people from all over the world writing about how "agile" did not work for them and laughing at anyone who is interested in trying.&lt;br /&gt;&lt;br /&gt;To add insult to injury, you can also hear usage of agile in the format like "Let's be agile about it, instead of insisting on ... ". It is really hard to argue in this situation, because you cannot just simply say "no, lets not be agile about it because we should insist on going through this three hour meeting to make sure that our stories are up to the standard".&lt;br /&gt;&lt;br /&gt;I have been avoiding throwing agile around for a while and I think I am happy with the result. I also have been ignoring the bad usage of 'agile' out there so that I can stay healthy to focus on bringing agility to my teams. (I swear this is the last time). A month ago, I went through all my blog posts and took agile out of the labels and categories.  This post will remain the only one with "Agile" as the label.&lt;br /&gt;&lt;br /&gt;I have been thinking about writing a post like this and finally decided to do it after reading James' post "&lt;a href="http://jamesshore.com/Blog/The-Decline-and-Fall-of-Agile.html"&gt;The Decline and Fall of Agile&lt;/a&gt;"&lt;br /&gt;&lt;br /&gt;Other References&lt;br /&gt;&lt;br /&gt;I am collecting references of others with similar ideas here:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://johlrogge.wordpress.com/2008/08/24/why-would-anyone-want-to-become-agile/"&gt;Why would anyone want to become agile&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blo%20g.robbowley.net/2008/11/15/lean-scrum/"&gt;Lean SCRUM&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=246513"&gt;&lt;span class="ts"&gt;Traps &amp;amp; Pitfalls of Agile Software Development - A Non-Contrarian View&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-4319000460259010693?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/4319000460259010693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=4319000460259010693' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4319000460259010693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4319000460259010693'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/11/staying-agile-by-going-off-agile.html' title='Staying Agile by Going off &quot;Agile&quot;'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-946067728327488817</id><published>2008-10-28T21:33:00.000-07:00</published><updated>2008-10-28T22:02:52.909-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Project Management'/><category scheme='http://www.blogger.com/atom/ns#' term='Coach'/><title type='text'>Two Sprint Equations</title><content type='html'>What should be the order of items to do when installing a Sprint process from scratch?  In the coaching days, we requested one to one ratio between the coaches and the rest of the developers plus a project manager, go all out for a couple of sprints, give everyone a chance to adjust to the process, before adjusting the process to the team.&lt;br /&gt;&lt;br /&gt;For a single person, the strategy would have to be different.  You would need to look at all the practices and make trade-offs with eyes on the big picture. The following two equations are what kept popping into my mind as I am installing the process to the two teams.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Value = Scope * (Feature Quality * Code Quality)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One comment to make here is that during the product development, these three factors are sometimes working against each other. A good business analyst or product manage is one that knows how and when to balance them.  Only then, one with a strong personality can bring the best value to the product.&lt;br /&gt;&lt;br /&gt;Scope is measurable, as the second section will show.  Feature quality and code quality however are simply not something can be determined by objective measurement, not purely on it anyway.  When pushed on something like a scope, the things that are not measurable get sacrificed, and everyone ends up paying for it sooner or later.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt; &lt;span style="font-weight: bold;"&gt;Scope =  Velocity * Number of Sprints&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Assuming that the quality of the product is controlled, the scope would be the next thing to look out for during a project.  This is pretty easy to understand: the more the team can do without sacrificing the quality (both feature quality and code quality), the better.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Velocity&lt;/span&gt; is something that can only be affected by tuning the Sprint process of the team, but can never be demanded.  What is left for this equation to work would be to adjust either the &lt;span style="font-weight: bold;"&gt;scope&lt;/span&gt; of the project, or the time of the project (&lt;span style="font-weight: bold;"&gt;number of sprints&lt;/span&gt;), and most of the time both.  This is probably one of the commonly stated facts, at the same time it is probably also one of the most ignored fact.&lt;br /&gt;&lt;br /&gt;Boosting velocity is the same as boosting productivity of the team, which is the job for the team lead.  This is the purpose of a lot of XP practices: TDD, paired programming, co-location, shared ownership, continuous integration.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-946067728327488817?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/946067728327488817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=946067728327488817' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/946067728327488817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/946067728327488817'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/10/two-sprint-equations.html' title='Two Sprint Equations'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-3552044217825286416</id><published>2008-10-24T21:04:00.000-07:00</published><updated>2008-10-26T09:22:47.222-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Project Management'/><title type='text'>An Interesting Agile Team Paradox</title><content type='html'>I learned this on the latest BayXP meeting&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;A good self-organizing team is commonly one with a strong leadership&lt;/blockquote&gt;I think there are a lot to this interesting comment. I'd like to find out more about its origin and elaborate on it at latter time. I just want to write it down because I have almost forgot it twice already.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-3552044217825286416?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/3552044217825286416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=3552044217825286416' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/3552044217825286416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/3552044217825286416'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/10/interesting-agile-team-paradox.html' title='An Interesting Agile Team Paradox'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-2469027285455759398</id><published>2008-08-17T00:52:00.000-07:00</published><updated>2008-09-12T20:44:55.310-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Building Java Project with Ruby - Part II</title><content type='html'>&lt;a href="http://cotta.sourceforge.net/reports/" target="_blank"&gt;http://cotta.sourceforge.net/&lt;wbr&gt;reports/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;is now produced by this:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://cotta.svn.sourceforge.net/viewvc/cotta/trunk/rakefile.rb?revision=200&amp;amp;view=markup" target="_blank"&gt;http://cotta.svn.sourceforge.&lt;wbr&gt;net/viewvc/cotta/trunk/&lt;wbr&gt;rakefile.rb?revision=200&amp;amp;view=&lt;wbr&gt;markup&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-2469027285455759398?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/2469027285455759398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=2469027285455759398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/2469027285455759398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/2469027285455759398'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/08/building-java-project-with-ruby-part-ii.html' title='Building Java Project with Ruby - Part II'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-5223693315895537577</id><published>2008-08-13T00:02:00.000-07:00</published><updated>2008-08-13T00:06:18.501-07:00</updated><title type='text'>Building Java Project with Ruby</title><content type='html'>I probably would be stretching it if I say this is THE solution.  But would you not look at &lt;a href="http://cotta.svn.sourceforge.net/viewvc/cotta/trunk/rakefile.rb?revision=196&amp;amp;view=markup"&gt;this&lt;/a&gt; and think 'this just feels right'?&lt;br /&gt;&lt;br /&gt;Next to do:&lt;br /&gt;&lt;br /&gt;* Implement 'project.test'&lt;br /&gt;* Implement 'project.report_coverage(dir_to_emma_files)'&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-5223693315895537577?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://cotta.svn.sourceforge.net/viewvc/cotta/trunk/rakefile.rb?revision=196&amp;view=markup' title='Building Java Project with Ruby'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/5223693315895537577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=5223693315895537577' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5223693315895537577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5223693315895537577'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/08/building-java-project-with-ruby.html' title='Building Java Project with Ruby'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-1608758483431666172</id><published>2008-07-10T10:04:00.000-07:00</published><updated>2008-07-10T10:09:54.303-07:00</updated><title type='text'>Converting in Image in Ruby - Can it get any easier?</title><content type='html'>&lt;blockquote&gt;require 'RMagick'&lt;br /&gt;Magick::ImageList.new('image.jpg').write('image.tif')&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Ok, that is way too short.  Let's add crop operation:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;image = Magick::ImageList.new('image.jpg')&lt;br /&gt;image.crop(0, 0, 64, 64).write('image.tif')&lt;/blockquote&gt;(I think I can add the first example to &lt;a href="http://cotta.sourceforge.net"&gt;Cotta&lt;/a&gt;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-1608758483431666172?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/1608758483431666172/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=1608758483431666172' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/1608758483431666172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/1608758483431666172'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/07/converting-in-image-in-ruby-can-it-get.html' title='Converting in Image in Ruby - Can it get any easier?'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-7354360970387078689</id><published>2008-06-16T21:23:00.001-07:00</published><updated>2008-06-17T21:07:27.702-07:00</updated><title type='text'>Five Sprints into SCRUM</title><content type='html'>We have kicked off Sprint 5 today for Application Framework team.&lt;br /&gt;&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Guidewire&lt;/span&gt; development is following SCRUM methodology.  However, through all these years, due to various reason, the ideas behind Sprints are not exactly followed.  There are many reasons for this, some of which are actually good reasons.  However, that does not mean it was the best decision, and some development teams are trying to bring back meaningful Sprints to the development process, including AF team.&lt;br /&gt;&lt;br /&gt;So what have I done differently this time?&lt;br /&gt;&lt;br /&gt;We ended up using &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;JIRA&lt;/span&gt; to track our stories.  There are many reasons for this.  I think the first one is the kind of work we are doing right now.  We are not yet doing active development, but rather fixing bugs for a point release and run performance testing.  Since all the bugs are created in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;JIRA&lt;/span&gt; already, using &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;JIRA&lt;/span&gt; to track items that are not bugs makes it easy to track all the items we need to do given any Sprint.  On the weekly work-from-home day, which each &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;Guidewire&lt;/span&gt; employee can choose freely, it is very convenience to go to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;JIRA&lt;/span&gt; to pick the next work to do.&lt;br /&gt;&lt;br /&gt;I am still keeping a Sprint board by writing down the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;JIRAs&lt;/span&gt; on the story cards but it is not as effective as I would like it to be.  I think one reason is that &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;QAs&lt;/span&gt; are verifying the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;JIRAs&lt;/span&gt; on their own schedule. (And the reason for that is some &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;QAs&lt;/span&gt; are not part of AF team, because AF work affects other application teams). I know it sounds &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;strang&lt;/span&gt;, but that is the situation right now.  We are talking about how to get away from this mode and have a real complete independent development teams but before that happens, we will just have to pull it through.&lt;br /&gt;&lt;br /&gt;The purpose for Sprint board now is more for daily Sprint meeting, where we talk about what we have achieved yesterday and are planning to do today.  I use it to help the team focus and work on only the blocker &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;JIRA&lt;/span&gt; or the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;JIRAs&lt;/span&gt; scheduled for the Sprint. Old habits die hard but we are making progress in that direction.  When we schedule too many for the Sprint, which has been the case for all the past Sprints, I use Sprint board to figure out what to push to the next Sprint.  I have not bee doing this aggressively.  Now that I have an idea of our current velocity, I'll do more now.&lt;br /&gt;&lt;br /&gt;I am also changing the Sprint planning format.  I am not going through the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;JIRAs&lt;/span&gt; one by one and ask question on them anymore, because the feedback has been that it takes a long time and becomes uninteresting.  I think the first reason is that we are not sharing enough to make it a team conversation.  Rather, it is me and whoever owns that part of the system talking with each other and figuring out the tasks to do.  Even that, because I cannot pair on each and every &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;JIRA&lt;/span&gt;, I am not able to track and check that each &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;JIRA&lt;/span&gt; is estimated correctly and each &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;JIRA&lt;/span&gt; is done within a Sprint. Without following them up and closing the feedback loop, all the work of creating tasks and track them become rather pointless.&lt;br /&gt;&lt;br /&gt;So in the Sprint &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;plannig&lt;/span&gt;, I now show the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;JIRA&lt;/span&gt; list scheduled, talk about them briefly in groups by the functional area, and track down the estimate after the meeting.  I think I will change the estimation to be before the meeting next time, so that I would know how much to schedule for the Sprint.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-7354360970387078689?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/7354360970387078689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=7354360970387078689' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/7354360970387078689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/7354360970387078689'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/06/five-sprints-into-scrum.html' title='Five Sprints into SCRUM'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-8107836092749097331</id><published>2008-05-18T11:56:00.000-07:00</published><updated>2008-05-18T12:00:10.857-07:00</updated><title type='text'>Fix : ERROR:  While executing gem ... (Zlib::BufError)</title><content type='html'>All you need to do is&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;gem update --system&lt;/blockquote&gt;Thank you &lt;a href="http://dontrepeatyourself.wordpress.com/2007/05/14/zlibbuferror/"&gt;&lt;span class="postedby"&gt;dontrepeatyourself&lt;/span&gt;&lt;/a&gt;&lt;span class="filedto"&gt; !!!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-8107836092749097331?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/8107836092749097331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=8107836092749097331' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/8107836092749097331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/8107836092749097331'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/05/fix-error-while-executing-gem.html' title='Fix : ERROR:  While executing gem ... (Zlib::BufError)'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-4873420610620317040</id><published>2008-02-24T14:21:00.000-08:00</published><updated>2008-02-24T14:24:39.701-08:00</updated><title type='text'>Guidewire Development Blog</title><content type='html'>I have developers from Guidewire customer commenting on my blog so I would like to mention that Guidewire now has its own development blog which I think you will find interesting.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://guidewiredevelopment.wordpress.com"&gt;http://guidewiredevelopment.wordpress.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-4873420610620317040?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://guidewiredevelopment.wordpress.com' title='Guidewire Development Blog'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/4873420610620317040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=4873420610620317040' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4873420610620317040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4873420610620317040'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/02/guidewire-development-blog.html' title='Guidewire Development Blog'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-954188669043682351</id><published>2008-02-24T14:18:00.000-08:00</published><updated>2008-02-25T08:15:08.516-08:00</updated><title type='text'>Proposal for Agile 2008 Submitted</title><content type='html'>Even though I still have one more post to go for this topic on Enterprise Agile Testing, submission deadline for Agile 2008 is approaching.  So I looked at other submissions, looked at what I have written, and submitted my proposal:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://submissions.agile2008.org/node/3736"&gt;http://submissions.agile2008.org/node/3736&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Feedbacks are welcome either through the submission page or my website &lt;a href="http://www.shaneduan.com/contact.html"&gt;http://www.shaneduan.com/contact.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-954188669043682351?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://submissions.agile2008.org/node/3736' title='Proposal for Agile 2008 Submitted'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/954188669043682351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=954188669043682351' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/954188669043682351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/954188669043682351'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/02/proposal-for-agile-2008-submitted.html' title='Proposal for Agile 2008 Submitted'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-6864703047512764976</id><published>2008-02-20T23:15:00.000-08:00</published><updated>2008-03-11T17:59:30.859-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test'/><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>Enterprise Agile Testing Part III: Managing Tests with ToolsHarness, Individually</title><content type='html'>This is the third part of the Enterprise Agile Testing:    &lt;ul&gt;&lt;li&gt;&lt;a name="y:-x"&gt;&lt;/a&gt;&lt;a href="http://agileworks.blogspot.com/2008/01/enterprise-agile-testing-part-i.html"&gt;Introduction&lt;/a&gt;&lt;span style=";font-family:Symbol;font-size:9;"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Test fixtures like assertion, builder &lt;/li&gt;&lt;li&gt;&lt;a name="wapw"&gt;&lt;/a&gt;&lt;a href="http://agileworks.blogspot.com/2008/02/enterprise-agile-testing-part-ii-test.html"&gt;Test Environment Set Up with TestBase&lt;/a&gt; &lt;/li&gt;&lt;li&gt;&lt;b&gt;ToolsHarness, a continuous integration server farm that treats tests individually&lt;/b&gt; &lt;/li&gt;&lt;li&gt;&lt;b&gt;Active and stable branch, localizing the damage&lt;/b&gt; &lt;/li&gt;&lt;/ul&gt;&lt;a name="i8vm"&gt;&lt;/a&gt;&lt;a href="http://www.martinfowler.com/articles/continuousIntegration.html"&gt;Continuous Integration&lt;/a&gt; has proven to be one of the most important practices in agile software development.  Every time that a developer checks in the code, the resulting code base is rebuilt and tests are run against it.  The end result of the integration tells everyone on the project if the codebase is good enough for release.  There are some prefer &lt;a name="em_1"&gt;&lt;/a&gt;&lt;a href="http://jamesshore.com/Blog/Continuous-Integration-on-a-Dollar-a-Day.html"&gt;synchronous continuous integration&lt;/a&gt; through a push-button process over an asynchronous process through a tool like &lt;a name="pkva"&gt;&lt;/a&gt;&lt;a href="http://cruisecontrol.sourceforge.net/"&gt;CruiseControl&lt;/a&gt;.  But everyone agrees that it is something very useful.&lt;br /&gt;&lt;br /&gt;&lt;h2 style="margin-left: 0in; text-indent: 0in;"&gt;the Difficulty of Holding the Line &lt;/h2&gt;  &lt;p class="MsoBodyText" style="margin-bottom: 14.15pt;"&gt;With a tool or not, the most difficult part of installing such a process is probably holding the line of "zero broken tests".  In my past consulting and coaching experience, it sometimes takes great effort and time to get the team into the habit of running all the unit tests before checking into the code, as well as making writing tests and test fixing as the highest priority, and keep tuning the test so that the whole process does not exceed ten minutes.  Even that, not all the teams kept up with the practice after we left the project on a good note.&lt;br /&gt;&lt;br /&gt;I recently got a chance to catch up Greg, one of the ex-ThoughtWorkers that I used to work with and respect.  He showed interest in what I am writing and expressed his opinion, as I quote:&lt;/p&gt;  &lt;div style="border: 1pt solid silver; padding: 7pt; margin-left: 28.35pt; margin-right: 28.35pt;"&gt;  &lt;p class="Quotations" style="margin: 0in 0in 14.15pt;"&gt;Our test suite is too large and too slow to run with every build. We are lucky to get results once a day.&lt;br /&gt;&lt;br /&gt;- Not everyone cares about the unit tests to the same degree. Some people are too busy to track down failures right away. Not everyone sees the value in the unit tests, mostly because our coverage figures aren't high enough.&lt;br /&gt;- Not everyone has the skills to write decent tests or design their code in a modular, testable fashion.&lt;/p&gt;  &lt;/div&gt;  &lt;p class="MsoBodyText" style="margin-bottom: 14.15pt;"&gt;When I read that email, I became more motivated working on this third post, because it is exactly what I want to write about.  In my previous job, I found out that the only way to make agile development work was to follow the XP practices, especially when it comes to continuous integration.  In an enterprise environment (as defined by &lt;a name="jqqd"&gt;&lt;/a&gt;&lt;a href="http://agileworks.blogspot.com/2008/01/enterprise-agile-testing-part-i.html"&gt;Introduction&lt;/a&gt; ), there seemed to be no middle ground between "green all the time" and "red all the time".  It seemed that the moment the team fell off the status of zero broken test and couldn't recover quickly, they would be in a deep hole right away.&lt;br /&gt;&lt;/p&gt;  &lt;p class="MsoBodyText"&gt;The first thing that I have learned at Guidewire, is that the above problems can be solved better with the help of a comprehensive continuous integration tool, ToolsHarness in this case.  I am not saying this is a silver bullet, because there are still a lot of development practices and disciplines required.  But I can certainly say that I am now seeing the light.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;&lt;span class="Heading2Char"&gt;&lt;span style="font-size:130%;"&gt;Test Farm for Parallel Testing&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;  &lt;p class="MsoBodyText"&gt;  No matter how hard you try, eventually you will not have enough time to run all the tests that you would like before checking in code.  When this becomes the case, test breaking will become the norm rather than exception, and the XP way of handling broken builds would not apply anymore.  For a complicated system, the time to run the full tests will be huge.  At the same time, agile software development dictates fast feedback time on code changes.  The longer the turnaround time is, the more fraction there is on the iterative development - how is it even possible for the team to build on top of something not yet proven to be working and expect to have a high throughput?&lt;/p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_1AIWiix4RXQ/R70liHxfSoI/AAAAAAAAARk/LoUJQ_oeKaM/s1600-h/machines.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_1AIWiix4RXQ/R70liHxfSoI/AAAAAAAAARk/LoUJQ_oeKaM/s200/machines.jpg" alt="" id="BLOGGER_PHOTO_ID_5169329215423597186" border="0" /&gt;&lt;/a&gt;    &lt;p class="MsoBodyText"&gt;Guidewire has a big testing farm, composed of dozens of machines, mostly on Linux and configured with H2 database.  These machines are configured so that when a build is available, they will check out the test suites to run.  &lt;/p&gt;&lt;div id="f2w." style="padding: 1em 0pt; text-align: left;"&gt;&lt;a href="http://docs.google.com/File?id=ddf25tch_13g32tsdgz" target="_blank"&gt;&lt;br /&gt;&lt;/a&gt;&lt;/div&gt;When a developer checks in a change list, ToolsHarness will first pull the source and do a full build to make sure that the projects still compile.  Once the compiling finishes successfully, ToolsHarness will post the build for test.   The tests used to be divided into different suites based on which test class they extends, for example, Database test, Metadata test, or Server test.  With &lt;a href="http://agileworks.blogspot.com/2008/02/enterprise-agile-testing-part-ii-test.html"&gt;the introduction of TestBase&lt;/a&gt;, they are all converted to NewTestSuite and NewSmokeTestSuite.  (The difference is that the tests in NewSmokeTestSuite are acceptance tests, which are full end-to-end test and require additional sample data.)  &lt;p class="MsoBodyText"&gt; &lt;/p&gt;  &lt;p class="MsoBodyText"&gt;Based on the previous run of the test, the suites are divided evenly into several parts, so that each testing machine can check out each part and run it.  In this way through parallel testing, it takes no more than 20 minutes to run a suite that would normally take hours to finish.  This system is highly scalable, because all you need to do is adding more machines.  With such a fast feedback loop, the developers can work on the large code base and still make medium size changes.  The worst thing that can happen would be to revert the change that you made less than half an hour ago.&lt;/p&gt;  &lt;p class="MsoBodyText"&gt; &lt;/p&gt;  &lt;p class="MsoBodyText"&gt;It is easy to run the tests against different databases and J2EE servers too.  Some testing machines are configured with Oracle database or SQL database, some are configured on Windows platform, and some are configured using Tomcat or WebLogic.   As I am writing this post, the tools pod (the team in charge of developing this server) is working on ‘customer build testing’, so that the test environment will be exactly as the production environment when running the acceptance tests.&lt;/p&gt;  &lt;h2&gt;&lt;span class="Heading2Char"&gt;&lt;span style="font-size:130%;"&gt;Tracking Tests Individually&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;  &lt;p class="MsoBodyText"&gt;With a large team, you will have developers with different skill sets.  While it is easy for an senior developers to be conscious about making small changes at a time, and be able to identify the problem based on the broken test, it normally takes a much longer time for a junior developer to fix them.  Unless all your senior developers happen to be good coaches, you are going to be stuck with broken tests popping up here and there for a while.&lt;/p&gt;&lt;div id="p.ys" style="padding: 1em 0pt; text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_1AIWiix4RXQ/R70liXxfSpI/AAAAAAAAARs/WErlafsJPlQ/s1600-h/trackingtests.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_1AIWiix4RXQ/R70liXxfSpI/AAAAAAAAARs/WErlafsJPlQ/s200/trackingtests.jpg" alt="" id="BLOGGER_PHOTO_ID_5169329219718564498" border="0" /&gt;&lt;/a&gt;When a testing machine is done with the test, it will post the test result back to the ToolsHarness.  ToolsHarness will parse the XML file and store the result of each test into the database to track them.  The benefit of this is so that developers can start tracking the tests individually.  When a test is broken, ToolsHarness will make an educated guess based on the change list and changed package to assign it to the developer.  If it turns out to be wrong, the developer can easily assign it to the right person.&lt;/div&gt;&lt;div id="z7zf" style="padding: 1em 0pt; text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_1AIWiix4RXQ/R70lh3xfSnI/AAAAAAAAARc/pyjHg4JbbBE/s1600-h/desktop.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_1AIWiix4RXQ/R70lh3xfSnI/AAAAAAAAARc/pyjHg4JbbBE/s200/desktop.jpg" alt="" id="BLOGGER_PHOTO_ID_5169329211128629874" border="0" /&gt;&lt;/a&gt;When a developer logs into ToolsHarness, the first page, Desktop, contains a list of tests that have been assigned to him or her.  In this way, you won’t be distracted as long as there are no tests assigned to you.  The summary of all the tests is also on this page so that you know not to check-in anything when there are hundreds of tests broken, or give the senior developers a clue to check in others in fixing tests.&lt;br /&gt;&lt;/div&gt;  &lt;p class="MsoBodyText"&gt; &lt;/p&gt;    &lt;p class="MsoBodyText"&gt; &lt;/p&gt;  &lt;p class="MsoBodyText"&gt;For each test, you can see the failure message in the form of the stack trace, the change lists associated with it, the history of the test to help you figure out the reason that the test is broken.  You can also look into the log directory to see any additional generated file like server log and HTML page snapshots.&lt;/p&gt;  &lt;p class="MsoBodyText"&gt; &lt;/p&gt;  &lt;p class="MsoBodyText"&gt;If you have written a broken test that you cannot yet fix, you can annotate it with &lt;b&gt;KnownBreak&lt;/b&gt;, and it will show up properly in the ToolsHarness.  If you have determined that a test in failing none-deterministically but you still cannot yet figure out why, you can mark it with &lt;b&gt;NoneDeterministic&lt;/b&gt;, and it will show up as such in ToolsHarness.  The key is to keep the noise of broken to minimum, if not zero, so that developers will get the notification accurately and fix them effectively.&lt;/p&gt;  &lt;h2&gt;&lt;span class="Heading2Char"&gt;&lt;span style="font-size:130%;"&gt;Localizing the Damage through Branches&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;  &lt;p class="MsoBodyText"&gt;With aggressive refactoring, you will not be able to leave your platform code alone.  Sometimes you know that the only way to be sure is to check in the code, let the continuous integration server do a full test on the changes.   With this approach, you are going to risk putting the build into unstable state for a while before you can figure out the best solution.  If the whole development team has to rely on a good build, they will either be out of commission for a while, or they are going to accumulate changes that will cause another wave of instability after you are done.  And  that is if you are lucky enough to quickly finish with the cycle of check in, revert, revert the revert to make more changes, check in, revert, ...&lt;/p&gt;&lt;p class="MsoBodyText"&gt;Sometimes, especially for the platform team and application framework team, you need to make big change in the code base.  When it proved to break lots of tests in ToolsHarness, the best thing to do is to move forward by checking in more fixes, instead of reverting the change to do it again.  The only problem with that, is that the code base comes unstable during the process.   If you have a large team with others working on other areas at the same time, the number of broken tests could be disturbing.  And as Greg pointed out at the beginning, not every team care about the tests in the same way.  Some would prefer finishing the job at hand before tracking down the broken tests.  The line for none-deterministic tests are much more blurry.&lt;/p&gt;&lt;div id="wr_x" style="padding: 1em 0pt; text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_1AIWiix4RXQ/R70lhnxfSmI/AAAAAAAAARU/SLo4W7ZPzCw/s1600-h/branches.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_1AIWiix4RXQ/R70lhnxfSmI/AAAAAAAAARU/SLo4W7ZPzCw/s200/branches.jpg" alt="" id="BLOGGER_PHOTO_ID_5169329206833662562" border="0" /&gt;&lt;/a&gt;At Guidewire, the way to make it work for all the teams working on the same code base is through the branches.  Each team works on an 'active' branch that they are free to do whatever they feel most productive.  The only rule that they need to follow is to fix all the tests before pushing the change to the 'stable' branch, where every team is pulling change from on a daily basis.  If it takes a team a couple of week to get into a stable state, then they will have to risk the merge conflicts.  For a team that is diligent on fixing the test, their branch will be stable most of the time, and pushing would come much easier.  It is exactly like what most agile books recommend on checking code -- check in as often as possible as long as the tests are passing -- except on the level of branches.&lt;br /&gt;&lt;/div&gt;Sometimes you can still make a mistake and push a broken test (or more) into the stable.  In this case, there is a 'merge' branch that you can use to fix the builds.  Most of the time however, the fix is very easy, then all you need to do is to find out which team is next in line to push to stable, and manually integrate your fix into their branch.  There are merge script written in Ruby to help the pull and push process.  They are very robust and well tested, so that majority of the push and pull are merely a push-button process, i.e., you type in the command "merge.rb --pull", and you are good to go.  We have a merge machine set up specifically for this job, so that the merger wouldn't have to give up his or her local resources.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;span class="Heading2Char"&gt;&lt;span style="font-size:130%;"&gt;Antidote&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p class="MsoBodyText"&gt; As many articles, books, blogs have pointed out, people are always the center of the agile development process.  Even with a powerful tool like ToolsHarness, it is still up for the team to apply disciplines and agile practices.  Because the team does not have to stop everything to fix any broken tests, it is actually easy for people to ignore the tests.  Given enough time, enough code changes would have been checked in, making it much harder than it should be to fix the tests.&lt;/p&gt;&lt;br /&gt;So the rule of the thumb is still the same: fixing any broken test as quickly as possible when they come up.  The old tricks still apply, which including things like revert the changes that broke the build, make small changes, check-in often, monitoring email notifications, run tests before checking in, etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-6864703047512764976?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/6864703047512764976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=6864703047512764976' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/6864703047512764976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/6864703047512764976'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/02/enterprise-agile-testing-part-iii.html' title='Enterprise Agile Testing Part III: Managing Tests with ToolsHarness, Individually'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_1AIWiix4RXQ/R70liHxfSoI/AAAAAAAAARk/LoUJQ_oeKaM/s72-c/machines.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-7482599668161515863</id><published>2008-02-08T17:15:00.000-08:00</published><updated>2008-02-21T21:31:52.590-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test'/><title type='text'>Enterprise Agile Testing Part II : Test Environment Set Up with TestBase</title><content type='html'>This is the second part of the Enterprise Agile Testing (Not exactly following my original order here):&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a title="Introduction" href="http://agileworks.blogspot.com/2008/01/enterprise-agile-testing-part-i.html" id="y:-x"&gt;Introduction&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Test fixtures like assertion, builder&lt;/li&gt;&lt;li&gt;&lt;b&gt;Test Environment Set Up with TestBase&lt;/b&gt;&lt;/li&gt;&lt;li&gt;ToolsHarness, a continuous integration server farm that treats tests individually&lt;/li&gt;&lt;li&gt;Active and stable branch, localizing the damage&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h2&gt;Testing through Inversion of Control (IoC) Container&lt;br /&gt;&lt;/h2&gt;(For concept of IoC container, see Martin Fowler's article: &lt;a title="Inversion of Control Containers and the Dependency Injection Pattern" href="http://www.martinfowler.com/articles/injection.html" id="uc_:"&gt;Inversion of Control Containers and the Dependency Injection Pattern&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;Ever since testing through dependency injection was formally named, it has become the most popular pattern for unit testing.  You control the environment in which the class is tested by carefully constructing the classes in the dependency before injecting them into the class under test.  In this style, a typical test is composed of three parts.  They are named differently if you talk to different people, but the one that I like is what I learned when I presented the "Given, When, Ensure" notation of jBehave to BayXP meetings:&lt;br /&gt;&lt;br /&gt;* Assemble: Construct the environment that the test is going to run.&lt;br /&gt;* Act: Invoke the method(s) that you want to test.&lt;br /&gt;* Assert: Assert that the tested method has caused the predicted change in the environment.&lt;br /&gt;&lt;br /&gt;It is safe to say that anyone who has done enough testing won't have any problem with "Act" and "Assert".  It is the "Assemble" that has been giving us trouble.  The following is an illustration extending &lt;a title="PicoContainer's diagram" href="http://www.picocontainer.org/introduction.html" id="h.c_"&gt;PicoContainer's diagram&lt;/a&gt;.&lt;br /&gt;&lt;div id="rci:" style="padding: 1em 0pt; text-align: left;"&gt;&lt;div id="t5og" style="padding: 1em 0pt; text-align: left;"&gt;&lt;div id="h_t8" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img style="width: 365px; height: 195px;" src="http://docs.google.com/File?id=ddf25tch_11fmgcwchm" /&gt;&lt;/div&gt;To test the class marked by the big arrow, you will need to create the world as this class sees, then invoke methods on class and assert changes caused by the invocation.  Among the ways of constructing the world according to the class under test, Stub and Mocks are probably the only pattern that has been &lt;a title="well documented" href="http://martinfowler.com/articles/mocksArentStubs.html" id="jyw7"&gt;well documented&lt;/a&gt;.  As indicated by the article, each solution has its own limitations.  For a small to medium size application, these kind of tests are generally manageable.  But if you have done enough enterprise application development (as defined in &lt;a href="http://agileworks.blogspot.com/2008/01/enterprise-agile-testing-part-i.html"&gt;Introduction&lt;/a&gt;), then you probably have seen your fair share of mocks and stubs getting out of hand, as was the case for Guidewire tests until year 2007.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2&gt;Testing with a Loaded Container&lt;/h2&gt;During the past year, Guidewire has been slowly converting its tests onto a home-grown JUnit extension framework.  The framework does the heavy lifting of constructing the dependencies, so that by the time the test code is called, &lt;b&gt;all&lt;/b&gt; the dependencies have already been set up properly.  If you really want to, you can even access a full web container through the &lt;a href="http://www.mortbay.org/"&gt;embedded Jetty server&lt;/a&gt;.  By putting your class inside a full container, you get a lot of benefits that you won't normally with a bare bone unit test, and you without breaking a sweat.&lt;br /&gt;&lt;br /&gt;The immediate benefit is that you no long deal with mocking, stubbing, guessing.  When your test calls into a method, you can be sure that the class would be in the same state as it is called in the real world (It might still not be in the one that you want in your test but that is a separate issue).  Without mocking and stubbing, you don't need to walk on the egg shells any more as you change the class responsibilities and collaborations.  You can call into a real messaging manager through the container, enable a message destination, commit an entity, and test that the message of the changes appear.  All the codes paths match exactly the real world, so that your won't have any integration surprises down the road.&lt;br /&gt;&lt;br /&gt;Because all the required validations are turned on, you are forced to create realistic data.  With realistic data, your test becomes more realistic.  You can put your test under debug mode at any time and get a good sense of what the data will be like in a real server.  If you make a mistake and forget to set a non-nullable field, your test will blow up right away.&lt;br /&gt;&lt;br /&gt;With a loaded container, you feel more confidence in the class that you are designing.  Because you can see easily how this class fits into the whole world, you can make sure it becomes a good citizen by doing just its job, no more, no less.&lt;br /&gt;&lt;br /&gt;This framework is extremely flexible, making it very powerful.  You can modify the testing environment by annotating your test and registering your own annotation handlers.  In this way, you can add additional set up code without even creating your own super test base, a typical case of &lt;a title="prefer composition over inheritance" href="http://guidewiredevelopment.wordpress.com/2008/02/05/favoring-composition-over-inheritance/" id="l28z"&gt;favoring composition over inheritance&lt;/a&gt;.  You will see many annotations that we have built already in the past half year.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Performance Improvement Considerations&lt;/h2&gt;Of course, all these are much easier said than done.  And we are sort of going against the conventional wisdom of unit testing here.  The first question most readers will raise would probably be "Loading the whole container for a simple unit test???  How can your test perform!?"  Please trust me when I say that I had the same concerns.  But after adapting to it for half a year, I think this is definitely a good solution.&lt;br /&gt;&lt;br /&gt;First of all, performance is overrated.  No, I am just kidding.  The first thing that I would like to say is that if you are a TDD veteran, in that you know how to design your class such that you can manage your own dependencies well most of the time, then kudos to you and you can use the @RunLevel annotation to tell the framework not to do any set up that for you (see below)&lt;br /&gt;&lt;br /&gt;I was actually not totally joking.  I would like to argue that for an enterprise application (as described in &lt;a href="http://agileworks.blogspot.com/2008/01/enterprise-agile-testing-part-i.html"&gt;Introduction&lt;/a&gt;), it is not uncommon that some part of the system is not designed as cleanly as it could have been.  As a result, you have to choose between making the test run fast through the kind of mock that no one knows what is going on, or making the test run a bit slower but reflects the real system.  Since design validation is the whole purpose of tests, I vouch for testing the right thing with a bit of sacrifice on the speed.&lt;br /&gt;&lt;br /&gt;In addition, the test framework has a set of performance considerations in place to make sure that overall the test performs well.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Run  Level&lt;/h3&gt;Guidewire applications have the notion of run level as a way to bring the system online in stages.  You can annotate each test with the desired run level to have just the things you need set up before the test.  The following is the list of run levels that I have used.&lt;br /&gt;&lt;br /&gt;* NONE: This is just like good-old jUnit test.&lt;br /&gt;* Shutdown: At this level, you have all the system configuration read in and meta data loaded.  You can run any test that does not touch database&lt;br /&gt;* No Daemon: This is the default value.  At this level, you have the database connection initialized and the schema updated.  You can run any test that hits the database.&lt;br /&gt;* Multiple User: At this level, you have a full blown application server with background batch process running.  This is typically used by QA for acceptance testing.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Database Tests&lt;br /&gt;&lt;/h3&gt;By default, all tests are using &lt;a title="H2" href="http://www.h2database.com/" id="notf"&gt;H2&lt;/a&gt; as the embedded databases which greatly improves the test performance.  I have been a &lt;a title="big fan on in-memory database" href="http://agileworks.blogspot.com/2004/09/hsqldb-and-database-design-issue.html" id="y8bm"&gt;big fan on in-memory database&lt;/a&gt; since HSQLDB.  &lt;a title="DBFixture" href="http://gforge.public.thoughtworks.org/projects/dbfixture/" id="j9mu"&gt;DBFixture&lt;/a&gt; is the proof.&lt;br /&gt;&lt;br /&gt;During the development, the database schema changes all the time.  Guidewire products have an upgrader built in place to compare the database schema and automatically issues SQL statements to upgrade the database to the right schema.  However, the upgrade process can take time. To save time, a backup copy is created after the upgrade finishes so that the database can be restored as necessary (See @ChangesSchema).  There is one implementation for each database that we officially support so all the tests can run on all databases if we choose to.&lt;br /&gt;&lt;br /&gt;For each table there is also a shadow table that stores the default data set up by the test environment.  Before each test run, the data in each table is restored from the shadow.  In this way, different tests won't step on each other's toes and end up causing other tests to fail.  For performance reason, the data is only restored once for each test classes, because it is easier to make sure that the test methods in the same test class don't affect each other's data.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Server Mode for Web Testing&lt;/h3&gt;The QA acceptance tests are written in GScript.  When running in browser mode, it uses &lt;a title="Selenium" href="http://selenium.openqa.org/" id="d6c:"&gt;Selenium&lt;/a&gt; to drive the browser to connect to the server and run tests.  However, when you have enough tests, the slowness of the browser really shows.  Guidewire applications are built on top of JSF framework, where the generated HTML source is driven by the page model on the server.  With the exactly same script, we can run them in server mode, where the scripts are run against the page models in the server session.  Without the browser layer, HTTP connection, HTML generation and parsing, the test run is cut down dramatically again.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Functional Considerations&lt;/h2&gt;The meta data layer of Guidewire applications is extremely extend-able and configurable, and the SQL being executed in the database layers is generated dynamically based on the metadata configuration and the database set up.  It would not be practical to mock out the whole thing.  The test framework provides a fixed out-of-the-box container for each test and locks it down so that the test or the code under test wouldn't accidentally try to change those dependencies.  But the developers can modify the test environment through annotations.  The following are the typical annotations:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;@IncludeModules&lt;/span&gt; for Configuration Testing: With this annotation, you can specify a list of directory where the test should load the additional configuration from.  In this way, you can configure the test environment (registering additional plugin, registering additional SOAP interface, extend the basic data model, add additional web pages, etc.).   This is great when you want to test different configuration cases, and still leave the base configuration simple and fast.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;@ChangesTime&lt;/span&gt; for Time-based Testing: Sometimes your test is date sensitive.  With this annotation, you get a hook to change the system date on the fly before you creates the data you want so that timestamp meets your condition.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;@ChangesSchema&lt;/span&gt; for upgrade testing: With this annotation, your test can run wild and make a havoc of the database schema.  At the end of your test, the schema will be restored from the backup automatically.  This is very useful for upgrader related tests.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Testing Annotations&lt;/h2&gt;These are the additional annotations telling the test framework how you want your test to run:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;@ProductUnderTest&lt;/span&gt;: You can write a test, put it in a common module and tell the test framework which product you want this test to run.  For example, we need to make sure that the base data model can pass the validation for all applications.  We can write a test that will start the validation without being dependent on which product it is.  With this annotation, the same test can be run with data model from each products.  Think dependency injection on production is a good way to go?  Why not apply it to test?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;@TestInDatabase&lt;/span&gt;: From time to time, you have to implement something that is a little different for different databases, or a feature that is only applicable to one database (Oracle AWR report, for example).  With this annotation, you can tell the test framework which database this test should be run against.  By default, all tests are running in H2 database only for performance reason.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;@DoNotRunInHarness&lt;/span&gt;: This is for push-button tests that cannot be run automatically.  For example, we have a test that pings map point web services and make sure that we can parse the result properly.  Map point ended up telling us not to ping their staging server continuously.  So this test is disabled in the testing server.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Testing Semantics&lt;br /&gt;&lt;/h2&gt;&lt;div style="text-align: left;"&gt;There are also other productivity improvements.  Your test case can now implement &lt;span style="font-weight: bold;"&gt;beforeClass()&lt;/span&gt;, &lt;span style="font-weight: bold;"&gt;afterClass()&lt;/span&gt;, &lt;span style="font-weight: bold;"&gt;beforeMethod()&lt;/span&gt; and &lt;span style="font-weight: bold;"&gt;afterMethod()&lt;/span&gt; to be run in the way, well, as the name indicated.  After answered enough question about when &lt;span style="font-weight: bold;"&gt;setUp()&lt;/span&gt; and &lt;span style="font-weight: bold;"&gt;tearDown()&lt;/span&gt; are run, I think it is a nice change.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Because jUnit holds on to ALL the test instances, each fields in the test class is actually a memory leak as far as the test concerns.  The test framework automatically null out all the fields (with some configurable exceptions) at the end of the test case when all the tests methods are done.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Other Considerations&lt;/h2&gt;This kind of test writing is also supported by our other development practices, namely ToolsHarness and Branching strategy, which I will cover in detail in later posts.&lt;br /&gt;&lt;br /&gt;With your tests covering more code, the tests could very well break for the wrong reason.  With the ToolsHarness, we were able to exam each test failure easily, locate and isolate the problems easily and the development won't grind to a halt every time there is a broken test.  With the test farm provided by the ToolsHarness, our test can run concurrently so we can have better tolerance on the speed of individual test.&lt;br /&gt;&lt;br /&gt;With the branching strategy, we are making sure that the platform code is in a good enough state before it is released to the application team.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Appendix: Things to watch out for&lt;/h2&gt;At the same time we creating a path to make test easier to write, we also put ourselves on a slippery slope that could lead us further and further away from effective unit testing.  Sometimes it is much easier to write a test that covers a lot of than to set up the environment so that only the code you want to be tested will be tested.  Why is that bad?  Here is an example:&lt;br /&gt;&lt;br /&gt;As I am writing this post, I am wrapping up a feature called "Field Level Encryption" by adding upgrade support from an earlier version of the application.  It was extremely tempting to do the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  // the column is length 6 nullable, alter it to leng 3 and not nullable&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  String[] sqls = getDbCatalogSupport().alterColumn(table, column).withLength(3).withNullability(false).getSql()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  DatabaseTestUtil.updateInTx(sqls)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  // Insert data that need to be updated&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  DatabaseTestUtil.updateInTx("insert into px_test_encryption (id) values (1)")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  // run the upgrader to make sure it does not fail&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  new Upgrader(database).upgrade()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  // run the schema checking to make sure everything is up-to-date&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  List&lt;string&gt; error = new DatabaseSchemaVerifier(getDbCatalogSupport.buildSchema()).verifyAll()&lt;/string&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  assertThat().list(error).isEmpty()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  Object[] row = assertThat().sql("select encrypted_field from px_test_encryption where id = 1", new Class[] {String.class}).hasOneRow()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  assertThat().array(row).is("tluafeddefault")  // null column should be updated with encrypted default value.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I am very sure that we can all agree that this is very concise and expressive.  Change the database schema, insert data, run the upgrade, make sure that the schema is now up-to-date and that the row is updated correctly, just like it should be, right?&lt;br /&gt;&lt;br /&gt;Not quite...&lt;br /&gt;&lt;br /&gt;The problem with this test lies in the "upgrade()" and "verifyAll()" method calls.  They are both very comprehensive and cover a lot of area.  As a result, this test runs for a long time (over a minute).  At the same time, someone could check-in a code with bug in either the upgrade code, or schema verification that has nothing to do with encryption, and this test will be broken.  In an enterprise environment, you only need a small portion of tests like this to generate enough noise.  And eventually developers will be so tire of spending time on a broken test only to find out that three other people are also looking at it and it will be fixed by one of them.  You will start delaying looking at broken tests and they will stay broken for a long time, other changes will be applied on top of the changes that broke the test, you will have a hard time fixing them, you will start hate tests, you will write less, the quality of the product will go down...&lt;br /&gt;&lt;br /&gt;So, for the sake of everybody, lets spent more time making the test as fine-grained as possible&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  // the column is length 6 nullable, alter it to leng 3 and not nullable&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  String[] sqls = getDbCatalogSupport().alterColumn(table, column).withLength(3).withNullability(false).getSql()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  DatabaseTestUtil.updateInTx(sqls)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  // Insert data that need to be updated&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  DatabaseTestUtil.updateInTx("insert into px_test_encryption (id) values (1)")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  // run the upgrader to make sure it does not fail&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  new Upgrader(database).encryptDecrptUpgrade()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;... (Some other code to verify just this schema)...&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  Object[] row = assertThat().sql("select encrypted_field from px_test_encryption where id = 1", new Class[] {String.class}).hasOneRow()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;  assertThat().array(row).is("tluafeddefault")  // null column should be updated with encrypted default value.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;However, this is not to say a test like the original one does not provide some value for being comprehensive.  We do have upgrade tests like this for specific kind of upgrades, the ones that our customers are going to go through.  Those tests will load the database from a backup so that the schema matches the ones that we release to our customer, then we run upgrader through it and verify that the schema is up-to-date.  Each test also has an opportunity to insert additional data before the upgrade and do additional verification after the upgrade.  In this way, when our customers get our newer build, rest assured the upgrade will not blow up horribly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-7482599668161515863?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/7482599668161515863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=7482599668161515863' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/7482599668161515863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/7482599668161515863'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/02/enterprise-agile-testing-part-ii-test.html' title='Enterprise Agile Testing Part II : Test Environment Set Up with TestBase'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-3807202527526934466</id><published>2008-01-12T20:03:00.000-08:00</published><updated>2008-10-24T21:13:38.819-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='Test'/><category scheme='http://www.blogger.com/atom/ns#' term='Enterprise'/><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>Enterprise Agile Testing Part I : Introduction</title><content type='html'>The idea of "Enterprise Agile Testing" has been in my head for several months now, result of what I have learned at Guidewire and based on my previous XP experience at ThoughtWorks. I am planning on a proposal to &lt;a title="Agile 2008" target="_blank" href="http://www.agile2008.org/" id="vms7"&gt;Agile 2008&lt;/a&gt; on this topic. Before I can choose my proposal topic, I need to write everything down first, kind of like a project engagement.&lt;br /&gt;&lt;br /&gt;Actually, project engagement is not a bad analogy. I must define what my proposal is about and what it not about --- what is out of scope if you will. My approach is to write a series of blog posts, each cover a specific topic and look back to see what I end up with when I am done. If I approach it as if I like writing a book or even like &lt;a title="that agile 2007 paper" href="http://www.agile2007.org/index.php?page=sub/&amp;amp;id=542" id="zg-_"&gt;that agile 2007 paper&lt;/a&gt;, I might never finish it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;b&gt;The Enterprise in Agile Testing&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Enterprise &lt;/i&gt;here means large scale software development. The large scale can come about through a large code base or a large team. Here I am ignoring the controversial topic of whether or not large code base or large team are problems that should be avoided in the first place. They exist, I just want to point out two things that result from them with regarding testing in such an environment.&lt;br /&gt;&lt;br /&gt;First, with a large code base, a tester cannot clearly hold onto the code's design in his or her head, let alone the intention of the test. Instead, agile testing in enterprise environments requires a comprehensive testing framework. This framework must do more than what JUnit does out-of-the box, so that anyone (including you) can come back to a test at any time and understand it.&lt;br /&gt;&lt;br /&gt;Second, with large team, it is pretty much impossible to ensure everyone is aware of how important testing is. This is not to say that you should give up on a large team's continuous improvement on treating testing seriously and writing better tests, but I have found out that the line of "Zero Test breakage" is extremely hard to hold. As a result, some middle ground must be reached between complete awareness and total ignorance.   Only in this way is it possible to see results in testing improvement efforts.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;b&gt;Agile&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Since &lt;a href="http://www.melstrom-myers.com/"&gt;Rob&lt;/a&gt; and &lt;a href="http://jamesshore.com/"&gt;Jim&lt;/a&gt; pulled me away from the EJB madness and introduced me to the wonderful world of XP in 2001, "Enterprise" has slowly restored its place in my vocabulary. At the same time, the term "Agile" is getting closer and closer to my list of &lt;a href="http://agileworks.blogspot.com/2006/08/good-read-eight-barriers-to-effective.html"&gt;red flag words&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Agile&lt;/i&gt; here refers to the situation where the code is constantly under changes. This can happen because the requirements keep changing, or the development is done iteratively through story driven development. Constant change makes the ability to write concise tests more important.  Additionally, the tests status of project must be treated as more than a binary state if testing is to keep pace with development. In this way, the development would not be paralyzed because there will almost always a test broken here and there, and the turn-around time for testing the checked-in code is not as short as 10 minutes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;b&gt;Testing&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So you have a large project code base that you keep changing, with a team of members with mixed skills. You need to ensure that the code (including the tests) you write is of high enough quality so that two moths from now you can still read them, understand what they do, understand why they do that, and change them. At the same time, you want to give others the time and tools to adjust to test infected development and hopefully test-driven development eventually.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;b&gt;Content and Structure&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, the above is the introduction.  The items that are in my mind are as following, I'll update the links as I post them.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Test utilities like assertion, builder&lt;/li&gt;&lt;li&gt;TestBase with annotations for test environment configuration&lt;/li&gt;&lt;li&gt;ToolsHarness, a continuous integration server that treats tests individually&lt;/li&gt;&lt;li&gt;Active and stable branch, localizing the damage&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-3807202527526934466?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/3807202527526934466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=3807202527526934466' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/3807202527526934466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/3807202527526934466'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/01/enterprise-agile-testing-part-i.html' title='Enterprise Agile Testing Part I : Introduction'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-292005366643358603</id><published>2008-01-08T23:19:00.001-08:00</published><updated>2008-01-10T07:54:34.475-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Story'/><category scheme='http://www.blogger.com/atom/ns#' term='Estimation'/><title type='text'>Team Estimation Game - By Steve Bockman</title><content type='html'>Well, &lt;a href="http://stevebockman.com/"&gt;Steve&lt;/a&gt; didn't have time to put it up his website, so I figure I'll write up what I have learned here.&lt;br /&gt;&lt;br /&gt;I ran into Steve during the agile 2007 conference so I invited him to do the session for us at BayXP.  Last October, Steve came down and hosted a session of the Team Estimation Game.  This is the first time I learned it I really liked it.&lt;br /&gt;&lt;br /&gt;Given a set of defined stories, the purpose of this game is to come to the consensus about the relative estimation of the work to be done for each story.  If you don't have a set of stories to try it out, you can use the sample produced by Steve &lt;a href="http://www.shaneduan.com/estimation/Story_Labels.doc"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So once you have all the story cards, you first estimate their complexity relative to each other:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Place Story Cards in pile on table.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;First player places top card on playing surface.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Next player places top card on playing surface relative to first card.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; Next player can either:&lt;br /&gt;* Play top card from pile, or&lt;br /&gt;* Move a card on the playing surface, or&lt;br /&gt;* Pass&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Repeat Step 4 until&lt;br /&gt;    a) no more cards remain in pile, and&lt;br /&gt;    b) no player wishes to move a card&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Here is an example of the result:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_1AIWiix4RXQ/R4W1iRjMZmI/AAAAAAAAAO4/mYOOozMUP84/s1600-h/storyestboard.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_1AIWiix4RXQ/R4W1iRjMZmI/AAAAAAAAAO4/mYOOozMUP84/s200/storyestboard.png" alt="" id="BLOGGER_PHOTO_ID_5153724949026596450" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;After the first stage is finished, you can now go on to assign points to them so that you can track your team velocity:&lt;br /&gt;&lt;br /&gt;6) As a team, choose estimation units and values.&lt;br /&gt;&lt;br /&gt;With the agreed units:&lt;br /&gt;&lt;br /&gt;7) Place an estimate at the top of each column.&lt;br /&gt;8) Change estimates until all team members agree.&lt;br /&gt;&lt;br /&gt;We did it during the meeting and it went very smoothly.  The interesting thing is that Steve told us the result is not too much different from the ones that he has conducted elsewhere with other groups.&lt;br /&gt;&lt;br /&gt;I am definitely going to try it on my next story estimation session.&lt;br /&gt;&lt;br /&gt;References:&lt;br /&gt;&lt;br /&gt;* &lt;a href="http://en.wikipedia.org/wiki/Planning_poker"&gt;Planning poker&lt;/a&gt;, which is another popular and useful estimation game.&lt;br /&gt;* Steve's slides: &lt;a href="http://www.shaneduan.com/estimation/Team_Estimation_Game.ppt"&gt;http://www.shaneduan.com/estimation/Team_Estimation_Game.ppt&lt;/a&gt;&lt;br /&gt;* Planning Poker Cards you can buy &lt;a href="http://www.mountaingoatsoftware.com/products/cards"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-292005366643358603?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/292005366643358603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=292005366643358603' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/292005366643358603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/292005366643358603'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2008/01/team-estimation-game-by-steve-bockman.html' title='Team Estimation Game - By Steve Bockman'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_1AIWiix4RXQ/R4W1iRjMZmI/AAAAAAAAAO4/mYOOozMUP84/s72-c/storyestboard.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-5496441053564097490</id><published>2007-11-08T16:58:00.000-08:00</published><updated>2008-01-15T22:43:16.183-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XP'/><title type='text'>Paired Programming</title><content type='html'>I posted this internally at Guidewire today in response to a "meta-analysis of  empirical studies done on analyzing the effectiveness of Pair  Programming." shared by colleague.  Then I thought this is actually a pretty good short summary of my point on Paired Programming nowadays:&lt;br /&gt;&lt;br /&gt;As useful as they are, my problem with these analysis is that they are trying to isolate the behaviors that work best when  applied together.  This applies to TDD, team development, short iteration, continuous integration, etc.&lt;br /&gt;&lt;br /&gt;Unlike engineering, software development is actually a discovery process, during which most of the value comes when discoveries are put together.  For example, when two heads get together, the value is not only about performing complex programming tasks correctly, sometimes it is actually more about realizing that there are other parts in the system that can help with the current task, or even not to attempt because someone has already tried.&lt;br /&gt;&lt;br /&gt;On the other hand, programming is a highly concentrated task.  Once interrupted, it always takes a while to get back to the mode, and we all know how frequent interruption is during a normal work day.  With paired programming, you can actually keep the flow even when one person is interrupted for a short period of time.  There are practices that you need to do to make sure that this is really the case.  For example, it it turns that the the person is going to help another pair for a long period of time, the right thing to do is to switch the pair, etc.&lt;br /&gt;&lt;br /&gt;Also the practices of XP work the best when they are working together.  For example, rotating your pair routinely help the  effectiveness of the paired programming.  If you do TDD during the paired programming, it will help the two people to focus and  lower the overhead of communication.&lt;br /&gt;&lt;br /&gt;One last thing that I have found out about paired programming is that it helps the team communication.  Paired programming forces the two people to talk constantly, which creates the "omni-communication".  I know some people find it annoying.  But I have sit in such environment on many occasions and once you get used to it, the kind of information you can pick up without any effort is very surprising.  Many project managers I talked to also reported that because of the "omni-communication" they pretty much eliminated the "status meeting" and replaced it with "issue resolving meeting".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-5496441053564097490?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/5496441053564097490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=5496441053564097490' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5496441053564097490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5496441053564097490'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/11/paired-programming.html' title='Paired Programming'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-8824616925070598806</id><published>2007-11-07T11:00:00.001-08:00</published><updated>2008-01-15T22:44:08.709-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Project Management'/><title type='text'>Thoughts of the Day</title><content type='html'>This person posted a blog with the following content, then posted another blog saying he just deleted it and made the apology.  Several weeks later, he posted another blog saying he is quitting.&lt;br /&gt;&lt;br /&gt;I don't know the details, but I swear to agile god that I would rather quit than have this happen on my team.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;It doesn’t bring any benefit , Pardon I asked stunned to hear the response I reeled in surprise as I took in what I was being told I mentally backed up a bit so in effect the team lead on a high value project was telling me not to worry and more to the point it was unlikely that anyone at least anyone on his team would ever worry about refactoring a piece of code I had come across because it worked and it was unlikely we would ever need to change it!&lt;br /&gt;&lt;br /&gt;I wanted to say but its wrong , its bad code but I didn’t I stood there and said oh ok I understand and I walked away and sat back down and carried on letting my fingers fly across the keyboard trying hard to block out the bad code screaming at me form the other file.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-8824616925070598806?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/8824616925070598806/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=8824616925070598806' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/8824616925070598806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/8824616925070598806'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/11/thoughts-of-day.html' title='Thoughts of the Day'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-2109056748024079248</id><published>2007-10-15T08:57:00.000-07:00</published><updated>2008-01-15T22:44:24.068-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>Green Day Blog</title><content type='html'>Something hilarious: &lt;a href="http://www.youtube.com/watch?v=T4SDQu7Izrk"&gt;http://www.youtube.com/watch?v=T4SDQu7Izrk&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And something useful:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; &lt;a href="http://www.bankrate.com/brm/news/energy-environment-2007/environmental_myths_a1.asp?caret=3a"&gt;http://www.bankrate.com/brm/news/energy-environment-2007/environmental_myths_a1.asp?caret=3a&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.guidewire.com/blog/marcusryu/archives/2007/10/more_important.html"&gt;http://blog.guidewire.com/blog/marcusryu/archives/2007/10/more_important.html&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-2109056748024079248?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.bankrate.com/brm/news/energy-environment-2007/environmental_myths_a1.asp?caret=3a' title='Green Day Blog'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/2109056748024079248/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=2109056748024079248' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/2109056748024079248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/2109056748024079248'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/10/green-day-blog.html' title='Green Day Blog'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-5223198445388077889</id><published>2007-09-19T08:27:00.000-07:00</published><updated>2008-01-15T22:44:35.715-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OperSource'/><title type='text'>Cotta 1.2 Release</title><content type='html'>I have got quite a few good feedback from Brian who is using it ('in anger'!) at Guidewire.  So I am putting together a 1.2 release, even though the change list is really small.&lt;br /&gt;&lt;br /&gt;This also include some &lt;a href="http://cotta.sourceforge.net/javadoc/"&gt;JavaDoc&lt;/a&gt; updates.  Even though I am not a believer myself on JavaDoc, I have come to realize that it is still a recognized way of communication and sometimes preferred over email or forum.&lt;br /&gt;&lt;br /&gt;(I have been writing drafts about the work that I have been doing at Guidewire, just never been able to publish any of them...  Not good if I want to keep this blog alive)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-5223198445388077889?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://cotta.sourceforge.net' title='Cotta 1.2 Release'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/5223198445388077889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=5223198445388077889' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5223198445388077889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5223198445388077889'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/09/cotta-12-release.html' title='Cotta 1.2 Release'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-3895844078588212700</id><published>2007-09-07T08:03:00.000-07:00</published><updated>2008-01-15T22:44:50.779-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OperSource'/><title type='text'>WebGen, Cool!</title><content type='html'>I finally run into &lt;a href="http://webgen.rubyforge.org/"&gt;WebGen&lt;/a&gt; today when checking out &lt;a href="http://rspec.rubyforge.org/"&gt;rSpec&lt;/a&gt;.  So far by the look of it, it is exactly what I have been looking for for the last two years!  Of course, that means that one third of my work with &lt;a href="http://buildmaster.rubyforge.org/"&gt;BuildMaster &lt;/a&gt;will be out of commission, but this is such a good thing!&lt;br /&gt;&lt;br /&gt;I supposed this was bound to happen sooner or later.&lt;br /&gt;&lt;br /&gt;I thought it was a bit odd that I didn't find anything interesting when I had the idea of generating a static HTML website based on specified template and using wiki style format like &lt;a href="http://hobix.com/textile/"&gt;Textile&lt;/a&gt;.  I had several simple websites to generate at that moment (&lt;a href="http://www.shaneduan.com/"&gt;my homepage&lt;/a&gt;, jBehave at the time, &lt;a href="http://cotta.sourceforge.net/"&gt;Cotta&lt;/a&gt;, and &lt;a href="http://buildmaster.rufyforge.org/"&gt;BuildMaster&lt;/a&gt;), so I settled for creating one of my own with &lt;a href="http://buildmaster.rubyforge.org/history.html"&gt;some simple Ruby script as the base&lt;/a&gt;.  It worked out well because I have been able to update the content very easily.  Earlier this year, I also set up the &lt;a href="http://selenium.rubyforge.org/"&gt;selenium Ruby&lt;/a&gt; project very easily.&lt;br /&gt;&lt;br /&gt;It didn't come without a price, when I &lt;a href="http://agileworks.blogspot.com/2006/07/buildmaster-070-released.html"&gt;released BuildMaster 0.7.0&lt;/a&gt; .  I just settled for the fact that there is simply not one that is easily found.  I also try my best to enhance it to be more powerful and flexible but I just never got enough time.&lt;br /&gt;&lt;br /&gt;Now with WebGen, I can finally take something off my plate and still get what I want.  Since I wrote those websites with Textile syntax already, I don't see a big content format conversion either.&lt;br /&gt;&lt;br /&gt;My first reaction was that "Man I wasted a lot of time because the lack of information".  Then I realized that I learned pretty much everything I know about Ruby and rSpec while working on this module, and that the &lt;a href="http://agileworks.blogspot.com/2006/09/buildmaster-surgery-moving-to-cotta.html"&gt;Cotta layer&lt;/a&gt; that I extracted out of it is still very valuable.  So even though I do need to do a better research next time, this time it worked out for the best.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-3895844078588212700?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/3895844078588212700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=3895844078588212700' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/3895844078588212700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/3895844078588212700'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/09/webgen-cool.html' title='WebGen, Cool!'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-8224014198572358421</id><published>2007-08-19T19:51:00.000-07:00</published><updated>2008-10-24T21:32:07.397-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Publications'/><category scheme='http://www.blogger.com/atom/ns#' term='Continuous Integration'/><title type='text'>Agile 2007 Experience Report</title><content type='html'>It is finally over.  Julian and I have been working hard on this experience paper for agile 2007, and I have just come back from the trip to Washington DC for the &lt;a href="http://www.agile2007.org/index.php?page=sub/&amp;amp;id=542"&gt;presentation&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The title of the paper is "Large Build Teams: Help or Hindrance?".  If you &lt;a href="http://www.google.com/search?q=Large+Build+Teams%3A+Help+or+Hindrance%3F&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;aq=t&amp;amp;rls=org.mozilla:en-US:official&amp;amp;client=firefox-a"&gt;google it&lt;/a&gt;, you should see an older version.&lt;br /&gt;&lt;br /&gt;When I got the copy of the experience reports at the agile 2007 registration booth, it sure feels good to flip through the pages and locate the fruit of my hard work in print.  Now I really admire the authors who can keep coming up with good books.&lt;br /&gt;&lt;br /&gt;The presentation itself went very well too, although I wish I had more time to make a good point of what I have learned in this project.  Oh well, those who are interested can certainly read the report and contact me directly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-8224014198572358421?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/8224014198572358421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=8224014198572358421' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/8224014198572358421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/8224014198572358421'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/08/agile-2007-experience-report.html' title='Agile 2007 Experience Report'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-6159245282233756745</id><published>2007-08-13T12:29:00.001-07:00</published><updated>2008-01-15T22:46:03.171-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>How Old is the Concept of "Inversion of Control"?</title><content type='html'>Think this &lt;a href="http://www.martinfowler.com/articles/injection.html"&gt;article by Martin Fowler&lt;/a&gt;, probably most quoted, is the first one talking about this concept?  Well, then we were both wrong, because I have just found out this article, "&lt;a href="http://www.objectmentor.com/resources/articles/dip.pdf"&gt;The Dependency Inversion Principle&lt;/a&gt;", published as early as 1996!&lt;br /&gt;&lt;br /&gt;Isn't that something?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-6159245282233756745?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/6159245282233756745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=6159245282233756745' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/6159245282233756745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/6159245282233756745'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/08/how-old-is-concept-of-inversion-of.html' title='How Old is the Concept of &quot;Inversion of Control&quot;?'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-5271240051139141686</id><published>2007-08-02T18:03:00.000-07:00</published><updated>2008-01-15T22:46:34.635-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>With Wing Bark, No Quack</title><content type='html'>I have heard tons of insane software development project stories, and this one beats all of them added up...&lt;br /&gt;&lt;br /&gt;I only hope the story is not true...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-5271240051139141686?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://worsethanfailure.com/Articles/No,_We_Need_a_Neural_Network.aspx' title='With Wing Bark, No Quack'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/5271240051139141686/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=5271240051139141686' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5271240051139141686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5271240051139141686'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/08/with-wing-bark-no-quack.html' title='With Wing Bark, No Quack'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-8322834113382060895</id><published>2007-08-02T09:16:00.000-07:00</published><updated>2008-01-15T22:46:57.029-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>Atlassian and Cenqua</title><content type='html'>Two of my favorite companies from down under is now one.  I love it.&lt;br /&gt;&lt;br /&gt;Atlassian taught me that wiki can be cool and professional, and that Bugzilla is not as good as a bug tracking system can get.&lt;br /&gt;&lt;br /&gt;Cenqua simply saved me from the CVS madness.&lt;br /&gt;&lt;br /&gt;Thank you both!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-8322834113382060895?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.atlassian.com/cenqua/default.jsp' title='Atlassian and Cenqua'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/8322834113382060895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=8322834113382060895' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/8322834113382060895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/8322834113382060895'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/08/atlassian-and-cenqua.html' title='Atlassian and Cenqua'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-7073611712914713014</id><published>2007-07-18T09:08:00.000-07:00</published><updated>2008-01-15T22:47:18.997-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDE'/><category scheme='http://www.blogger.com/atom/ns#' term='Interaction Design'/><category scheme='http://www.blogger.com/atom/ns#' term='Rants'/><title type='text'>Sad Day for Polite Software like IDEA</title><content type='html'>&lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=IDEShowdown&amp;amp;asrc=EM_NLN_1758032&amp;amp;uid=2105151"&gt;IDE Showdown - Evangelists duke it out at Cologne JUG&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;My hats off for organizing this meeting.  However, based on the conclusion that the article has drawn, I mark this as a sad day for the polite software like IDEA.   Apparently we still live in a society where the quantity of the work, i.e. feature list and 'advanced features', rather than the quality of the work, i.e. how you implement the same feature in polite way, matters.&lt;br /&gt;&lt;br /&gt;And I am also annoyed every time someone says "Eclipse is more than just a Java IDE", or "Eclipse is more than just an IDE", as if it is a good reason for it to be poorly designed and most annoying to use.  You know, that is not even a good excuse.&lt;br /&gt;&lt;br /&gt;I can rant on for days.  But I have been ranting for so long since Borland decided to stop the development of JBuilder purely out of fear for Eclipse (hence my reason to quit) several years ago, that I am just tired.  All that I feel up to do right now, is to quote Alan Cooper in his great book “&lt;a href="http://www.amazon.com/exec/obidos/tg/detail/-/0672316498/103-0646908-7216639?v=glance"&gt;The Inmates Are Running the Asylum&lt;/a&gt;”:&lt;br /&gt;&lt;blockquote&gt;It is abundantly clear to most of us that common folk don't know the difference between a token ring and a mood ring. We need these creator of "faster, stronger, better" innovations to be sure that the creations actually improve our work and lives -- not simply drive us crazy. We need the technology to work in the same way average people think. We need a revolution to restore our sanity.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Update: I also think that IDEA is wrong by trying to fight on the open source battle ground.  Of course you are going to lose!  What is so wrong by saying&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Our business model is to produce a killer softerware full time and get paid well enough for it to be sustainable.  Because of our business model, we have the purest agenda and vision for our IDE, i.e., make Java developers do their own job in the most efficient way.  If any other FREE IDE can beat us in this market, we will cease to exist.  But so far, it looks like we are the best.   And we ARE supporting open source in our own way, by giving out open source licenses.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-7073611712914713014?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/7073611712914713014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=7073611712914713014' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/7073611712914713014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/7073611712914713014'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/07/sad-day-for-polite-software-like-idea.html' title='Sad Day for Polite Software like IDEA'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-146424845433287349</id><published>2007-07-09T08:21:00.000-07:00</published><updated>2008-01-15T22:48:02.130-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>Squeak - My New Language of the Year</title><content type='html'>When someone took the time and write a tutorial &lt;a href="http://squeak.preeminent.org/tut2007/html/index.html"&gt;like this&lt;/a&gt;, the least that I should do is to read it through and learn it to show my respect.&lt;br /&gt;&lt;br /&gt;I am not totally sold on the ""Learn at least one new language every year" (p. 14 on &lt;a href="http://www.pragmaticprogrammer.com/"&gt;Pragmatic Programmer&lt;/a&gt; book).  Not that I don't think it is a great idea.  I just think for one it would be very hard to do since it normally takes one (me at least) several years to learn to fully appreciate the language.  Another reason is that I think it is more important to contribute back to the society of what you have learned than keep learning for learning's sake.  I know I have not contribute enough as it is, given the pressure to put food on the table, making my way to afford a house in bay area, take time to &lt;a href="http://funworks.blogspot.com/"&gt;enjoy life&lt;/a&gt;, and such.&lt;br /&gt;&lt;br /&gt;But when all you need to do is to download the &lt;a href="http://www.squeak.org/Download/"&gt;Virtual Machine and Image&lt;/a&gt;, and read &lt;a href="http://squeak.preeminent.org/tut2007/html/index.html"&gt;the tutorial&lt;/a&gt;, and you are up every night feeding the baby anyway, why not.&lt;br /&gt;&lt;br /&gt;Update: As it just turned out, &lt;a href="http://log.reflectivesurface.com/2007/02/07/smalltalk-variations-on-a-theme/"&gt;this post&lt;/a&gt; showed up in case you wonder what are the choices are out there if you want to learn smalltalk.&lt;br /&gt;&lt;br /&gt;Second Update: Free (and Legal) &lt;a href="http://www.iam.unibe.ch/%7Educasse/FreeBooks.html"&gt;online Smalltalk books&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-146424845433287349?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://squeak.preeminent.org/tut2007/html/index.html' title='Squeak - My New Language of the Year'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/146424845433287349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=146424845433287349' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/146424845433287349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/146424845433287349'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/07/squeak-my-new-language-of-year.html' title='Squeak - My New Language of the Year'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-2480126623208060099</id><published>2007-07-08T03:51:00.000-07:00</published><updated>2008-10-24T21:16:48.802-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Iterative Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Project Management'/><title type='text'>Yak shaving</title><content type='html'>I have found this &lt;a href="http://en.wikipedia.org/wiki/Yak_shaving"&gt;Yak Shaving&lt;/a&gt; to be true in many occasions, especially when &lt;a href="http://buildmaster.rubyforge.org/history.html"&gt;starting the BuildMaster project&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I think that is why Agile development works.  You use one iteration to focus on one level of the work to build a "Walking Skeleton" as described in "Crystal Clear".  At the same time, you keep updating the story backlog about all the work that you discovered on the way so that you don't lose anything and can prepare for future iterations at the same time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-2480126623208060099?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://en.wikipedia.org/wiki/Yak_shaving' title='Yak shaving'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/2480126623208060099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=2480126623208060099' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/2480126623208060099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/2480126623208060099'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/07/yak-shaving.html' title='Yak shaving'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-557598396738163814</id><published>2007-07-08T03:18:00.000-07:00</published><updated>2008-01-15T22:49:26.055-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>Reference: Really Bad Powerpoint</title><content type='html'>Julian sent me this link, "&lt;a href="http://sethgodin.typepad.com/seths_blog/2007/01/really_bad_powe.html"&gt;Really Bad Powerpoint&lt;/a&gt;", as a guideline as we are developing our presentation for the Agile 2007.&lt;br /&gt;&lt;br /&gt;I do find the content convincing, especially about preparing full notes but not handing them out, and use less words on the slides.&lt;br /&gt;&lt;br /&gt;I don't think I agree with the idea of no transition, though.  I have had good experience using them, and I have seen others using them with good effect.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-557598396738163814?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://sethgodin.typepad.com/seths_blog/2007/01/really_bad_powe.html' title='Reference: Really Bad Powerpoint'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/557598396738163814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=557598396738163814' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/557598396738163814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/557598396738163814'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/07/reference-really-bad-powerpoint.html' title='Reference: Really Bad Powerpoint'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-892661380179768681</id><published>2007-06-12T22:59:00.000-07:00</published><updated>2007-06-14T09:48:59.007-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Interaction Design'/><title type='text'>Bad Interaction Design - Installing Acrobat Reader</title><content type='html'>It just so happened that two day after I was impressed with Firefox' &lt;a href="http://agileworks.blogspot.com/2007/06/good-interaction-design-closed-tab-list.html"&gt;good interaction design&lt;/a&gt;, I was utterly annoyed by the installing process of Acrobat Reader.&lt;br /&gt;&lt;br /&gt;What is so wrong about downloading an exe file that is an installer (using any download manager that I want), run it, and choose the location that I want to install the program???&lt;br /&gt;&lt;br /&gt;Oh no... You need to install the nice "Acrobat Get", which is either an ActiveX control for IE or Firefox plugin, which of course means that you have to set the security setting on your browser.  Then you have to wait for that thing to come up, start downloading, and silently install the program at the place where it sees fit (which happens to be my C drive that has only 1.5 GB left).&lt;br /&gt;&lt;br /&gt;So I ended up with even smaller space on C drive (40 GB free space on D drive).  And guess what, my computer hung during the process and I had to do a hardware shutdown (holding on to power button for 5 seconds).&lt;br /&gt;&lt;br /&gt;Update:  &lt;a href="http://thom.org.uk/blog"&gt;Tom&lt;/a&gt; just commented and provided this link to download the installer. &lt;br /&gt;&lt;br /&gt;&lt;a href="ftp://ftp.adobe.com/pub/adobe/reader/win/8.x/8.1/enu/AdbeRdr810_en_US.exe"&gt;ftp://ftp.adobe.com/pub/adobe/reader/win/8.x/8.1/enu/AdbeRdr810_en_US.exe&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Thanks!  I love internet!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-892661380179768681?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/892661380179768681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=892661380179768681' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/892661380179768681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/892661380179768681'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/06/bad-interaction-design-installing.html' title='Bad Interaction Design - Installing Acrobat Reader'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-6474597868890958912</id><published>2007-06-10T16:13:00.000-07:00</published><updated>2008-01-15T22:49:51.930-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XP'/><title type='text'>Test Doubles</title><content type='html'>This is a nice article that covers the topic very well.  &lt;a href="http://www.martinfowler.com/articles/mocksArentStubs.html"&gt;Stub, Mock&lt;/a&gt;, etc., are all part of the test double.&lt;br /&gt;&lt;br /&gt;Pay attention to the very first paragraph.  Going out of this context is how mocks are getting abused.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-6474597868890958912?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://xunitpatterns.com/Test%20Double.html' title='Test Doubles'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/6474597868890958912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=6474597868890958912' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/6474597868890958912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/6474597868890958912'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/05/test-doubles.html' title='Test Doubles'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-1691560047956030271</id><published>2007-06-06T13:58:00.001-07:00</published><updated>2007-06-10T16:04:54.620-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Interaction Design'/><title type='text'>Good Interaction Design: Closed Tab List</title><content type='html'>I was very delighted to discover the "Recently closed tab" feature in firefox!&lt;br /&gt;&lt;br /&gt;If you accidentally close a tab, you can now recover it through the menu "History--&gt;Recently Closed Tabs".  And guess what, your history is available as well!&lt;br /&gt;&lt;br /&gt;Now that is a good interaction design.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-1691560047956030271?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/1691560047956030271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=1691560047956030271' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/1691560047956030271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/1691560047956030271'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/06/good-interaction-design-closed-tab-list.html' title='Good Interaction Design: Closed Tab List'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-2553030504170621039</id><published>2007-06-03T23:09:00.001-07:00</published><updated>2008-10-24T21:20:32.947-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Communication'/><title type='text'>Remote vs Collocated Team</title><content type='html'>There is a heated but surprisingly friendly &lt;a href="http://tech.groups.yahoo.com/group/agile-usability/message/3361"&gt;discussion about Remote vs Collocated Team&lt;/a&gt; going on right now at &lt;a href="http://tech.groups.yahoo.com/group/agile-usability/"&gt;Yahoo! agile-usability group&lt;/a&gt;.  I have just started paying attention (and try to follow it) this weekend because the daily digest I get each day is full of it now.&lt;br /&gt;&lt;br /&gt;It is pretty interesting to read.  Well, if you have done XP coach or consulting at a firm that is not so hot on everything about agile, you might appreciate it more.&lt;br /&gt;&lt;br /&gt;It is also interesting to point out that the very first post started with this:&lt;br /&gt;&lt;blockquote&gt; Maybe this is not a hotly debated topic any more since ...&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-2553030504170621039?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://tech.groups.yahoo.com/group/agile-usability/message/3361' title='Remote vs Collocated Team'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/2553030504170621039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=2553030504170621039' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/2553030504170621039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/2553030504170621039'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/06/remote-vs-collocated-team.html' title='Remote vs Collocated Team'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-5945684214634210666</id><published>2007-06-01T22:01:00.000-07:00</published><updated>2008-01-15T22:50:11.604-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OperSource'/><title type='text'>rSpec 1.0.4</title><content type='html'>Busy with &lt;a href="http://buildmaster.rubyforge.org/"&gt;BuildMaster&lt;/a&gt;, &lt;a href="http://selenium.rubyforge.org/"&gt;selenium-ruby&lt;/a&gt;, and &lt;a href="http://www.dbentrance.com/"&gt;Entrance&lt;/a&gt;, I have not looked at rspec for a while.&lt;br /&gt;&lt;br /&gt;Until the Code Kata with rSpec we did at BayXP last week.&lt;br /&gt;&lt;br /&gt;Boy have they changed...&lt;br /&gt;&lt;br /&gt;And all for the better I'll say, after converted one file last night.  Personally I liked the 'specify' more like 'it'.  Actually, I thought they would go with 'should' since I type that at the beginning of the every specification name.&lt;br /&gt;&lt;br /&gt;But that is small thing.  With the new version, it would be a lot easier to come up with new matchers, re-use behaviors.&lt;br /&gt;&lt;br /&gt;Update: Check out the rspec report I have after converting to this version!  It is actually cool to see the broken tests report, more so than the passing report that &lt;a href="http://rspec.rubyforge.org/report.html"&gt;rspec has itself&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://buildmaster.rubyforge.org/rspec/"&gt;http://buildmaster.rubyforge.org/rspec/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-5945684214634210666?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://rspec.rubyforge.org' title='rSpec 1.0.4'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/5945684214634210666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=5945684214634210666' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5945684214634210666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/5945684214634210666'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/06/rspec-104.html' title='rSpec 1.0.4'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-2590366194553724700</id><published>2007-05-26T14:28:00.000-07:00</published><updated>2008-01-15T22:51:50.331-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Design'/><title type='text'>Different Perspective: Singleton as Dependency Management</title><content type='html'>I used to loath the singleton pattern, mostly because of the pain it has caused me whenever I take over some old code and try to write test on it. Interesting enough, Guidewire has used it in a way that is actually kind of cool.&lt;br /&gt;&lt;br /&gt;If you have tried to manage component dependencies before the IoC container came out, you are probably fully aware of the pain you have to go through when a new dependency is introduced. Either you end up with a HUGE interface, or you have to change the signature of a handful classes and make some of them have longer parameter list in the process.&lt;br /&gt;&lt;br /&gt;Here those dependencies are manager as "Dependencies" singleton interface. It is a set of static methods to be precise. So if a class decides it needs to use metadata layer to build the query and database layer to execute the query (like the archiving project that I am working on), it can just grab the instance by calling "PLDependencies.getExtractController()" and "DatabaseDependencies.getDatabase()". The dependencies are set up during the server initialization (through dependency registrations) and never changes.&lt;br /&gt;&lt;br /&gt;There are some behavior changes associated with this design.  Two on top of my head:&lt;br /&gt;&lt;br /&gt;* No mocking/stubbing. Nothing is stubbed out within the application. We use H2 for testing and the database is reset using restore. So the tests run fairly fast. After seeing some horrible mocking code, I like this style more and more.&lt;br /&gt;* Be aware of the dependencies. With dependency injection, you get used to understanding the dependency relationships by looking at the construction and method parameter list. With this design, surprises can really happen. You could very well call into something that does not take any parameter only to find out that it actually does a lot of things.&lt;br /&gt;&lt;br /&gt;It is not the perfect design, but once you understand the pattern and learn not to abuse it, you can actually manage the dependencies quiet easily.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-2590366194553724700?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/2590366194553724700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=2590366194553724700' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/2590366194553724700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/2590366194553724700'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/05/different-perspective-singleton-as.html' title='Different Perspective: Singleton as Dependency Management'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-411191501786957201</id><published>2007-05-15T11:19:00.000-07:00</published><updated>2007-05-15T20:20:57.331-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test'/><title type='text'>Test Coverage</title><content type='html'>&lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=204677"&gt;http://www.artima.com/weblogs/viewpost.jsp?thread=204677&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The above link got passed around at Guidewire the other day.  It reminded me of the consulting days where we had to figure out the right answer for the right stage of the agile enablement.&lt;br /&gt;&lt;br /&gt;This also reminded me about another interesting thing is this "90%, 50% rule" from Adam.  He told me that he started paying more attention to the line coverage of the projects that he has been on.  What he noticed is that the line coverages seem always end up at 90% or 50%.  Normally 90% are the projects that developers are doing test-driven development, and 50% are the ones that people recognize that writing tests is an essential part of software development but not necessarily in the TDD fashion.&lt;br /&gt;&lt;br /&gt;I do remember that all my projects in ThoughtWorks had the around 90% coverage.  I wonder how much we have at Guidewire or my open source projects.  The reason that I don't know is because at Guidewire the QA tests affects the coverage as well so it is not the same thing.  My open source projects are all done in the TDD fashion so I never bothered to spend time create something that I don't really use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-411191501786957201?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/411191501786957201/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=411191501786957201' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/411191501786957201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/411191501786957201'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/05/test-coverage.html' title='Test Coverage'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-4332014062901817916</id><published>2007-04-29T17:27:00.000-07:00</published><updated>2008-01-15T22:52:13.022-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>Build vs Buy</title><content type='html'>It has always been a constant debate on Build v.s. Buy.  After working for an &lt;a href="http://www.thoughtworks.com/"&gt;elite consulting company&lt;/a&gt;, and now a &lt;a href="http://www.guidewire.com/"&gt;revolutionary product company&lt;/a&gt;, I start thinking that there probably is no simple answer.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.addsimplicity.com/adding_simplicity_an_engi/"&gt;http://www.addsimplicity.com/adding_simplicity_an_engi/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Maybe the truth is that this is the wrong question to ask, that the real question is "How to verify the return of the investment in IT"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-4332014062901817916?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.addsimplicity.com/adding_simplicity_an_engi/' title='Build vs Buy'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/4332014062901817916/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=4332014062901817916' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4332014062901817916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/4332014062901817916'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/04/build-vs-buy.html' title='Build vs Buy'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-437073980033661325</id><published>2007-04-22T17:49:00.000-07:00</published><updated>2009-10-21T22:09:31.463-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>GScript - You don't Have to Use Ruby to be Cool</title><content type='html'>So why do you think Ruby is cool?&lt;br /&gt;&lt;br /&gt;If you are like me who work mainly on Java platform, then you probably like Ruby because how much less code you write in Ruby to achieve the same result.  Now, if you think about it, not all of them are because of the type-free concept.&lt;br /&gt;&lt;br /&gt;With the way that generics goes (what it was and what it is), we can see that the design of Java language comes with some tough trade-offs.  After all, I don't suppose you want to piss off the big vendors who keep the money rolling.&lt;br /&gt;&lt;br /&gt;Well, what if we can start fresh?&lt;br /&gt;&lt;br /&gt;Check this one out...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;var list = new ArrayList&lt;keyablebean&gt;({one, two})&lt;br /&gt;// this creats a map of beans with ID as key.&lt;br /&gt;&lt;/keyablebean&gt;var idMap = list.partition(\bean -&gt; bean.ID)&lt;br /&gt;&lt;/blockquote&gt;A few notes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The last statement uses closure, in GScript syntax.  For anyone familiar with Ruby, this call would be something like "list.partition {|bean| bean.id}"&lt;/li&gt;&lt;li&gt;The expression "bean.ID" is actually a "bean.getID()" method call, which is declared as property getter in GScript&lt;/li&gt;&lt;li&gt;Even though "list" is a type of List, you can add "Enhancement" to this interface so that you can have additional behavior built on top of existing public methods.  This gives you some of the benefit of "mixing" without sacrificing the type safety.  If you use apache commons library extensively, you probably have a list of enhancement that you can write already.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The type is inferred so you really need to type once. (Note that the type of variable idMap will be inferred as Map&amp;lt;Key, KeyableBean&amp;gt;, a generic map instead of just a Map)&lt;/li&gt;&lt;li&gt;Create the list like the way you mean it instead of the Arrays.asList syntax.&lt;/li&gt;&lt;/ul&gt;You have just caught a glimpse (and I do mean "glimpse") of GScript, the language that Guidewire developed on top of Java.  You want a rule engine that can be configured?  What about a rule engine that can be programed and deployed without bouncing the server?&lt;br /&gt;&lt;br /&gt;There are talks about making this public, by which time you will be able to see the full power of it.  Before that, you can consider coming in for an interview. :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-437073980033661325?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/437073980033661325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=437073980033661325' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/437073980033661325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/437073980033661325'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/03/gscript-you-dont-have-to-use-ruby-to-be.html' title='GScript - You don&apos;t Have to Use Ruby to be Cool'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-517028824307589542</id><published>2007-04-01T10:40:00.000-07:00</published><updated>2007-04-01T19:23:42.757-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>Free Broadband using Sewer System from Google!</title><content type='html'>As expected, Google has something cool this time every year.&lt;br /&gt;&lt;br /&gt;The last several ones that I have enjoyed was:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.google.com/technology/pigeonrank.html"&gt;How does google search work?&lt;/a&gt;&lt;/li&gt;&lt;li&gt; &lt;a href="http://www.google.com/googlegulp/"&gt;Google drink&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Or you can &lt;a href="http://www.google.com/tisp/notfound.html"&gt;read all of them here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-517028824307589542?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.google.com/tisp/' title='Free Broadband using Sewer System from Google!'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/517028824307589542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=517028824307589542' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/517028824307589542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/517028824307589542'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/04/free-broadband-using-sewer-system-from.html' title='Free Broadband using Sewer System from Google!'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-7882909410347369713</id><published>2007-03-30T12:00:00.000-07:00</published><updated>2007-03-31T14:23:38.845-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>Label Blog Post!</title><content type='html'>If you are a blogger user, did you know that you can put labels on your posts???!!!&lt;br /&gt;&lt;br /&gt;I have been jealous of &lt;a href="http://wordpress.org/"&gt;WordPress&lt;/a&gt; users for a long time but I am just too busy/lasy to set up a server of my own.&lt;br /&gt;&lt;br /&gt;Until the other day I noticed a blog post with labels hosted on blogspot.  Well, I guess that says how sloppy I have been on writing this blog.&lt;br /&gt;&lt;br /&gt;Again, thank you Google!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-7882909410347369713?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://googleblog.blogspot.com/2006/12/bloggers-new-bag-of-tricks.html' title='Label Blog Post!'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/7882909410347369713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=7882909410347369713' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/7882909410347369713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/7882909410347369713'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/03/label-blog-post.html' title='Label Blog Post!'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-7650821106516541934</id><published>2007-01-13T17:00:00.000-08:00</published><updated>2007-03-30T11:58:39.010-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>So Close</title><content type='html'>Working on several things at the same time and they are all getting very close but just not quite.  I have to say this puts a bit of stress on me.&lt;br /&gt;&lt;br /&gt;At &lt;a href="http://www.guidewire.com"&gt;guidewire&lt;/a&gt;, I am working on a feature that involves analyzing the domain graph so that we can do things like record purging, archiving, data relationship analysis, etc.  I think I have the main graph finally worked out (even have a primitive UI to show for it).  I have the tests running and one of them can generate a Wiki content so that the document is always up-to-date.  However, at the edge of the graph where the domain objects inside the graph has references to or from objects outside the graph, it gets a little complicated.  I am keeping down a list on the wiki and it is getting more and more complete..... Just not yet. &lt;br /&gt;&lt;br /&gt;I have arranged next sprint (two-week period) to start on next week so I was really hoping that I could finish this before I kick it off, because it will make a lot of stories easier to write.  But for various reason I just couldn't quite just make it.  I think I'll have to spend next Tuesday (Monday being a holiday) to make sure that the stories for the next sprint is good to go and that QA is on board with what I want to do.  Adam has got me an account with Pivotal's tracker.  Things are all good, just that being one-man team is not easy because you still have to do the same amount tracking if you want to still get the benefits for agile development.&lt;br /&gt;&lt;br /&gt;At home, I have been busy with mainly two projects, &lt;a href="http://buildmaster.rubyforge.org"&gt;BulidMaster&lt;/a&gt; and &lt;a href="http://selenium.rubyforge.org"&gt;Selenium-Ruby&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For BuildMaster, I finally figured out how to use RubyGem to archive the file, and why reading image file with Cotta cannot read the full content (you have to call io.binmode even if you open it with 'wb' argement).  I am getting very close to have Cotta support archive and zip so that we can just do 'dir.archive_to(target_file).zip' and get a zip file.  I need to redesign the BuildMaster website so that project releasing, website building and cotta are presented as three separate pieces.&lt;br /&gt;&lt;br /&gt;For Selenium, that is something that I am still not ready to share but I think it will be interesting as well.  I will need to modify the selenium server and again I am getting very close.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-7650821106516541934?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/7650821106516541934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=7650821106516541934' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/7650821106516541934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/7650821106516541934'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/01/so-close.html' title='So Close'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-116844627852591763</id><published>2007-01-10T08:21:00.000-08:00</published><updated>2008-01-15T22:52:29.399-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>Yet Another Keyboard Layout?</title><content type='html'>Interesting...  Although switching between QWERTY and Dvorak, and telling people about Dvorak is already hard enough.   If anything, I would be glad to see the day that Dvorak prevail.&lt;br /&gt;&lt;br /&gt;Nevertheless, the &lt;a href="http://colemak.com/Compare"&gt;comparison applet&lt;/a&gt; is still something very interesting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-116844627852591763?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/116844627852591763/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=116844627852591763' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116844627852591763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116844627852591763'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/01/yet-another-keyboard-layout.html' title='Yet Another Keyboard Layout?'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-116840652369621238</id><published>2007-01-09T21:19:00.000-08:00</published><updated>2008-01-18T18:05:30.851-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDE'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>This Made My Day</title><content type='html'>Enough said...&lt;br /&gt;&lt;br /&gt;Bye bye Eclipse!  I know I am supposed to say "thank you and miss you" and stuff, but I really don't want to lie.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-116840652369621238?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.jetbrains.net/confluence/display/RUBYDEV/Home' title='This Made My Day'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/116840652369621238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=116840652369621238' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116840652369621238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116840652369621238'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/01/this-made-my-day.html' title='This Made My Day'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-116789906419226267</id><published>2007-01-04T00:19:00.000-08:00</published><updated>2007-03-30T11:59:42.047-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Test'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Domain Based Web Testing</title><content type='html'>This has been in my mind for some time and with the creation of Selenium-Ruby I finally have someplace to put it:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://selenium.rubyforge.org/doc/domain-based-web-testing.html"&gt;http://selenium.rubyforge.org/doc/domain-based-web-testing.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The idea of domain driven is also behind the &lt;a href="http://buildmaster.rubyforge.org/"&gt;BuildMaster&lt;/a&gt; and &lt;a href="http://cotta.sourceforge.net"&gt;Cotta&lt;/a&gt; project.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-116789906419226267?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://selenium.rubyforge.org/doc/domain-based-web-testing.html' title='Domain Based Web Testing'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/116789906419226267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=116789906419226267' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116789906419226267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116789906419226267'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2007/01/domain-based-web-testing.html' title='Domain Based Web Testing'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-116624455237563543</id><published>2006-12-15T20:44:00.000-08:00</published><updated>2007-03-30T12:13:21.146-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OperSource'/><title type='text'>fix svn tagging in sourceforge</title><content type='html'>I have been having tagging problem with Subversion in &lt;a href="http://www.sourceforge.net"&gt;Sourceforge&lt;/a&gt;.  It took me several days to realize that this is not going to be resolved by itself.  Once again, Google helped me found the solution:&lt;br /&gt;&lt;br /&gt;You need to point your working directory to a different repository URL, through command like:&lt;br /&gt;&lt;br /&gt;svn switch --relocate https://svn.sourceforge.net/svnroot/cotta/trunk https://cotta.svn.sourceforge.net/svnroot/cotta/trunk&lt;br /&gt;&lt;br /&gt;You just need to replace 'cotta' to the unix name of your project.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-116624455237563543?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/116624455237563543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=116624455237563543' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116624455237563543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116624455237563543'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/12/fix-svn-tagging-in-sourceforge.html' title='fix svn tagging in sourceforge'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-116530167979363946</id><published>2006-12-04T22:22:00.000-08:00</published><updated>2007-03-30T12:13:28.052-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>So Much for Java Generics</title><content type='html'>I always thought that Java generics is supported through compiler is a bit weird, and after 5 hours of email and spike, I finally know why.&lt;br /&gt;&lt;br /&gt;Don't get me wrong, I love generics.  Even though with TDD I can catch my mistakes most of the time, but with generics I can see my mistakes even before I run the tests.  I won't say no to that.&lt;br /&gt;&lt;br /&gt;Anyway, it all started with me starting a prove-of-concept project with another friend.  So I am setting up libraries and figured I'll use jMock's constraint framework, after I convert it to support generics.   Hence started my journey.&lt;br /&gt;&lt;br /&gt;I checked out jmock code and was surprised to find out that there is a jmock2 directory.  By the document that has been written, it is a way to stay with jMock style but don't lose the type safety.  Cool!  What is more, the constraint framework has been extracted into something called hamcrest.&lt;br /&gt;&lt;br /&gt;Through email, Nat pointed me to the project in sourceforge (duh): http://sourceforge.net/projects/hamcrest.  It looks very promising, even have the adapter for JUnit3, JUnit 4, and TestNG.  It is apparent the intention of this project.&lt;br /&gt;&lt;br /&gt;After I calmed down with all the excitement, I noticed one thing strange:  The Matcher interface, the one interface that matching framework is evaluating matching logic, takes the "Object" type, rather than the generic type.  What this means is that all the matching instance will have to do a type cast.&lt;br /&gt;&lt;br /&gt;"That was silly", thought I, "Surely they know better than this".  So I modified the interface in hamcrest, ran all the tests and proudly submitted my patch to Joe.&lt;br /&gt;&lt;br /&gt;Turns out that the issue is not hamcrest itself, but jMock. &lt;br /&gt;&lt;br /&gt;If you have two methods of the same name that you want to mock, say&lt;br /&gt;    public void test(int value);&lt;br /&gt;    public void test(String value);&lt;br /&gt;&lt;br /&gt;And you provide the expectation&lt;br /&gt;    mock.expect("test").with(eq(1))&lt;br /&gt;&lt;br /&gt;Upon the invocation of a.test("arg"), it will try to find the match by checking the matcher returned by eq(1) as well as that returned by eq("arg").  When comparing to eq(1) it will fail because from the instance there is no way you can figure out what the generic type is, and invoking by force will cause a class cast exception because there is a class cast injected by the compiler.&lt;br /&gt;&lt;br /&gt;So in the above invocation, instead of having something like "unexpected invocation error", you end up with a weird ClassCastException error.&lt;br /&gt;&lt;br /&gt;Bloody hell.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-116530167979363946?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/116530167979363946/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=116530167979363946' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116530167979363946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116530167979363946'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/12/so-much-for-java-generics.html' title='So Much for Java Generics'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-116478888438397176</id><published>2006-11-29T00:18:00.000-08:00</published><updated>2008-10-24T21:21:33.668-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SCRUM'/><title type='text'>SCRUM at Guidewire</title><content type='html'>A month ago, I have joined guidwire, a local start-up building insurance products.&lt;br /&gt;&lt;br /&gt;At guidwire, we are using SCRUM.  So every new hire will get a book of "&lt;a href="http://www.amazon.com/Agile-Software-Development-SCRUM-Schwaber/dp/0130676349"&gt;Agile Software Development with SCRUM&lt;/a&gt;".  Somehow I missed it but I found it soon enough and got a copy right away.&lt;br /&gt;&lt;br /&gt;I don't know why I never got a chance to read this book and I am really glad that I did.  SCRUM is very much like the project management part of what I have been doing for the last several years.  This includes the details like format of SCRUM meeting (daily stand-ups), feature backlog (master story list), goal driven team development.&lt;br /&gt;&lt;br /&gt;On google video, there is a presentation done by Ken himself: &lt;a href="http://video.google.com/videoplay?docid=-7230144396191025011&amp;amp;q=ken+scrum"&gt;http://video.google.com/videoplay?docid=-7230144396191025011&amp;amp;q=ken+scrum&lt;/a&gt;.&lt;br /&gt;In it, he talked about SCRUM and XP complements each other.  I didn't understand it before, and now I think it is really true.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-116478888438397176?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/116478888438397176/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=116478888438397176' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116478888438397176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116478888438397176'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/11/scrum-at-guidewire.html' title='SCRUM at Guidewire'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-114117588259761224</id><published>2006-11-22T17:15:00.000-08:00</published><updated>2007-03-30T12:12:02.257-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Misc'/><title type='text'>Typing Contest : Dvorak vs. QWERT</title><content type='html'>After switching to Dvorak for almost a year, I decided to switch back to QERTY, for two reasons.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I was pairing at least 6 hours a day and was driving everyone mad with the layout switching&lt;/li&gt;&lt;li&gt;I wanted to see how fast I was with QWERTY.&lt;/li&gt;&lt;/ul&gt;Before I switched back, I timed myself in typing out the page "&lt;a href="http://agileworks.blogspot.com/2005/06/dvorak-follow-up-why-i-think-it-is.html"&gt;Dvorak Follow-Up&lt;/a&gt;".  Now that I am fluent with QWERTY again (I should have done that earlier but I was too lazy), I just typed the page again using QWERTY.&lt;br /&gt;&lt;br /&gt;And the result is...(drum...)...&lt;br /&gt;&lt;br /&gt;DVORAK!&lt;br /&gt;&lt;br /&gt;Time used with Dvorak: 9:28minutes.&lt;br /&gt;Time used with QERWT: 9:55 minutes&lt;br /&gt;&lt;br /&gt;I cannot say that I am not surprised.  After all, I have been typing QWERTY almost my entire life and I only used Dvorak for a year.  But here you go.&lt;br /&gt;&lt;br /&gt;On the other side, 30 second is very small.  I could just be tired tonight.&lt;br /&gt;&lt;br /&gt;I also finished the "Joy and Pain with Fitnesse" in 29:30 minutes using QWERTY.  If I ever switch to Dvorak again, I might do another contest.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-114117588259761224?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/114117588259761224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=114117588259761224' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114117588259761224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114117588259761224'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/11/typing-contest-dvorak-vs-qwert.html' title='Typing Contest : Dvorak vs. QWERT'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-116366275130271452</id><published>2006-11-15T23:36:00.000-08:00</published><updated>2008-10-24T21:22:01.379-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SCRUM'/><title type='text'>Scrum et al. at Google Vedio</title><content type='html'>&lt;a href="http://video.google.com/videoplay?docid=-7230144396191025011"&gt;http://video.google.com/videoplay?docid=-7230144396191025011&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I thought it was interesting on the part that SCRUM works with XP. I always thought SCRUM was too much on the management side, and now I think I know why.&lt;br /&gt;&lt;br /&gt;Too bad most of the guys on &lt;a href="http://groups.google.com/group/agilechina"&gt;agilechina&lt;/a&gt; cannot see it. Copyright issue I suppose.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-116366275130271452?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/116366275130271452/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=116366275130271452' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116366275130271452'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116366275130271452'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/11/scrum-et-al-at-google-vedio.html' title='Scrum et al. at Google Vedio'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-116306627877302829</id><published>2006-11-09T01:51:00.000-08:00</published><updated>2007-03-30T12:10:17.949-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OperSource'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Code Snippet, with Color!</title><content type='html'>I did it!&lt;br /&gt;&lt;br /&gt;Now build master can grab code snippet from another file and apply syntax highlighting using &lt;a href="http://syntax.rubyforge.org"&gt;syntax&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Next step is to figure out a way to specify the snippet validations.&lt;br /&gt;&lt;br /&gt;I am dead tired right now and I have a 9am meeting tomorrow.  So I just updated two (actually one and half) pages to show it off.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://buildmaster.rubyforge.org/getting-started.html"&gt;http://buildmaster.rubyforge.org/getting-started.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://buildmaster.rubyforge.org/docs/tag-references.html"&gt;http://buildmaster.rubyforge.org/docs/tag-references.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I also fixed the document source and history link at the end of each page so you should be able to see the source file now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-116306627877302829?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/116306627877302829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=116306627877302829' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116306627877302829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116306627877302829'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/11/code-snippet-with-color.html' title='Code Snippet, with Color!'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-116114956161687217</id><published>2006-10-17T22:12:00.000-07:00</published><updated>2008-01-15T22:53:25.239-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><category scheme='http://www.blogger.com/atom/ns#' term='ThoughtWorks'/><title type='text'>Last Day as ThoughtWorker</title><content type='html'>Last day as ThoughtWorker, writing this blog that I have been putting off until the last minute, I find myself lost in thoughts in all the things that I have experienced since I joined ThoughtWorks 30 months ago.&lt;br /&gt;&lt;br /&gt;It has been a nothing short of life-changing experience.  As a matter of fact, it is with these changes that I have decided that in order for me to push even further, I will have to go out and look for good opportunities that can help me, rather than waiting for them to happen.  As I going through the projects, my expectation on what I can do on the project has changed dramatically.&lt;br /&gt;&lt;br /&gt;When I first joined, I was just happy if I can merrily write my tests, be happy about the 40-hour week and that the CEO is not trying to cash in one million dollars every quarter when the company stock is not going anywhere (like some company that I have worked for).  Now on my last day, I have found myself comfortable coaching agile software development and influencing project management.  I have experienced all the things a senior developer can do in a project, and even have had a short taste of being an IM and PM.  I have been to China, twice, to lead projects.  I have been on more and more discussion and presentations that involve more than "TDD" or "patterns".  I am even pulling an effort with several others right now to write a book that we hope can be published.&lt;br /&gt;&lt;br /&gt;Like my fellow Borlanders showing me the way to be a good developer, my fellow ThoughtWorkers have helped me understand what it takes to have a success project, besides technical execellence.  I created this blog for my experience in ThoughtWorks.  I have grown fond of it over the time and I am going to keep it up for my experience in applying agile practices.&lt;br /&gt;&lt;br /&gt;So to wrap it up:&lt;br /&gt;&lt;br /&gt;First several books that I read as a ThoughtWorker:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Enterprise Application Architecture&lt;/li&gt;&lt;li&gt;Domain Driven Design&lt;/li&gt;&lt;li&gt;pragmatic Project Automation&lt;/li&gt;&lt;/ul&gt;Most recent books that I read as a ThoughtWorker:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Tipping Point&lt;/li&gt;&lt;li&gt;Blink&lt;/li&gt;&lt;li&gt;Build to Last&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Blue Ocean Strategy&lt;/li&gt;&lt;li&gt;Crystal Clear&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Things I enjoyed doing in ThoughtWorks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Talk to Roy (don't worry about subjects)&lt;/li&gt;&lt;li&gt;Meet old timers, they will show you why the idea that "employee managed company" has a chance in ThoughtWorks.  (If someone was surprised that you were not one, it is a compliment)&lt;/li&gt;&lt;li&gt;Meet at least one ThoughtWorker from each office from other country, especially the noisy ones.&lt;/li&gt;&lt;li&gt;Request traveling to other country for a project.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Things that would be fun to do in ThoughtWorks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Tell Obie that ruby won't fly because it does not have an IDE like IntelliJ and it is not type safe. (well, maybe not anymore since he has been fighting that battle for a while and getting very good at it)&lt;/li&gt;&lt;li&gt;Tell Hammant that you love Spring&lt;/li&gt;&lt;li&gt;Buy beer around the table and ask for airplane takeoff and landing stories&lt;/li&gt;&lt;/ul&gt;Things that I did not enjoy doing:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;On beach for more than two weeks&lt;/li&gt;&lt;li&gt;Travel weekly with connection flights each way.&lt;/li&gt;&lt;li&gt;Stuck in an airport for a delayed flight for 7 hours&lt;/li&gt;&lt;li&gt;Stuck in an airplane on the ground for 3 hours&lt;/li&gt;&lt;li&gt;Saying goodbyes&lt;/li&gt;&lt;li&gt;On your last day, be notified that you won't be covered by medical insurance anymore (So much for chilling out before the next job), even though you have accumulated over four weeks of vacation, and you could technically take your vacation before you send in the two weeks' notice, getting covered and accumulate additional vacation at the same time.  The reason?  You are not worth risking the liability anymore, now that you are not going to make money for the company and all. (Not in that word but I get the message)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;I would have put boring period of the project in there but the following are what I have done each time I got bored:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Learned Dvorak&lt;/li&gt;  &lt;li&gt;Created open source projects: &lt;a href="http://www.shaneduan.com/opensource.html"&gt;http://www.shaneduan.com/opensource.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Read books&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-116114956161687217?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/116114956161687217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=116114956161687217' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116114956161687217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/116114956161687217'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/10/last-day-as-thoughtworker.html' title='Last Day as ThoughtWorker'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115955432117655986</id><published>2006-09-29T11:12:00.000-07:00</published><updated>2008-10-24T21:27:02.440-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test'/><category scheme='http://www.blogger.com/atom/ns#' term='Rants'/><category scheme='http://www.blogger.com/atom/ns#' term='Project Management'/><category scheme='http://www.blogger.com/atom/ns#' term='Communication'/><title type='text'>Things You CANNOT Get Certified For</title><content type='html'>So...&lt;br /&gt;&lt;br /&gt;I was chatting through IM with a friend of mine about something that I read recently (&lt;a href="http://www.amazon.com/Crystal-Clear-Human-Powered-Methodology-Development/dp/0201699478/sr=1-1/qid=1159424905/ref=pd_bbs_1/104-3916389-8449525?ie=UTF8&amp;amp;s=books"&gt;Crystal Clear&lt;/a&gt;).  And the conversation, as hard as I tried, just went downhill from there.  I got really agitated in the end, even after I realizing that half the time it is one of those flag words that got on my nerve.&lt;br /&gt;&lt;br /&gt;Looking back at the log, I realized that I thought he knew what I have been doing at ThoughtWorks for the last two and half years, and he probably thought I had no idea about the topic in this book.   During the whole conversation, we were on different depth level of the topic.  I guess this is one more case proving that you should watch out for "&lt;a href="http://agileworks.blogspot.com/2006/08/good-read-eight-barriers-to-effective.html"&gt;Barriers for Effective Listening&lt;/a&gt;" and ask "&lt;a href="http://agileworks.blogspot.com/2006/08/ask-why-do-you-ask.html"&gt;Why do you ask&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;With all that behind, I was still stunned at the fact that no matter how well so many people try to protect a good idea, there are still people out there trying to profit from it by coming up with bogus stuff in its name.  And one very good example is "certification".  Because apparently they succeeded in making my friend think that is what it is all about, another certification.&lt;br /&gt;&lt;br /&gt;So here is a list of things that you cannot get certified for.  Instead, only your peers who work with you day in and day out can rate you, subjectively.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Doing TDD even when you are under the pressure to delivery.  Everyone can pass a test and do a little practice in their own pleasure.&lt;/li&gt;&lt;li&gt;Have the courage to speak up when there are things that you think is wrong.  "Do you think you should speak up when you see something wrong?"  "Yes." "Good! You are certified!"&lt;/li&gt;&lt;li&gt;Sit-Together.  How can you certify that, just by sitting together for a week?  It is one thing to say "yeah, it is a good idea", it is another thing to go to the extreme length of getting the tools yourself and start taking cubicles apart.  (Yes I have met someone who really did it).&lt;/li&gt;&lt;li&gt;Code Co-ownership.  I am sure everyone can check that checkbox to get certified.  But how can you certify a person's willingness to learn as much as the codebase, make sure that the design is as clear as it can be, and pass on the knowledge to others as soon as possible?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Sorry but "certification" is such a binary rating system, that it just does not fit into what it is in the real world.&lt;br /&gt;&lt;br /&gt;Then of course, it is always good to get some education on the topic and have a proof that you have finished them successfully.&lt;br /&gt;&lt;br /&gt;But that hardly gives anyone the authorization to say that "It is nice, but it is really really hard to do a business-driven situation".&lt;br /&gt;&lt;br /&gt;Not when the purpose of the whole thing is "Deliver the business value in whatever the best possible way".&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;(BTW, did you realize that if you mistype blogspot.com as blogpsot.com, it is an actual website selling ads?)&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115955432117655986?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115955432117655986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115955432117655986' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115955432117655986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115955432117655986'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/09/things-you-cannot-get-certified-for.html' title='Things You CANNOT Get Certified For'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115905029302424764</id><published>2006-09-23T15:08:00.000-07:00</published><updated>2007-03-30T12:12:51.704-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OperSource'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>BuildMaster Surgery - Moving to Cotta</title><content type='html'>I have been struggling with the File operations for a while, before I fully understand what is going on.&lt;br /&gt;&lt;br /&gt;After I released &lt;a href="http://cotta.sourceforge.net"&gt;Cotta&lt;/a&gt; project, the way File operations works in Ruby is like a hideous stain on top of a shining gem, always bugged me, especially when there are these nice classes like Pathname and StringIO already exist in Ruby.  &lt;br /&gt;&lt;br /&gt;Finally, my curiosity of making it better got the best of me, and I ported BuildMaster over to &lt;a href="http://cotta.sourceforge.net/power.html"&gt;Cotta Style&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I have decided to call the files CottaFile and CottaDirectory so that I don't have to worried about the name space issue.  Since BuildMaster does quite a bit of shell operations, I added method "shell" to the cotta instance so that the in memory version can log them for tests.&lt;br /&gt;&lt;br /&gt;All things are happening behind the scene.  The following is a code snippet demonstrate the new API:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px solid rgb(68, 68, 68); background: rgb(204, 204, 255) none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;&lt;br /&gt;   #system implementation is injected here&lt;br /&gt;   cotta = BuildMaster::Cotta.new(BuildMaster::InMemorySystem.new)&lt;br /&gt;   file2 = cotta.file('dir2/file.txt')&lt;br /&gt;   file2.exists?.should_equal false&lt;br /&gt;   # parent directories are created automatically&lt;br /&gt;   @file.save('my content')&lt;br /&gt;   @file.copy_to(file2)&lt;br /&gt;   file2.exists?.should_equal true&lt;br /&gt;   file2.load.should_equal 'my content'&lt;br /&gt;   file2.read {|file| puts file.gets}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The API still need to be fine tuned but they provide all the operations that BuildMaster needs for the moment.  Hopefully, someday something like this can be part of the ruby library.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115905029302424764?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115905029302424764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115905029302424764' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115905029302424764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115905029302424764'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/09/buildmaster-surgery-moving-to-cotta.html' title='BuildMaster Surgery - Moving to Cotta'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115904824095276303</id><published>2006-09-23T13:48:00.000-07:00</published><updated>2007-03-30T12:12:51.705-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OperSource'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>BuildMaster Surgery - Moving to rSpec</title><content type='html'>This is the first part of the BuildMaster surgery that I have just finished (well, 95%)  that have been keeping me up late every day.  I will write the second part as a separate blog.&lt;br /&gt;&lt;br /&gt;Moving BuildMaster to rSpec turned out to be not as smoothly as I hoped.  Hopefully this blog will help anyone who is interested on similar task.  This is what I have figured out so far so if there is a better way of doing it do let me know.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Syntax Change&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you have tons of test/unit scripts already, changing the code to use the rSpec syntax could be boring.  They do have "&lt;a href="http://rspec.rubyforge.org/tools/test2spec.html"&gt;Test::Unit Migration&lt;/a&gt;" support.  However, I didn't get to take full advantage.  It just generated "migration error" with no detail information for me.  So I had to use some regular expressions to get the most of the change done, which I have blogged in "&lt;a href="http://agileworks.blogspot.com/2006/09/going-rspec.html"&gt;Going rSpec&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Specification Sharing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The "Context API" document on rSpec teaches you how to call helper methods in your specification code.  However, it does not show you how you can make two context share the specifications, which is very useful if you want to make sure that two different implementation of the same interface shares the exact same behaviors.&lt;br /&gt;&lt;br /&gt;Brain from &lt;a href="http://www.pivotalsf.com/index"&gt;Pivotal&lt;/a&gt; showed me that you can achieve this by using 'extend' (instead of include).  So you can write the common behavior specifications in one file:&lt;br /&gt;&lt;br /&gt;&lt;pre style="color:black;background: #CCCCFF;border:1px solid #444;"&gt;module CottaSpecifications&lt;br /&gt;&lt;br /&gt;def register_cotta_file_specifications&lt;br /&gt;  setup do&lt;br /&gt;  # this one uses the @system that will be set up by each implementation spec setup&lt;br /&gt;  @file = BuildMaster::CottaFile.new(@system, Pathname.new('dir/file.txt'))&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;specify 'file can be created with system and pathname' do&lt;br /&gt;  @file.name.should_equal 'file.txt'&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;Then you can include those common behavior in your specification file for the implementation:&lt;br /&gt;&lt;pre style="color:black;background: #CCCCFF;border:1px solid #444;"&gt;require 'cotta_file_specifications'&lt;br /&gt;module BuildMaster&lt;br /&gt;context 'Cotta file' do&lt;br /&gt;  # extending the module so that you can call the methods&lt;br /&gt;  extend CottaSpecifications&lt;br /&gt;  setup do&lt;br /&gt;  # setup the implementation for specifications&lt;br /&gt;  @system = InMemorySystem.new&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# this call registers all the spefications&lt;br /&gt;register_cotta_file_specifications&lt;br /&gt;end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;Hopefully the above code makes sense to you.  If not, let me know.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Running All Specifications&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Again, thanks Brain to explain the reason and provided me with a solution.&lt;br /&gt;&lt;br /&gt;Somehow, all the registered contexts are run at the end of each context registration.  So my &lt;a href="http://agileworks.blogspot.com/2006/08/loading-all-test-cases-in-ruby.html"&gt;code for loading all the tests&lt;/a&gt; will now make the same context run again and again:&lt;br /&gt;&lt;br /&gt;If you have context A and B in tc_a.rb and tc_b.rb and you require each file one by one.  After "require 'tc_a'", the specifications in Context A will run.  After "require 'tc_b'", the specifications in Context B will run, this time ALONG with all the specification in Context A.  If you have C, D, etc., then specifications of Context A will run again and again at the end of each following require.&lt;br /&gt;&lt;br /&gt;So Brain wrote his own specification runner, which will hold off the execution until all the contexts are loaded:&lt;br /&gt;&lt;br /&gt;&lt;pre style="color:black;background: #CCCCFF;border:1px solid #444;"&gt;require 'rubygems'&lt;br /&gt;require 'spec'&lt;br /&gt;#require 'diff/lcs'&lt;br /&gt;dir = File.dirname(__FILE__)&lt;br /&gt;#require "#{dir}/../test/common_test_case"&lt;br /&gt;require 'test/unit'&lt;br /&gt;Test::Unit.run = true&lt;br /&gt;&lt;br /&gt;args = ARGV.dup&lt;br /&gt;unless args.include?("-f") || args.include?("--format")&lt;br /&gt;  args &lt;&lt; "--format"&lt;br /&gt;  args &lt;&lt; "specdoc"&lt;br /&gt;end&lt;br /&gt;#args &lt;&lt; "--diff"&lt;br /&gt;args &lt;&lt; $0&lt;br /&gt;$context_runner  = ::Spec::Runner::OptionParser.create_context_runner(args, false, STDERR, STDOUT)&lt;br /&gt;&lt;br /&gt;def run_context_runner_if_necessary(system_exit, has_run)&lt;br /&gt;  return if system_exit &amp;&amp; !(system_exit.respond_to?(:success?) &amp;&amp; system_exit.success?)&lt;br /&gt;  return if has_run&lt;br /&gt;  exit context_runner.run(true)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;at_exit do&lt;br /&gt;  has_run = !context_runner.instance_eval {@reporter}.instance_eval {@start_time}.nil?&lt;br /&gt;  run_context_runner_if_necessary($!, has_run)&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To use this, all I needed to do was to require this file at the beginning of my "ts_buildmaster.rb" file.&lt;br /&gt;&lt;br /&gt;And it generates nice output too:&lt;br /&gt;&lt;br /&gt;&lt;pre style="color:black;background: #CCCCFF;border:1px solid #444;"&gt;...&lt;br /&gt;Directory object with cotta for in memory system&lt;br /&gt;...&lt;br /&gt;- dir should return sub directory&lt;br /&gt;- dir should return a directory from a relative pathname&lt;br /&gt;- should get file in current directory&lt;br /&gt;- should create dir and its parent&lt;br /&gt;- should delete dir and its children&lt;br /&gt;- should do nothing if dir already exists&lt;br /&gt;- should list dirs&lt;br /&gt;&lt;br /&gt;Directory object with cotta for physical system&lt;br /&gt;...&lt;br /&gt;- dir should return sub directory&lt;br /&gt;- dir should return a directory from a relative pathname&lt;br /&gt;- should get file in current directory&lt;br /&gt;- should create dir and its parent&lt;br /&gt;- should delete dir and its children&lt;br /&gt;- should do nothing if dir already exists&lt;br /&gt;- should list dirs&lt;br /&gt;...&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115904824095276303?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115904824095276303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115904824095276303' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115904824095276303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115904824095276303'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/09/buildmaster-surgery-moving-to-rspec.html' title='BuildMaster Surgery - Moving to rSpec'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115873412296301937</id><published>2006-09-19T22:56:00.000-07:00</published><updated>2008-01-15T22:53:43.641-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><category scheme='http://www.blogger.com/atom/ns#' term='ThoughtWorks'/><title type='text'>Tricky Business of Being a ThoughtWorks Consultant</title><content type='html'>I have been thinking about this for quite a while and the topic came up again recently.  So I figure I might as well write it down.  Keep in mind that these are my personal opinion as ONE ThoughtWorker based on my situations.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Blog or not to blog&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Historically, my blog thoughts come through several ways, all of which is under the condition that requires me to blog at airport or late at night (like now).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. Feeling Pain&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As the book "&lt;a href="http://www.amazon.com/Project-Retrospectives-Handbook-Team-Reviews/dp/0932633447/ref=sr_11_1/104-3916389-8449525?ie=UTF8"&gt;Project Retrospective&lt;/a&gt;" has pointed out, when you feel the pain of doing something, it is very important to stop for long enough period of time to reflect about what you are doing.  As true as it is, which makes me a true believer of retrospective, I still have the same amount, if not more than usual, of billable work that I need to do.  When I do come up with an idea of improving the process, I only create more work for me to talk with others to sell the idea, one more thing on my coaching list, and a task to implement the fix.&lt;br /&gt;&lt;br /&gt;So at the same time that I have learned a new aspect on software development, I am also burned out more from my day's work, which makes it a lot less appealing to write a blog about it.  Sometimes an idea has to go through several round to mature, so I hold off the blog.  Then when it is mature, I have got used to it and don't feel the excitement and urge writing it down anymore.&lt;br /&gt;&lt;br /&gt;Yes probably it would be ideal if I can slow down my other work so that I can keep my energy up everyday, which brings back to the title "consultant", as in, like it or not, I am being paid to live up to my previous promises as much as possible.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2. Learning something new&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When I got to know about something new, I always find a way to apply it so that I can learn more.  What that means is my afterhour will pretty much be occupied by those activities rather than blog about my incomplete thoughts about it.  To name a few:&lt;br /&gt;&lt;br /&gt;Behaviour-driven development: Liz from UK office did a presentation on &lt;a href="http://www.jbehave.org/"&gt;jBehave&lt;/a&gt; in the China office.  After that, I start visiting &lt;a href="http://behaviour-driven.org/"&gt;Behaviour-driven website&lt;/a&gt; to learn more about it.  When we created &lt;a href="http://cotta.sourceforge.net/"&gt;Cotta&lt;/a&gt; project, we decided to give it a try and it turned out to be very well.  But the IDE integration sucked very much and jBehave is a bit rough around the edges (like loading all behaviors), so we joined jBehave project, created Eclipse and IntelliJ plugin and fine-tuned the API, during which process the site building part of &lt;a href="http://buildmaster.rubyforge.org/"&gt;BuildMaster&lt;/a&gt; became mature.&lt;br /&gt;&lt;br /&gt;Can you imagine me keep a log of all these activities while I am working on them in my afterhour?  I didn't think so.  Although now I realize that I have different take on BDD from Dan North and Dave Astels, maybe I should write something about it, well, after I finish this thing about build and release that I learned from last project, and my thoughts on how BuildMaster can rock the world.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3. Getting Into Interesting Internal Discussion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;From time to time I met people, ThoughtWorkers or not, who are not afraid of expressing their opinion and discuss about it.  A lot of the time the outcome of the discussion is that "We now know what we don't know" (in a good way, kind of like your feeling after finish reading "&lt;a href="http://www.amazon.com/World-Flat-History-Twenty-first-Century/dp/0374292884/ref=sr_11_1/104-3916389-8449525?ie=UTF8"&gt;the World is Flat&lt;/a&gt;" from what I have been told).  So is there a point of blogging that?  Maybe, maybe not.  How to blog it, what is a good balance to strike, I think this is the time when I feel that technical writers are being paid for a reason.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Discuss or Not to Discuss&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A good project is a project that is under "Total Quality Control", i.e., every single detail of the process is constantly under review to see if there are any room for improvement.  Since ThoughtWorks has got itself out of the staffing business, ThoughtWorkers are generally taking the lead on the projects.&lt;br /&gt;&lt;br /&gt;Whenever a new ThoughtWorker joins the project, it is more than welcome, as part of ThoughtWorks culture, for him or her to question every detail of how this project is run.  Sometimes debates will rise during the day so that everyone can understand not only the way it is but also the history behind it.&lt;br /&gt;&lt;br /&gt;On the other hand, ThoughtWorks is brought in as "consulting firm", being paid to say what the right way is to run a process.  So when the new member joins and debates start occurring, it can be potentially perceived by the client as the incompetence of the existing project lead, incompetence of the new member, mismatch of the personality between the parties, or weird management style of ThoughtWorks.&lt;br /&gt;&lt;br /&gt;This happened to me several times, and luckily, my clients have been open enough to raise the question thus giving me a chance to explain.  It happens a lot less now because the first impression that I am trying to make is that "there is generally no silver bullet".  At the same time I am giving out suggestions, sometimes strong ones, I also tell the reason behind it and that those reasons are revalidated constantly.&lt;br /&gt;&lt;br /&gt;Then that makes me look like the kind of consultants that I have had contact in the past, with who are all talks and never tells the client anything concrete, the exact kind that I loath and want to stay way from.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Hence the "Tricky Business". &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are a few more thoughts on this but they are not as well thought.  Plus it is 12:30am now and I did plan on have a full night sleep for a change, well, after I finish ironing my shirt for tomorrow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115873412296301937?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115873412296301937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115873412296301937' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115873412296301937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115873412296301937'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/09/tricky-business-of-being-thoughtworks.html' title='Tricky Business of Being a ThoughtWorks Consultant'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115864828509902998</id><published>2006-09-18T23:37:00.000-07:00</published><updated>2007-03-30T12:10:42.116-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Going rSpec</title><content type='html'>After played with &lt;a href="http://rspec.rubyforge.org/"&gt;rSpec&lt;/a&gt; for a while, I have decided to convert BuildMaster on top of it.  However, the test2spec script did not work for the project, so after a few experiment, the following regular expression helped me converting the majority of the syntax.  I still had to convert the class definition to context definition manually, though.&lt;br /&gt;&lt;br /&gt;1. Converting assert_equal(a, b) to b.should_equal a&lt;br /&gt;&lt;br /&gt;replace "assert_equal\(([^,]+),\s*([^\n]+)\)" with "$2.should_equal $1"&lt;br /&gt;&lt;br /&gt;2. Converting "test_..." methods to "specify ..."&lt;br /&gt;&lt;br /&gt;replace "def test_([^\s]+)" to "specify '$1' do"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115864828509902998?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115864828509902998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115864828509902998' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115864828509902998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115864828509902998'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/09/going-rspec.html' title='Going rSpec'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115752088958844768</id><published>2006-09-05T22:26:00.000-07:00</published><updated>2007-03-30T12:10:53.381-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Speed of Unit Test</title><content type='html'>I have heard more than once from people saying that their unit tests are long because they have thousands, or tens of thousands of them.&lt;br /&gt;&lt;br /&gt;Some would blame it on the complicated application architecture, or the language (like Java).&lt;br /&gt;&lt;br /&gt;But if these guys can use a script language to &lt;a href="http://jayfields.blogspot.com/2006/09/rubyrails-unit-testing-in-less-than-1.html"&gt;run 132 tests, 219 assertions in just over half a second&lt;/a&gt;, maybe there is something to the idea of faster tests after all.&lt;br /&gt;&lt;br /&gt;I am not saying it is easy, just that it is a goal worth pushing for.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115752088958844768?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115752088958844768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115752088958844768' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115752088958844768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115752088958844768'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/09/speed-of-unit-test.html' title='Speed of Unit Test'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115714668747649041</id><published>2006-09-01T14:25:00.000-07:00</published><updated>2008-01-15T22:53:04.416-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OperSource'/><category scheme='http://www.blogger.com/atom/ns#' term='XP'/><category scheme='http://www.blogger.com/atom/ns#' term='ThoughtWorks'/><title type='text'>One Week in SLC</title><content type='html'>The past four days just flew by and I am now sitting at the airport waiting for my flight back.  I was hoping to fly my wife over so that we can visit the mountains around here during the weekend but it turned out to be much more expensive.  That is OK, I still need to scout out the beach park where I am going to host the BBQ party next weekend.&lt;br /&gt;&lt;br /&gt;I held on to a story card and paired with different developer each day.  The domain that this story affects turned out to be the worst part of the application so each day I did a bit of clean-up and refactoring.  The story dragged on a bit but I managed to make steady progress.&lt;br /&gt;&lt;br /&gt;Since this is a .NET project, there are SQL server and IIS server to run on the laptop.  After figuring out how to start and stop the service from the command, I wrote two Ruby driver class for them in the hotel room and checked them into BuildMaster.&lt;br /&gt;&lt;br /&gt;So now I have a script that I can call to stop both service with:&lt;br /&gt;&lt;blockquote&gt;services.rb stop&lt;/blockquote&gt;and all it does is:&lt;br /&gt;&lt;blockquote&gt;services = [&lt;br /&gt;BuildMaster::IisDriver.new, BuildMaster::SqlServerDriver.new&lt;br /&gt;].each do |service|&lt;br /&gt;service.send ARGV[0]&lt;br /&gt;end&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115714668747649041?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115714668747649041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115714668747649041' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115714668747649041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115714668747649041'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/09/one-week-in-slc.html' title='One Week in SLC'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115685831434974368</id><published>2006-08-29T06:23:00.000-07:00</published><updated>2008-01-15T22:53:59.413-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ThoughtWorks'/><title type='text'>Back on the Road</title><content type='html'>After almost three months of local project, which I intend to log sometime soon, I am back on the road again.&lt;br /&gt;&lt;br /&gt;This time I have my Verizon national access card that allows me get connected to do things like writing this blog at the Oakland airport.  I could request the extra battery but with only 3-hour travel time I doubt the weight is worth the benefit.&lt;br /&gt;&lt;br /&gt;Next project is an ASP.NET application and have quite a few ThoughtWorkers on it.  I am afraid that is as much as I am allowed to say.  I would like to whine about the painful download/install process I have been through in order to run the application, but I don't think anyone, like .NET or not, would care.&lt;br /&gt;&lt;br /&gt;This project is on a 4-10 schedule which means once I get myself comfortable with the code and my role, I will be able to spend only 3 nights in the hotel and sleep at home 4 nights per week.  Not that I am tired of traveling but there is something to "sleeping in your own bed".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115685831434974368?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115685831434974368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115685831434974368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115685831434974368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115685831434974368'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/08/back-on-road.html' title='Back on the Road'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115678526483952727</id><published>2006-08-28T10:08:00.000-07:00</published><updated>2008-10-24T21:11:27.836-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Communication'/><title type='text'>A Good Read: Eight Barriers to Effective Listening</title><content type='html'>&lt;a href="http://www.sklatch.net/thoughtlets/listen.html"&gt;http://www.sklatch.net/thoughtlets/listen.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Richard Watt hosted an OpenSpace session in the last HOD.  I was thinking about checking it out at the time.  But other things came up and I forgot about it.&lt;br /&gt;&lt;br /&gt;I cam in the office today preapring for the next project and saw the printout at the printer.  Figure I better grab a copy and blog it before that happens again.  (Also need to buy "&lt;a href="http://www.amazon.com/gp/product/0142000280/ref=sr_11_1/102-4110280-7634554?ie=UTF8"&gt;Getting Things Done&lt;/a&gt;").&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115678526483952727?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115678526483952727/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115678526483952727' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115678526483952727'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115678526483952727'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/08/good-read-eight-barriers-to-effective.html' title='A Good Read: Eight Barriers to Effective Listening'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115657694884797301</id><published>2006-08-26T00:13:00.000-07:00</published><updated>2007-03-30T12:12:24.018-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OperSource'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Tying Up Loose End - Cotta</title><content type='html'>So I have rolled off another project and I am going on the next project right away next week.&lt;br /&gt;&lt;br /&gt;Typing up a few the loose end at the moment, since I won't be able to have a couple of weeks beach time like I did last time.&lt;br /&gt;&lt;br /&gt;I have started with Cotta because this is most close to being ready.  Based on the feedback and my experience with Ruby file handling, I have finalized the core API.  Release candidate is &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=171037&amp;amp;package_id=195405"&gt;now available&lt;/a&gt;.  Even though I still prefer setting all the API right on the first release, my busy schedule just won't allow it.  I think I'll release 1.0 and leave it like that, until I get a chance using it or get some feedback from the field.&lt;br /&gt;&lt;br /&gt;Of course, SourceForge is done, so in the meanwhile, only the &lt;a href="http://cotta.sourceforge.net"&gt;website&lt;/a&gt; is available.&lt;br /&gt;&lt;br /&gt;More blog coming up with last project, and other loose ends.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115657694884797301?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115657694884797301/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115657694884797301' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115657694884797301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115657694884797301'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/08/tying-up-loose-end-cotta.html' title='Tying Up Loose End - Cotta'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115629556795522139</id><published>2006-08-22T18:12:00.000-07:00</published><updated>2007-03-31T20:10:40.577-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Interaction Design'/><title type='text'>Why Lotus WebAccess is not My Favorite Webmail Client</title><content type='html'>I am on a machine that has 1.99GHZ dual CPU, 2GB of RAM, and 75GB of harddrive.  Yet for every scroll up and down action in my inbox view, it sends a separate request.  So even when I know the exact date an email was sent, it still takes forever to locate it.&lt;br /&gt;&lt;br /&gt;And I noticed this is on the log out screen today:&lt;br /&gt;&lt;br /&gt;* Secure: Delete all traces of my personal use of Domino Web Access and Web pages from this computer but keep program elements (boosts performance when next person logs on).&lt;br /&gt;&lt;br /&gt;* More secure: Delete all traces of Domino Web Access and all other Web pages in the Temporary Internet Files folder.&lt;br /&gt;&lt;br /&gt;Right... I understand what they are trying to do.  But what's up with the "Secure" and "More Secure" notion?  Apparently, the "Secure" is not so "Secure" after all when there is a "More Secure", isn't it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115629556795522139?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115629556795522139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115629556795522139' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115629556795522139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115629556795522139'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/08/why-lotus-webaccess-is-not-my-favorite.html' title='Why Lotus WebAccess is not My Favorite Webmail Client'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115535072429816121</id><published>2006-08-11T19:45:00.000-07:00</published><updated>2008-10-24T21:28:44.219-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Project Management'/><title type='text'>Benevolent Dictator</title><content type='html'>This came up during a chat with someone while I was visiting the office.&lt;br /&gt;&lt;br /&gt;This is a term that has its own history (&lt;a href="http://en.wikipedia.org/wiki/Benevolent_dictator"&gt;http://en.wikipedia.org/wiki/Benevolent_dictator&lt;/a&gt;), but is now applied to a kind of management style for software development.  In opensource development, Codehaus is probably the most famous for this management style (project despot).  You should read "&lt;a href="http://www.codehaus.org/Manifesto"&gt;Codehaus Manifesto&lt;/a&gt;" if you want to understand it fully.&lt;br /&gt;&lt;br /&gt;In Agile software development, the developers have (or should have) the absolute power on deciding how and when a business value can be delivered.  While this brings lots of benefits, which we won't get into here, it does bring certain risks at the same time.&lt;br /&gt;&lt;br /&gt;Different developers might have different opinion on design of certain part of the system, or no one have strong opinion over several sound solutions for the same problem.  This is when benevolent dictator steps in, makes a decision in the team's place, and move on.&lt;br /&gt;&lt;br /&gt;Of course, this is not nearly as easy as it sound.  I did a little dig (very little, mind you) on my previous projects and pulled together the following criteria:&lt;br /&gt;&lt;br /&gt;* The power should be used when necessary but ONLY when necessary.&lt;br /&gt;* Any decision is a team's decision.  Everyone takes the credit, everyone accepts the responsibility.&lt;br /&gt;* Decision is not final in the sense that objections are noted and tracked, so that the wrong ones can be amended as early as possible.&lt;br /&gt;* The title of "benevolent Dictator" is better granted.&lt;br /&gt;&lt;br /&gt;At last, here is a PDF file that I have on my bookmark, which I think is related: "&lt;a href="http://www.ccpace.com/Resources/documents/AgileProjectManagement.pdf"&gt;Agile Project Management.pdf&lt;/a&gt;"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115535072429816121?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115535072429816121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115535072429816121' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115535072429816121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115535072429816121'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/08/benevolent-dictator.html' title='Benevolent Dictator'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115519166268415287</id><published>2006-08-09T23:34:00.000-07:00</published><updated>2008-10-24T21:24:55.739-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Communication'/><category scheme='http://www.blogger.com/atom/ns#' term='Coach'/><title type='text'>Ask "Why Do You Ask"</title><content type='html'>As a traveling consultant working for a company pushing for agile, I keep on being asked for similar question repeatedly.  "What do you do in stand-up?"  "Why is TDD good enough to spend time on?"  "What do you mean the velocity is 20 this week, 25 last week, and 18 the week before???"&lt;br /&gt;&lt;br /&gt;Naturally, I trid to come up with the best answer based on the experience I had had, the books and articles I had read, the other conversation that I had had with other people, and the understanding that I had gained about the one who asked the question.  Slowly, my answer to the above questions became bigger and bigger, with more details, more angles, as if I was getting closer and closer to the truth.&lt;br /&gt;&lt;br /&gt;WRONG...&lt;br /&gt;&lt;br /&gt;What I have realized in the past year, was that the best way to answer these questions, actually, are:&lt;br /&gt;&lt;blockquote&gt;Give a 30-second brief answer.  Stop, and ask: "Why Do You Ask?"&lt;/blockquote&gt;Different people have different situation, and are seeking the solution to different problem when asking the same question.  In this case, giving a by-the-book answer, no matter how pragmatic or complete it is, does not necessarily solve that problem.&lt;br /&gt;&lt;br /&gt;Here is a true case.&lt;br /&gt;&lt;br /&gt;When I was traveling in China, I stayed late in the office one day to do some market research and spike on &lt;a href="http://buildmaster.rubyforge.org/"&gt;BuildMaster&lt;/a&gt; project.  Another ThoughtWorker, who was doing some of his own thing, turned to me and asked "So what have you been working on lately?"&lt;br /&gt;&lt;br /&gt;Since he expressed interest in &lt;a href="http://dbfixture.public.thoughtworks.org/"&gt;DbFixture&lt;/a&gt; before, and that I knew he was on beach at the moment, I thought he was looking for something interesting to work on.  So immediately I went on talking about the problem that I was trying to solve and the "grand" vision that I had with BuildMaster, Cotta and jBehave.  I went on for 5 minutes (if not more) and realized none of them gained any interest.  Going out on a limb, and out of a bit frustration, I finally asked the million-dollar question.&lt;br /&gt;&lt;br /&gt;Turned out that he had an idea of starting an open-source project to help WebServices testing and would like to get me involved because of all the xFixture projects that I had been working on.&lt;br /&gt;&lt;br /&gt;Granted, it was not exactly a straightforward question.  Yet more and more I start paying attention to the motivations behind the questions rather than the questions themselves, and even sometimes observing the conversations others have.&lt;br /&gt;&lt;br /&gt;And the rest is history.&lt;br /&gt;&lt;br /&gt;I can now control myself much better nowadays instead of "blah blah..." for minutes.&lt;br /&gt;&lt;br /&gt;Otherwise, I might as well say "42"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115519166268415287?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115519166268415287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115519166268415287' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115519166268415287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115519166268415287'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/08/ask-why-do-you-ask.html' title='Ask &quot;Why Do You Ask&quot;'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115501489272188966</id><published>2006-08-07T22:22:00.000-07:00</published><updated>2008-01-18T18:03:10.266-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDE'/><title type='text'>Why Eclipse is not My Favorite IDE</title><content type='html'>Need to find a way to exclude certain folders in my Eclipse Ruby project so that it does not show up in the Open Resource  dialog.  Searched on line and find this in Eclipse bug database:&lt;br /&gt;&lt;blockquote&gt;&lt;pre id="comment_text_16"&gt;There is now technology in place to support exclusion filters in the workspace.&lt;br /&gt;You can create an exclusion filter in I20060110 by creating a linked resource&lt;br /&gt;to the "null" file system.  The linked resource will hide any file system&lt;br /&gt;resource with the same name, thus acting as an exclusion mechanism.&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Maybe it is now a good time to reconsider the investment in &lt;a href="http://www.activestate.com/Products/Komodo/"&gt;Komodo&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;---&lt;br /&gt;&lt;br /&gt;Update:  Thanks for Robert for pointing this one out and I stopped pounding my head (a lot less at least):&lt;br /&gt;&lt;br /&gt;apparently you can right click on the directory, select "Properties", and check the "Derived" check box, which will do the trick.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115501489272188966?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115501489272188966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115501489272188966' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115501489272188966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115501489272188966'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/08/why-eclipse-is-not-my-favorite-ide.html' title='Why Eclipse is not My Favorite IDE'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115496678694489860</id><published>2006-08-07T08:56:00.000-07:00</published><updated>2006-08-07T09:06:27.020-07:00</updated><title type='text'>Loading All Test Cases in Ruby</title><content type='html'>Now that I finally understand that '$:' in '$:.unshift' is a variable reference, and that 'require ...' is literally a method call loading the file,  I realized why there are no utilities in ruby to load all the test cases for you:&lt;br /&gt;&lt;br /&gt;create a file 'ts_all.rb' at the root directory of the test with the following content:&lt;br /&gt;&lt;br /&gt;# test/unit module that will pick up all loaded testcass automatically&lt;br /&gt;require 'test/unit'&lt;br /&gt;&lt;br /&gt;# find where the root directory of the tests is&lt;br /&gt;root = File.dirname(__FILE__)&lt;br /&gt;&lt;br /&gt;# do a name matching and iterate through all tc_*.rb files&lt;br /&gt;Dir.glob("#{root}/**/tc_*.rb") do |file|&lt;br /&gt; # load the file (assuming naming convention)&lt;br /&gt; require "#{file}"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That is it!  Executing 'ruby ts_all.rb' will just run all the tests.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115496678694489860?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115496678694489860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115496678694489860' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115496678694489860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115496678694489860'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/08/loading-all-test-cases-in-ruby.html' title='Loading All Test Cases in Ruby'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115364844456505565</id><published>2006-07-23T02:40:00.000-07:00</published><updated>2006-07-23T02:54:04.576-07:00</updated><title type='text'>BuildMaster 0.7.0 Released</title><content type='html'>Since it has already helped me a lot on setting up my personal website (&lt;a href="http://www.shaneduan.com"&gt;http://www.shaneduan.com&lt;/a&gt;), I have decided to burn some midnight oil to release 0.7.0.&lt;br /&gt;&lt;br /&gt;Now the whole BuildMaster site can be downloaded from here &lt;a href="http://rubyforge.org/frs/download.php/11919/buildmaster-0.7.0-docs.zip"&gt;http://rubyforge.org/frs/download.php/11919/buildmaster-0.7.0-docs.zip&lt;/a&gt;.  Source is also included so that it can serve as an example itself.&lt;br /&gt;&lt;br /&gt;Still need to work on a better way to convert absolute path reference (for link, css and images references).  And need to support a site descriptor like Maven or XSite so that the XHTML writing for the skin won't be so intimidating.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115364844456505565?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115364844456505565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115364844456505565' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115364844456505565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115364844456505565'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/07/buildmaster-070-released.html' title='BuildMaster 0.7.0 Released'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115219990300423088</id><published>2006-07-06T08:30:00.000-07:00</published><updated>2006-07-06T08:31:43.030-07:00</updated><title type='text'>Geek Joke</title><content type='html'>Heard this one yesterday from Miles:&lt;br /&gt;&lt;br /&gt;"C++ should actually be called ++C..."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115219990300423088?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115219990300423088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115219990300423088' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115219990300423088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115219990300423088'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/07/geek-joke.html' title='Geek Joke'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115190943977406529</id><published>2006-07-02T20:37:00.000-07:00</published><updated>2007-03-31T20:11:47.123-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Cotta Power</title><content type='html'>So I got one feedback already for Cotta project, neat!&lt;br /&gt;&lt;br /&gt;So the million-dollar question is: "How is Cotta different from other files system project like Apache commos VFS, other than support a lot less file system types?"&lt;br /&gt;&lt;br /&gt;My first response is, "Ouch, that hurt!"&lt;br /&gt;&lt;br /&gt;Second response would be, "Hmm... I think we should think through how we structure our website so that people would not try to compare it with the wrong kind of library"&lt;br /&gt;&lt;br /&gt;From the beginning, the main reason behind Cotta project is to make file operations easy to write and test (or verify the behaviours, in &lt;a href="http://www.jbehave.org"&gt;jBehave&lt;/a&gt; term).  So the main focus, which is also the power, of Cotta, is as below in two parts.  We are still bouncing our thoughts around it, and the final documentation should be published on cotta project website.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Domain Driven&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In my humble opinion, the current File class in Java, or the FileObject in Apache common VFS, or the Url in the VFS system of Borland JBuilder OpenAPI (BTW, it is nicely designed as well), all has one fundamental problem.  For this or that reason, they still don't match fully to the domain, which is, in this case, NORMAL file system operation.&lt;br /&gt;&lt;br /&gt;The number one problem I have is: "A file is NOT a directory". Namely, you want to list the children of a DIRECTORY, and the parent of a FILE should be a DIRECTORY.  You should be able read/write only the content of a FILE, not a DIRECTORY.  When your code has a path string, it should already know that it is a DIRECTORY or a FILE.&lt;br /&gt;&lt;br /&gt;Also, when I delete a DIRECTORY, it should be GONE, instead of telling me that it is not empty.  If I want a safety measure, my filesystem implementation should do that for me.  My list can go on for a while if you let me...&lt;br /&gt;&lt;br /&gt;Cotta was implemented in that way.  As it was written, we have already got a project that does file operations, so we laid out the expected behaviours of the classes one by one, and implemented the code one by one.  When it comes down to physical file system operations, there has been no guesses.  The resulting API is compact, which is exactly what we intended.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Test Driven&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Or &lt;a href="http://dannorth.net/archives/23"&gt;Behaviour-Driven&lt;/a&gt; to be exact.  When I write a class that operates on filesystem, I'd like to be able to verify the behaviour of that class.  Even being a seasoned BDD developer, I still like to spend less time writing more functionality.  And cutting the time spend on setting up and tearing down environment is always a good choice, hence the birth of XmlFixture (part of &lt;a href="http://www.sourceforge.net/projects/xpe"&gt;XPE&lt;/a&gt;, but you'll have to download the package to see the document), &lt;a href="http://dbfixture.public.thoughtworks.org/"&gt;DbFixture&lt;/a&gt;, and now Cotta.&lt;br /&gt;&lt;br /&gt;When it comes to behaviour verification, a common pattern is to go through "&lt;a href="http://www.martinfowler.com/articles/injection.html"&gt;Dependency Injection&lt;/a&gt;".  With Cotta, the domain class just need to work on a "FileSystem" instance being passed in, or one of the Cotta objects (TFileFactory, TFile, TDirectory) that can be created from the FileSystem.  During the verification phase, the filesystem is replaced with a "InMemoryFileSystem".&lt;br /&gt;&lt;br /&gt;Cotta also has FileSystem decorators that can be used to verify the behaviour on file system like read only (ControlledFileSystem), or file system with disk problems (CatastrophicFileSystem).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What Next?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The idea of making file system implementation for JAR file, FTP etc., was an after thought.  I forgot to check with Apache common VFS again to see if I am re-inventing the wheels (as it turns out, I am, more or less).  I think the next thing for us to do is to focus more on the two aspects that I have laid out above, and make it clear on the website about the real market value of this project.&lt;br /&gt;&lt;br /&gt;Why dive into the Red Ocean when you have already discovered a Blue one, right?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115190943977406529?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115190943977406529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115190943977406529' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115190943977406529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115190943977406529'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/07/cotta-power.html' title='Cotta Power'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115174089218857248</id><published>2006-07-01T00:58:00.000-07:00</published><updated>2007-03-31T20:11:47.124-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Cotta Project in Business</title><content type='html'>Finally we are in bunnies, well, sort of.&lt;br /&gt;&lt;br /&gt;A project to ease the pain of using file/directory related operations.  See detail at the front page that is still under construction: http://cotta.sourceforge.net&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115174089218857248?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115174089218857248/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115174089218857248' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115174089218857248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115174089218857248'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/07/cotta-project-in-business.html' title='Cotta Project in Business'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115138958008125367</id><published>2006-06-26T23:21:00.000-07:00</published><updated>2006-06-26T23:26:20.093-07:00</updated><title type='text'>A Cool Story</title><content type='html'>I thought something like this might happen when I started &lt;a href="http://buildmaster.rubyforge.org/"&gt;BuildMaster&lt;/a&gt;, and I sure enjoyed seeing it unfold.  Thank Nat for following up on each one of us, and thank Joe for putting it all together.&lt;br /&gt;&lt;br /&gt;You can read it here: &lt;a href="http://buildmaster.rubyforge.org/history.html"&gt;http://buildmaster.rubyforge.org/history&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115138958008125367?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115138958008125367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115138958008125367' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115138958008125367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115138958008125367'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/06/cool-story.html' title='A Cool Story'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-115087051757654509</id><published>2006-06-20T23:00:00.000-07:00</published><updated>2006-06-20T23:15:17.600-07:00</updated><title type='text'>BuildMaster 0.6.0 Released</title><content type='html'>Finally!  I get to write this blog about this little project that I have been working on.  It is amazing how much you can get done when you are commuting by BART instead of driving.&lt;br /&gt;&lt;br /&gt;It is a Ruby project that helps on the aspect of project releasing management, and website management.&lt;br /&gt;&lt;br /&gt;The URL is &lt;a href="http://buildmaster.rubyforge.org"&gt;http://buildmaster.rubyforge.org&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-115087051757654509?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://buildmaster.rubyforge.org' title='BuildMaster 0.6.0 Released'/><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/115087051757654509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=115087051757654509' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115087051757654509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/115087051757654509'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/06/buildmaster-060-released.html' title='BuildMaster 0.6.0 Released'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-114927587176280170</id><published>2006-06-02T12:16:00.000-07:00</published><updated>2008-10-24T21:29:41.916-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rants'/><title type='text'>Architectural Central Approach?</title><content type='html'>Another post that I didn't post.&lt;br /&gt;&lt;br /&gt;"... Picking story using an architecture central approach ..."&lt;br /&gt;&lt;br /&gt;My head is hurting...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-114927587176280170?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/114927587176280170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=114927587176280170' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114927587176280170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114927587176280170'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/06/architectural-central-approach.html' title='Architectural Central Approach?'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-114841383363600756</id><published>2006-05-23T11:47:00.000-07:00</published><updated>2006-05-24T02:20:30.280-07:00</updated><title type='text'>Power of Whiteboards</title><content type='html'>Just finished a kick-off of a project in Beijing, before I came back to my base office, San Francisco, for the next assignment.&lt;br /&gt;&lt;br /&gt;The project is  a short one,  with one week as QuickStart + Iteration Zero, four weeks of development, and one week of bug fixing + final release.&lt;br /&gt;&lt;br /&gt;Needless to say, the time was short and there were lots of things to do in four days, gathering the requirements, breaking them down to stories, and coming up with a release plan.&lt;br /&gt;&lt;br /&gt;As it turned out, the whiteboards became very useful.  We found two of them available, and pulled up the blinds to make the glass wall a third one. &lt;br /&gt;&lt;br /&gt;One board at the end of the room, half filled with goal of the week, and the other half as the parking area.  With the goals listed, we were able to keep ourselves focused.  And we were also free to write topics or thoughts down on the parking area as we discuss, so that we don't get side tracked.  From time to time, we check these items to cross out the things that have been taken care of.&lt;br /&gt;&lt;br /&gt;The other whiteboard stands right by the door, with a little space in front of it, for requirements discussion.  We use it to write down the role and goals, and draw process diagram on it again and again until we get it right.  Then we divide it into stories with numbers mapped to different part of the diagram and took digital photos, so that we can easily see how the stories fit into the whole pictures.&lt;br /&gt;&lt;br /&gt;The glass window turned into a over-all design board, with cards indicating internal components, external components, screens, and running list for the notes on each of the above.  For example, there are WebServices that we need to call as part of the application.  So we had a card with the WebServices name on it.  During the requirement discussion, whenever we realized that we need to use the WebServices to retrieve or update some information, we will pull the card over, put it as part of the process diagram on the discussion board, and start writing down the kind of interface we need from the WebServices.  In the end, we can just take a look at this card and come up with a list of dependencies that this application has on the WebServices.&lt;br /&gt;&lt;br /&gt;At the end of the week, looking at the three boards full of arrows, blocks, notes, I just cannot imagine how we can do without them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-114841383363600756?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/114841383363600756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=114841383363600756' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114841383363600756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114841383363600756'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/05/power-of-whiteboards.html' title='Power of Whiteboards'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-114579697978946071</id><published>2006-04-23T05:27:00.000-07:00</published><updated>2006-04-23T05:56:20.230-07:00</updated><title type='text'>A Sample of Practices Interdependencies</title><content type='html'>More than once, I have got the kind of inquiry as "I'd like to adopt agile(XP) practices, which ones do you think that I should try first.  It is always a hard question.&lt;br /&gt;&lt;br /&gt;One main reason is that I very much intend to say "every team member should have the XP book by hand, the principle up on the wall, be open-minded and try to adopt the whole practices as a whole".  It might sound intimidating but here is the reason:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;All These Practices are Related&lt;/span&gt;&lt;br /&gt;All these practices are supporting each other.  I know it has been spelled out since day one that XP came out, but I still think it is a point that gets forgotten sometimes, especially when the team is under pressure.&lt;br /&gt;&lt;br /&gt;In one of the training engagement that I was involved in, after some training sessions of several practices that we think the client needed, in an effort of making sure that the student understand that these practices are much better working together, we created a little dependency diagram using &lt;a href="http://www.graphviz.org/"&gt;Graphviz&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;We did it by creating the graphics file as following (detail omitted):&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;digraph g {&lt;br /&gt;"Collaboration" [label="Collaboration"];&lt;br /&gt;"Collocation" -&gt; "Time-Boxed Iterations and Releases";&lt;br /&gt;"Collocation" -&gt; "Continuous Improvement";&lt;br /&gt;...&lt;br /&gt;"Test First" -&gt; "Collocation";&lt;br /&gt;"Test First" -&gt; "Collaboration";&lt;br /&gt;"Test First" -&gt; "Automated Testing";&lt;br /&gt;...&lt;br /&gt;"Time-Boxed Iterations and Releases" -&gt;"Collocation";&lt;br /&gt;"Time-Boxed Iterations and Releases" -&gt;"Collaboration";&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The result was pretty staightforward:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/1315/85/1600/practice.png"&gt;&lt;img style="float:up; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger/1315/85/320/practice.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Of course, in the presentation that we gave it looks a lot nicer with bi-directional arrows and stuff.  But the idea is the same, you cannot pull one out without affecting the whole picture.&lt;br /&gt;&lt;br /&gt;On the other hand, if you want to adopt the practices, trying them one by one will probably only make things slower and harder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-114579697978946071?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/114579697978946071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=114579697978946071' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114579697978946071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114579697978946071'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/04/sample-of-practices-interdependencies.html' title='A Sample of Practices Interdependencies'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-114536417898604165</id><published>2006-04-18T05:28:00.000-07:00</published><updated>2006-04-18T05:48:44.936-07:00</updated><title type='text'>A Geek's Version of a Joke</title><content type='html'>If you have &lt;a href="http://rubyforge.org/projects/rubyinstaller/"&gt;Ruby&lt;/a&gt; and &lt;a href="http://wtr.rubyforge.org/"&gt;Watir&lt;/a&gt; installed, here is my "Geek's Version of 'How far do you want to go for a deep joke'".  Enjoy&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;require 'watir'&lt;br /&gt;&lt;br /&gt;ie = Watir::IE.start("http://www.sbpoet.com/2006/01/how_far_would_y.html")&lt;br /&gt;while link = ie.link(:text, /(blond)|(joke)|(this one is great)|(&gt;CLICK&lt;)/)&lt;br /&gt;  link.focus&lt;br /&gt;  link.click&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Personally I don't find it THAT great, but like Steve Boswell always says, "I digress".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-114536417898604165?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/114536417898604165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=114536417898604165' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114536417898604165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114536417898604165'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/04/geeks-version-of-joke.html' title='A Geek&apos;s Version of a Joke'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-114455301116293345</id><published>2006-04-08T20:08:00.000-07:00</published><updated>2008-10-24T21:31:20.002-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Project Management'/><category scheme='http://www.blogger.com/atom/ns#' term='Communication'/><title type='text'>Less Leads to More?</title><content type='html'>Just found out that I never published this...&lt;br /&gt;&lt;br /&gt;Sometimes, less does leads to more.&lt;br /&gt;&lt;br /&gt;After I came to Xi'an, I started working on a distributed project.  The development was splitted between Xi'an China and Bangalore India office.&lt;br /&gt;&lt;br /&gt;Based on the observations, I decided to cut the development team in China down as well so that we can be more focused during the communication between India and China teams.  So rather than 7-8 developers, we only have 4 developers, including me and Jake to work on the project.  It worked out pretty well.  We have got to know with each other and built a relationship that is good enough that we are free to use phone/IM/skype/iChat/campfire whenever any one of us needed something.&lt;br /&gt;&lt;br /&gt;During the weekend, I had a chance to chat with another ThoughtWorker who is working as PM on another project and he gave me another example (I don't remember the example now...)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-114455301116293345?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/114455301116293345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=114455301116293345' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114455301116293345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114455301116293345'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/04/less-leads-to-more.html' title='Less Leads to More?'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-114455098925541071</id><published>2006-04-08T18:53:00.000-07:00</published><updated>2006-04-08T20:07:39.023-07:00</updated><title type='text'>Building China Office</title><content type='html'>Flew in China on Feb. 22nd, I got myself busy right away.  The experience is still very exciting and sometimes the tension is killing me.&lt;br /&gt;&lt;br /&gt;So these are what we have been doing in China office:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Building the China Website&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We were finally able to translate the ThoughtWorks website into Chinese and started hosting it on our China domain (&lt;a href="http://www.thoughtworks.com.cn/index.html"&gt;http://www.thoughtworks.com.cn/index.html&lt;/a&gt;).  Arguing about how to translate a sentence or even just a term has been very much fun and educational at the same time.&lt;br /&gt;&lt;br /&gt;On the principle of "Fixing the Windows", we improved the staging environment by reducing the downtime from 30 minutes every hour to 5-6 minutes every hour.  Tests were also written for two bugs that we have found during the translation test.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Building the Awareness&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ThoughtWorkers in China have been pretty active in getting in touch with the local communities.  We have made arrangement with several universities in Xi'an to give the student some exposure of agile software development.&lt;br /&gt;&lt;br /&gt;Other ThoughtWorkers working on projects in the other cities are also presenting to the local universities and communities.&lt;br /&gt;&lt;br /&gt;As for me, I am going to give presentation to BEA user group meeting this month at Shanghai (&lt;a href="http://dev2dev.bea.com.cn/usergroup/20060460.html"&gt;http://dev2dev.bea.com.cn/usergroup/20060460.html&lt;/a&gt;), titled "Agile in Practice" (originally "XP in Practice").&lt;br /&gt;&lt;br /&gt;I think this is an interesting topic to give presentation to.   Whenever after someone giving the presentation about agile development, there was always a long session of questions and answers.  This presentation can serve as a follow-up by targeting those questions.&lt;br /&gt;&lt;br /&gt;With the help from other ThoughtWorkers, I have collected feedback from the projects that we have worked on in China, grouped and categoried them, so that we can show what agile is from yet another perspective.  The more I work on it, the more it reminds me of the book "XP Installed".&lt;br /&gt;&lt;br /&gt;So I am concentrate more on the photo shots and project samples.  It already has over 30 slides and over 10 megabytes in size.  Maybe I will have to cut it a bit to fit into the 60 minutes that I have for this presentation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Distributed Project&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Of course, the one and only activity that leads directly to revenue in ThoughtWorks is working on a billable project.  Since the first day that I entered Xi'an office, I have been assigned to a distributed project.&lt;br /&gt;&lt;br /&gt;The client's headquarter is in UK, and this project involves their offices in Spain and France.  So we have two BAs working in Europe gathering requirement.  The development team was originally in our Bangalore office.  Due to the lack of resource, another small development team was formed in Xi'an office and some of the work has been shifted here.&lt;br /&gt;&lt;br /&gt;As you can imagine, the communication has been identified as a risk from day one.  We have taken various measures to make sure that the developers understand the code base as well as the requirement, and that everyone is update to date on the project status.  This includes Yahoo! IM configuration so that everyone can tell which story each other is working on, daily standup meeting through iChat between Xi'an and Bangalore, and daily BA meeting conference, etc.  Of course, &lt;a href="http://www.campfirenow.com/"&gt;Campfire&lt;/a&gt; made by &lt;a href="http://www.37signals.com/"&gt;37 signals&lt;/a&gt; helped a lot on this issues, gaining more of my already established respect for them.&lt;br /&gt;&lt;br /&gt;Just within a month, there has already been a change of direction from the customer, which proved one more time that change is constant and planning is an on-going activity.  The expats in the China team left, except me, Jake who knows the code base, and Sagar who knows the business requirements.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-114455098925541071?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/114455098925541071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=114455098925541071' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114455098925541071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/114455098925541071'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/04/building-china-office.html' title='Building China Office'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-113955222425687032</id><published>2006-02-09T22:15:00.000-08:00</published><updated>2006-02-12T13:31:46.500-08:00</updated><title type='text'>Performance Testing Project</title><content type='html'>This is the project that we engaged for the last two weeks.  Even though it did not happen there are things that I have learned through out the process.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Business&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The project came to us as a returned business.  Basically, when party B did a contract for party A to build a system, they are required to find a third party to do a performance testing for the system so that they can prove that this system will work with the estimated workload.&lt;br /&gt;&lt;br /&gt;This came to us as a returned business.  It sounded like a routine contract that will just benefit all parties.  Party B gets to finish its contract and get paid, party A will get to know better about the non-functional behavior of the system.   As I have learned, the rate for performance testing contract is normally higher than other contracts.  So it would have been a good short contract for me (working with a long time ThoughtWorker, Matthew Short) before I head back to China.  And ThoughtWorks doesn't have to put me on beach.&lt;br /&gt;&lt;br /&gt;For reasons that I cannot publicly post, the contract fell through even though technically we have a pretty good idea of who we need to work with, what we need to produce and what to do to get the data.&lt;br /&gt;&lt;br /&gt;So now everyone lose.&lt;br /&gt;&lt;br /&gt;This is my first fall-through project.  Not totally surprised since I cannot imagine that all engagements that we have turn into a project, but still I am still a bit uneasy to the fact that despite all efforts, we just cannot influence the other parties to prevent them from taking actions that jeopardizes the project.&lt;br /&gt;&lt;br /&gt;Or can we, I wonder?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Technically&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;I have done some performance testing for various projects, but always as part of the project iterative tuning process.  It mainly focused on the profiling part rather than the performance benchmarking as a whole.&lt;br /&gt;&lt;br /&gt;In the last project in China, the client who hired us had a contract with the customer, which put the specific performance requirement as part of it.  It looked pretty vague to be, when reading through that part of the contract, that they are just numbers that can be easily met as long as you are free to choose the hardware, or could be almost impossible if the hardware is fixed.&lt;br /&gt;&lt;br /&gt;In preparation for project by referring to the one that we did before, I have learned about performance testing methodology, Transaction Processing Performance Council and their benchmarks (&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt;&lt;a href="http://www.tpc.org/"&gt;http://www.tpc.org&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;Because the application is going to be deployed on a Linux system (while the last one was on a Windows system), with a little research and the great help from &lt;a href="http://www.thoughtworks.com/profiles/Kwan,+Barrow.html"&gt;Barrow Kwan&lt;/a&gt;, we were able to have a Linux at our disposal, run resource monitoring programs, process the data into csv files, port them over to Microsoft Excel and generate the performance chart.&lt;br /&gt;&lt;br /&gt;I guess I didn't totally lose on this after all.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-113955222425687032?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/113955222425687032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=113955222425687032' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113955222425687032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113955222425687032'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/02/performance-testing-project.html' title='Performance Testing Project'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-113933591427570778</id><published>2006-02-07T10:10:00.000-08:00</published><updated>2006-02-07T10:42:29.553-08:00</updated><title type='text'>Three Announcements from ThoughtWorks</title><content type='html'>Internally, ThoughtWorks has lots of interesting emails about announcements and discussions.  Here are three announcements that I got this week that I think worth logging.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Selenium on OpenQA&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Selenium has moved to OpenQA (&lt;a href="http://www.openqa.org/selenium/"&gt;http://www.openqa.org/selenium/&lt;/a&gt;). For those who don't know, Selenium is a web testing technology written to various degree by a couple of ThoughtWorkers and friends.  It turns your browser into a web testing tool so that you can test your web application in any browser on any platforms.  I have used to in some projects and I strongly suggest you check it out.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;CruiseControl Better and Greater&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;I have been using CruiseControl on every single project that I have worked on in ThoughtWorks.  And I have to say that they have come a long way.  Now the latest version of CruiseControl launches web server along with the CruiseControl server, and has a "build" button on the reporting page!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Event Announcement: CI and Testing&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Greetings Continuous Integration Testers,&lt;br /&gt;&lt;br /&gt;This email is being sent to announce an upcoming event for everyone interested in continuous integration and the type of automated testing associated with it.&lt;br /&gt;&lt;br /&gt;Jeffrey Fredrick and Paul Julius are cohosting an event that will focus on these topics. The event will use Open Spaces to structure conversation, understanding and innovation.&lt;br /&gt;&lt;br /&gt;What: Open Space event discussing all aspects of CI and Testing, together&lt;br /&gt;Where: Chicago, IL&lt;br /&gt;When: Early April (final date tbd)&lt;br /&gt;Who: Everyone interested in CI and Testing&lt;br /&gt;Cost: Free&lt;br /&gt;&lt;br /&gt;We'll be inviting people for all manner of projects and places. In fact, feel free to pass this invitation along to anyone that you think will be interested.&lt;br /&gt;&lt;br /&gt;For us to finalize the details of time and place we need to get a feel for how many people are likely to attend. If you are interested in attending please join the CITCON mailing list at:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.yahoo.com/group/citcon"&gt;http://groups.yahoo.com/group/citcon&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;and post an introductory message. In your message it would be useful if you could indicate any topics of special interest and also how likely you are to attend.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Sincerely,&lt;br /&gt;Jeffrey Fredrick (jtf@agitar.com)Paul Julius (pj@thoughtworks.com)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-113933591427570778?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/113933591427570778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=113933591427570778' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113933591427570778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113933591427570778'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/02/three-announcements-from-thoughtworks.html' title='Three Announcements from ThoughtWorks'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-113805280369052844</id><published>2006-01-23T13:42:00.000-08:00</published><updated>2006-01-23T13:46:43.700-08:00</updated><title type='text'>Hey Look!  A Delete Button!</title><content type='html'>This just proves that it sometimes takes a while for even the best to see the light.&lt;br /&gt;&lt;br /&gt;Finally GMail has a "Delete" button!  Now I just need to un-train myself to click it instead of that drop-down list.&lt;br /&gt;&lt;br /&gt;Finally Yahoo Mail logs in using SSL by default!  Now I just need to stop clicking on that link on the login page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-113805280369052844?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/113805280369052844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=113805280369052844' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113805280369052844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113805280369052844'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/01/hey-look-delete-button.html' title='Hey Look!  A Delete Button!'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-113778240011301760</id><published>2006-01-20T10:08:00.000-08:00</published><updated>2006-01-20T12:02:02.656-08:00</updated><title type='text'>曲突徙薪无恩泽，焦头烂额为上客 -- An IT Phenomena</title><content type='html'>This is a thought that I had during my two week vacation.&lt;br /&gt;&lt;br /&gt;Sitting at in-law's home, I grabbed a book about Chinese idioms for my nephew to kill some time, and a story caught my attention.&lt;br /&gt;&lt;br /&gt;The story started when a guy built a beautiful house, and invited his friends and neighbors over for a house warming party.  As everyone else admiring the house and congratulating the host, one guest, however, made a comment, "The chimney is too straight up and the fire woods are too close to the stove.  If you don't make the chimney into an S shape and move the logs away from the fire, chances are that the house will catch fire before long."&lt;br /&gt;&lt;br /&gt;The host, however, was not very happy to hear these, thinking this guest is saying words of such bad luck on such a good day.&lt;br /&gt;&lt;br /&gt;As the luck went, the house did catch fire a month later.  All the neighbors came to help.  Eventually the fire was put out, leaving everyone with burns and bruises.&lt;br /&gt;&lt;br /&gt;The host was very grateful.  He opened the kitchen immediately.  He had everyone sitting in the best seat, and treated them with the best food and drinks. &lt;br /&gt;&lt;br /&gt;During the meal, another guest, who also came to the house-warming party, brought up the topic, "A month ago during your house warming party, there was a guest that predicted that this would happen.  Had you listen to him at that time, chances are that your house will not catch fire and we would not be sitting here enjoying the feast.  Don't you find it backwards, when the one who recommended the modification on the chimney and moving away the log was not being appreciated, while the rest of us with burns and bruises are being treated as the best guests (曲突徙薪无恩泽，焦头烂额为上客)?"&lt;br /&gt;&lt;br /&gt;The host came to realize the mistake that he has made.  He immediately sent for that guest, and treated him with the best seat in the house.&lt;br /&gt;&lt;br /&gt;As I work through projects and in different organizations, in ThoughtWorks or before ThoughtWorks, I noticed that the person who is good at putting out the fires are always the one that gets the limelight.  The person could be a manager who knows how to talk to the customer to cut the scope in the last minute, or find ways to persuade the developers to work overtime, or he/she could be a developer who is good at digging through a bunch of messy code and come up with a hacking patch for a last minute bug.&lt;br /&gt;&lt;br /&gt;On the other hand, there don't seem to have enough attention to the sources of all these crises.  People tend to pay most attention to how to resolve these crises rather than how to prevent these crises.  So advice was not given any thought and measures were not taken because "if it aint broke, don't fix it".&lt;br /&gt;&lt;br /&gt;And there are more crises.&lt;br /&gt;&lt;br /&gt;And it is more important to keep the ones who knows how to put out fires with burns and bruises.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-113778240011301760?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/113778240011301760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=113778240011301760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113778240011301760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113778240011301760'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2006/01/it-phenomena.html' title='曲突徙薪无恩泽，焦头烂额为上客 -- An IT Phenomena'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-113463016469275459</id><published>2005-12-14T22:35:00.000-08:00</published><updated>2005-12-14T23:02:44.706-08:00</updated><title type='text'>The Job of Project Manager</title><content type='html'>I always believe a real good project manager is not one who always resolves crises, the same reason that a real good developer is not one who knows how to fix his own bugs.  The reason is simple: it takes more skill to prevent problem than that to resolve problems.&lt;br /&gt;&lt;br /&gt;I think a good project manager is one that make sure everything runs smoothly.  For example, all the necessary preparations are done before each meeting and all the action items come out of a meeting are being followed in time and properly.  Each of the team member knows what the project vision is, knows how to do his or her own job, and is motivated to do the job.&lt;br /&gt;&lt;br /&gt;Sounds too vague huh?  I agree.  And the reason for this bolg is that I finally have something concrete.&lt;br /&gt;&lt;br /&gt;For various reason, we are now having an agile development team with a project manager who is not experienced in an agile project.  In China, it is very common to have a project manager with technical background, and it is very common for the project manager to help out the development work rather than managing the project.&lt;br /&gt;&lt;br /&gt;In order to help the new PM managing this project (rather than checking out the source code and database schema), I asked for Renee, another ThoughtWorker who were the manager of this team to write down a list of responsibilities.  It turns out to be very helpful for everybody.  She also directed me to this on-line document (&lt;a href="http://ccpace.com/Resources/documents/AgileProjectManagement.pdf"&gt;Agile Project Management&lt;/a&gt;), which is a good read as well.&lt;br /&gt;&lt;br /&gt;The following is the list:&lt;br /&gt;&lt;br /&gt;Here is a summary of the key responsibilities of a PM on an Agile project:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;VISION - Establishing a guiding vision for the project and continuously reinforcing it through works and actions.&lt;/li&gt;&lt;li&gt;Ensure the team and client understand the vision.&lt;/li&gt;&lt;li&gt;Clear up any questions about the vision.&lt;/li&gt;&lt;li&gt;Includes timeline, release planning, scope.&lt;/li&gt;&lt;li&gt;TEAMWORK &amp; COLLABORATION - Facilitate collaboration and teamwork through relationships and community.&lt;/li&gt;&lt;li&gt;Establish a good relationship with the team and client.&lt;/li&gt;&lt;li&gt;The team and client will come to you with issues if they trust you.&lt;/li&gt;&lt;li&gt;SIMPLE RULES - Establish and support the teamÂs set of guiding practices.&lt;/li&gt;&lt;li&gt;Examples include TDD, standups, pair programming, etc..&lt;/li&gt;&lt;li&gt;OPEN INFORMATION - Provide open access to information&lt;/li&gt;&lt;li&gt;Release plan&lt;/li&gt;&lt;li&gt;Story list&lt;/li&gt;&lt;li&gt;Progress, velocity&lt;/li&gt;&lt;li&gt;Staffing changes&lt;/li&gt;&lt;li&gt;LIGHT TOUCH - Apply just enough control to foster emergent order.&lt;/li&gt;&lt;li&gt;Demanding control will only cause the team to lose order.&lt;/li&gt;&lt;li&gt;Empower team members to do their jobs&lt;/li&gt;&lt;li&gt;AGILE VIGILANCE - Constantly monitor and adjust.&lt;/li&gt;&lt;li&gt;Hold retrospectives on team progress&lt;/li&gt;&lt;/ul&gt;An Agile PM needs to be full time on the project. A part-time PM cannot remove obstacles, encourage collaboration, or provide vision.  Here are some addition day to day responsibilities:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Lead stand-ups&lt;/li&gt;&lt;li&gt;Track daily progress&lt;/li&gt;&lt;li&gt;Manage release plan&lt;/li&gt;&lt;li&gt;Communicate with customer leads&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Supporting the team and helping the customer to understand project decisions, e.g., why we want to do J2EE without EJB&lt;/li&gt;&lt;li&gt;Listening to the developers and team, helping to remove obstacles&lt;/li&gt;&lt;li&gt;Risk identification and mitigation &lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-113463016469275459?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/113463016469275459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=113463016469275459' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113463016469275459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113463016469275459'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2005/12/job-of-project-manager.html' title='The Job of Project Manager'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-113163655774541197</id><published>2005-11-10T07:13:00.000-08:00</published><updated>2005-11-10T08:21:50.886-08:00</updated><title type='text'>The Job of Architect</title><content type='html'>In the ThoughtWorks project that I have been working on, there are just one lead and several developers. Even though the lead is normally called "Architect" because that is the term that we use externally, he or she is much difference from what people normally think of Architects.&lt;br /&gt;&lt;br /&gt;Rather than drawing all kinds of fancy diagrams and leave to the developers to implement the design (More than once I have heard of this theory that the developers don't have to be highly skilled as long as they do what is told).&lt;br /&gt;&lt;br /&gt;In my previous projects, I have been very impressed with the work of our project lead. Highly technical and very experienced, the lead pairs with the team and working out the design decisions with the team. I felt that this is the best way for each member of the team to learn and grow and this is the best way to come to the right decision for the project.&lt;br /&gt;&lt;br /&gt;On this project, being an architect turns out to be much more than just leading the development work. The current project involves three different servers posting their interfaces through WebServices and communicate to each other through these interfaces. WebMethods is the data exchange platform so that more services can be added, and there is a CA server for certificate verifications. Because of this, there are a lot of coordination required among the development groups. In addition, the requirement is not clear so I need to help the BA on the story list creation.&lt;br /&gt;&lt;br /&gt;So between the development groups technical discussions and requirements gathering, I have not been too active on programming. The worst day was last Tuesday, where I had meeting back to back from the morning to the evening. I have been trying to play catch-up, looking through the code after work. But now I realize that with the code changes everyday, I will end up killing myself and still not able to keep myself up-to-date. So I am now delegating the design decisions to the team and pay more attention to their development practices like pair programming, test driven development, rotation, etc.&lt;br /&gt;&lt;br /&gt;The good thing is that with the BA on track with the requirements gathering and story list creation, I get to concentrate more and more on the development.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-113163655774541197?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/113163655774541197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=113163655774541197' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113163655774541197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113163655774541197'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2005/11/job-of-architect.html' title='The Job of Architect'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-113103819288534019</id><published>2005-11-03T09:10:00.000-08:00</published><updated>2005-11-03T09:16:32.896-08:00</updated><title type='text'>Two More about China Environment</title><content type='html'>So here are two more things that I thought worth mentioning.&lt;br /&gt;&lt;br /&gt;All the three hotel rooms that I have been staying at have a central control panel by the bed. So to go to sleep you can just press one button, which will turn off all the lights and sets up the sign "Don't disturb" at the door. Pretty cool eh?&lt;br /&gt;&lt;br /&gt;Although they don't have an alarm clock.&lt;br /&gt;&lt;br /&gt;The connection in China to US is BAAAAAAAAAAD.  I did a download speed test the other day and here are the data:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;ThoughtWorks gforge 0.6kb&lt;/li&gt;   &lt;li&gt;sourceforge 1.9kb&lt;/li&gt;   &lt;li&gt;rubyforge 2.3kb&lt;/li&gt;   &lt;li&gt;java.net 2.7kb&lt;/li&gt;   &lt;li&gt;codehaus 2.3kb&lt;/li&gt; &lt;/ul&gt; Doesn't that remind you the good-old days of dial-up? :)&lt;br /&gt;&lt;br /&gt;BTW, the connection within China is pretty fast.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-113103819288534019?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/113103819288534019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=113103819288534019' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113103819288534019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113103819288534019'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2005/11/two-more-about-china-environment.html' title='Two More about China Environment'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-113068946000067400</id><published>2005-10-30T07:47:00.000-08:00</published><updated>2005-10-30T08:27:48.150-08:00</updated><title type='text'>Things to be Prepared for in China</title><content type='html'>First of all I think I need to say that I am still greatly enjoying working with great people in China and enjoying great food here.&lt;br /&gt;&lt;br /&gt;Originally I put the title as "Things that I don't like in China". But later I thought about all these stuff I realized that they probably won't change in a short period of time. So the only solution is to watch out and try not to get bothered. (Granted, the city we are staying is not as a big city like Beijing or Shanghai).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Private Space&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I know it always happens in a place where there are lots of people and limited spaces. However, from time to time, I still get surprised.&lt;br /&gt;&lt;br /&gt;For example, now I have learned that when the elevator reaches your floor, you need to step right in from of the door and get ready to block the door so that you can push your way out easily. Otherwise, there will be people pushing their way in so quickly that you might have a hard time getting out.&lt;br /&gt;&lt;br /&gt;Another case is that when talking to the front desk don't get offended if someone else just budge in and start asking question to the person who you are talking to at the moment. And don't get surprised if that person will switch attention to him or her right away and let you stand there waiting for the answer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Limited Services&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Traveling in United States, I have gotten used to stepping in a hotel and have iron board, steaming iron ready in the room. When I travel for over a week, I know I can always find a place to wash my clothes, most of the time inside the hotel that I am staying at. However, that is not the case here. Both hotels I stayed at in Shijiazhuang don't have iron and board. And I had to buy an iron because the second hotel has only the old style ones that burn shirts easily. Laundry has been a problem because I cannot find any place to wash them myself.&lt;br /&gt;&lt;br /&gt;The other guys found two apartments to stay in. I was hoping to be able to do laundry at their places. However, the apartment services here is hardly any good. The washing machine in one apartment does not work, and the other one is missing a water pipe. What's more, there has been some repairing or construction going on and they have been out of hot water for over a week. Calling the owner or the property management has been in vain. The guys have been pretty cool about it by taking the shower at the shower room of the swimming pool downstairs. Still, I don't find it satisfying.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Task Management&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In our working environment, there seems to exist a tendency of setting the task without setting the date. At the beginning the reply we here very often was "ok, let me discuss with them about this". In a project that has only 3 months and still working on requirements at the third iteration, this kind of got me nervous. However, all we needed to do was to ask for a date, either for the answer or a follow-up date about the date.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-113068946000067400?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/113068946000067400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=113068946000067400' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113068946000067400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/113068946000067400'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2005/10/things-to-be-prepared-for-in-china.html' title='Things to be Prepared for in China'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-112921097512926772</id><published>2005-10-13T06:23:00.000-07:00</published><updated>2005-10-13T07:59:45.236-07:00</updated><title type='text'>One Week in China</title><content type='html'>This moment exactly one week ago, I checked in the Great Wall Sheraton Hotel in Beijing, and began my life as a consultant traveling oversea.&lt;br /&gt;&lt;br /&gt;One week is not a long time, but it has already been a blast. The ThoughtWorkers in China get along very well (not that the ones in US didn't) and there is always constant conversation during the day as we cranking off the story cards. Because of this tight relationship (the other four guys actually live together in two apartments of the same complex), conversations are very open. For example, the CruiseControl server is in the same room, on a Windows machine, so the guys set it up so that every time there is a broken build, it will play a 20 second clip saying in Chinese something like&lt;br /&gt;&lt;blockquote&gt;"What the !@#$% are you doing that for... Would you ever stop? I have already told you that I cannot handle it anymore, but you keep on doing it, doing it, doing it. You just don't care if I can stand it or not. If you do it one more time I probably will have to stab you..."&lt;br /&gt;&lt;/blockquote&gt;The original text can be found &lt;a href="http://culture.netbig.com/topic/xiyou/text/g0210.htm"&gt;here&lt;/a&gt; and it is definitely much funnier to hear it in person. Because it is long and loud, it easily gets annoying, and with the good team relationship whoever broke the build definitely gets a lot peer pressure to fix the build.&lt;br /&gt;&lt;br /&gt;There is also a bonus for me on this project. That is I get to get involved in a lot of project management stuff. With the client speaking Chinese, I am helping the manager whenever we need to talk to the client or whenever they need to talk to us about project plan and arrangement. The current crucial task is the story list. Because there is not a full-time BA, and that we are only developing one part of the system, and because that the time is limited, we are trying to finalize the story list, so that we can track the project progress with higher accuracy. So I am also going to play the role of BA for a little bit whenever there is a translation needed.&lt;br /&gt;&lt;br /&gt;On Monday, we had a kick-off meeting. Because this is the first time that the customers were involved in iteration planning, and that this is the second time that they were presented with Agile Software Development, we decided to give them a second presentation of agile software development, focusing on the benefit, role and responsibility of the customers, and we were able to invite the deputy director.  I believe the presentation was well received, because the deputy directory got excited and spoke at the end that we should receive the full support from their side. The full-time customers that have been assigned to us also turned out to be good natured and knowledgeable to the domain.&lt;br /&gt;&lt;br /&gt;One more reason that I love this team is also because that the guys are very comfortable with me adding the Dvorak keymap to each laptop that I touched. We set Alt+Shift+8 for QWERT and Alt+Shift+9 for Dvorak and it works out pretty good. Someone even showed interest in learning Dvorak. Hehee... Maybe sometime we can finally say bye-bye to QWERT in the China office.&lt;br /&gt;&lt;br /&gt;It is also interesting to learn the Chines meaning of the terminologies that I have been working with for the last 6 years.  The following is a list that is on top of my mind:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Development: 开发&lt;/li&gt;   &lt;li&gt;Iteration: 迭带&lt;/li&gt;&lt;li&gt;Document: 文档&lt;/li&gt;   &lt;li&gt;Release: 发布&lt;/li&gt;   &lt;li&gt;Deployment: 部署&lt;/li&gt;   &lt;li&gt;Class: 类型&lt;/li&gt;&lt;li&gt;Method: 方法&lt;/li&gt;&lt;li&gt;Agile Development: 敏捷开发&lt;/li&gt;   &lt;li&gt;Project Management: 项目管理&lt;/li&gt;   &lt;li&gt;Test: 测试&lt;/li&gt;   &lt;li&gt;Run Test: 跑测试&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Constructor: 构造函数&lt;/li&gt;     &lt;/ul&gt;And learning Wubi (五笔), a Chinese input method, is fun as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-112921097512926772?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/112921097512926772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=112921097512926772' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/112921097512926772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/112921097512926772'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2005/10/one-week-in-china.html' title='One Week in China'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-112870021608859185</id><published>2005-10-07T08:03:00.000-07:00</published><updated>2005-10-07T08:50:16.136-07:00</updated><title type='text'>Arrived at ShiJiaZhuang</title><content type='html'>After a 12-hour flight, half hour Customs Service (The 'Paul and Jamie Buckman' behind me sure made it seem like 2 hours), one night hotel, 2-hour train ride with half hour delay, I finally arrived the city of the project, ShiJiaZhuang (石家庄).&lt;br /&gt;&lt;br /&gt;I have finally met three of the four ThoughtWorkers in China office, Li Mo, Li Chaoqun and Li Xiao. (Yes, Li is a common name in China), and I got a chance to talk with Li Mo on the train. Sid's comment of ThoughtWorkers was "young and super smart" (sounds like the early days of ThoughtWorkers?) and talking with them sure confirmed it.&lt;br /&gt;&lt;br /&gt;What I have gathered so far has already shown that projects in China is definitely different from the states, unfortunately I cannot reveal much. As much as I want to keep this blog on my experience in ThoughtWorks, the special condition in China might force me to log lots of them on an internal server.  I guess we shall see.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-112870021608859185?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/112870021608859185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=112870021608859185' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/112870021608859185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/112870021608859185'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2005/10/arrived-at-shijiazhuang.html' title='Arrived at ShiJiaZhuang'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-112761287501624466</id><published>2005-09-24T18:14:00.000-07:00</published><updated>2005-09-24T18:47:55.023-07:00</updated><title type='text'>Walking off, and Going to China Project</title><content type='html'>This is one of the times that I am proud to be a ThoughtWorker.&lt;br /&gt;&lt;br /&gt;We have been working with the current client for over a half year (I joined three months ago). The agreement has always been that this is a transformation (formerly known as enablement) project, that, given the clients' background of waterfall approach and ThoughtWorks' experience in agile development, should rely highly on ThoughtWorks' input. That is, for a start, during the scoping phase form a small group (6) and have one on one ratio of ThoughtWorker and the employee from the client.&lt;br /&gt;&lt;br /&gt;But apparently someone thinks that if they pay us they own us. Before the pilot project even starts (hence gets the requirement), there is already order from high up to use one of those so called "J2EE framework server". And during the initial phase, there are going to be 9 people instead, with only 3 from ThoughtWorks. All these decisions are made without even consult ThoughtWoks (you would think that should be the reason to hire a "consultant"). And no reason has been given for these decision.&lt;br /&gt;&lt;br /&gt;So as the current finishes this month. The manager decided not to renew it and walk off from a project that is not built on a solid ground of trust and understanding, even thought the rate on this project is fair and we might have a good account. This decision got the support from the headquarter and the four of us are already on the list of available consultants for October.&lt;br /&gt;&lt;br /&gt;As for me, I am really glad of the decision being made, because that shows that we are serious about being good at what we do, and the we care about have happy consultants on the project.&lt;br /&gt;&lt;br /&gt;Another good reason for me to be happy is that the moment my name come up, there is already a good project for me to go -- China. Because of this and last transformation project that I worked on, and the fact that I speak Madrine, I turn out to be a good fit for this project that needs someone to come in and help out. Time is short so I am busy working on the visa and travel plans.&lt;br /&gt;&lt;br /&gt;At this moment, my goal of China trip is the following, I am still updating it:&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Get to know the ThoughtWorkers in China: I have heard of great things about the people that we hire there. I need to spend as much time as I can to get to know them and exchange our experiences to learn from each other.&lt;/li&gt;   &lt;li&gt;Get to know the market in China: Despite the great potential in Xi'an, I still think there should be a lot of opportunities in Beijing and Shanghai. Agile software development in China is getting a lot of attention, if we don't grasp the market and build our good names, there will be someone else very soon.&lt;/li&gt;   &lt;li&gt;Get to know the IT environment: There might be a lot of things that I am taking for granted here that is not as available. Programming in a non-English speaking environment might bring different dynamics.&lt;br /&gt;&lt;/li&gt; &lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-112761287501624466?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/112761287501624466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=112761287501624466' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/112761287501624466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/112761287501624466'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2005/09/walking-off-and-going-to-china-project.html' title='Walking off, and Going to China Project'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-112735518994889163</id><published>2005-09-21T19:04:00.000-07:00</published><updated>2005-09-21T19:33:10.433-07:00</updated><title type='text'>Deployment Script with Watir (Take THAT, Websphere!)</title><content type='html'>So, after some struggling with Websphere on deploying an EAR file (Don't ask me question about why we still bother, please... ) and not able to get a hand on a simple deployment script (I think there should be one but I just didn't have the time to look further), I have decided to automate the web process that I have been doing, using WATIR.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Task&lt;/span&gt;&lt;br /&gt;Call me innocent, but I really thought that depolying an EAR file on an application server would be easy, given the 'comprehensive' file structure and all the deployment descriptors.&lt;br /&gt;&lt;br /&gt;But no..., you have to click through this long 'wizard' (ooohhh...) process every single time. Not only you have to do it manually, it also takes quite a lot of time. And I happen to be one of the impatient guys who thinks that it is a machine's job, then a human should not suffer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Watir&lt;/span&gt;&lt;br /&gt;In case you haven't heard of it, Watir (&lt;a href="http://wtr.rubyforge.org/"&gt;http://wtr.rubyforge.org/&lt;/a&gt;) is a ruby library used for web testing. I am still not sure how exactly it works, but the result is that you can control an internet explorer instance using Ruby script. So basically almost anything you do with IE, you can write a script and automate it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Code&lt;/span&gt;&lt;br /&gt;So long story short, I was finally able to write a script that uploads the file to the server, click through the steps, and save the configurations.  Needless to say, I am very impressed the progess that Watir has made, functionality as well as the documentations.&lt;br /&gt;&lt;br /&gt;The script is actually not that long.  Here it is (with comments):&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;require 'watir'&lt;br /&gt; &lt;br /&gt;class IeLauncher&lt;br /&gt;  def IeLauncher.open(*args)&lt;br /&gt;    result = ie = Watir::IE.start(*args)&lt;br /&gt;    if block_given?&lt;br /&gt;      begin&lt;br /&gt;        result = yield ie&lt;br /&gt;      ensure&lt;br /&gt;        ie.close&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;    return result&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt; &lt;br /&gt;# Ignore the above, they are just basic set up.&lt;br /&gt; &lt;br /&gt;# Launch IE, go to the specified URL&lt;br /&gt;IeLauncher.open('http://localhost:9060/ibm/console/') do |ie|&lt;br /&gt;  # Log in, my local server doesn't have a password&lt;br /&gt;  ie.text_field(:name, 'username').set('admin')&lt;br /&gt;  ie.button(:value, 'Log in').click&lt;br /&gt; &lt;br /&gt;  # Only one login is allowed so you will have to log out last one&lt;br /&gt;  if ie.contains_text('Login Conflict')&lt;br /&gt;    ie.radio(:name, 'action', 'force').set&lt;br /&gt;    ie.button(:value, 'OK').click&lt;br /&gt;  end&lt;br /&gt; &lt;br /&gt;  # Apprantly when you deploy an application, you need to 'save' it.&lt;br /&gt;  # This recovers it&lt;br /&gt;  if ie.contains_text('Recover prior changes')&lt;br /&gt;    ie.radio(:name, 'action', 'recover').set&lt;br /&gt;    ie.button(:value, /OK/).click&lt;br /&gt;  end&lt;br /&gt; &lt;br /&gt;  # This get the frame that has the navigation tree and look for the right node&lt;br /&gt;  navigation = ie.frame('navigation_tree')&lt;br /&gt;  navigation.link(:text, 'Applications').click&lt;br /&gt;  navigation.link(:text, 'Enterprise Applications').click&lt;br /&gt;  detail_frame = ie.frame('detail')&lt;br /&gt; &lt;br /&gt;  # Uninstall the existing deployment&lt;br /&gt;  if detail_frame.contains_text('DukesBank')&lt;br /&gt;    dukesbank_checkbox = detail_frame.checkbox(:value, /DukesBank/)&lt;br /&gt;    dukesbank_checkbox.click&lt;br /&gt;    detail_frame.button(:value, 'Uninstall').click&lt;br /&gt;    detail_frame.button(:value, 'OK').click&lt;br /&gt;  end&lt;br /&gt; &lt;br /&gt;  # Install&lt;br /&gt;  detail_frame.button(:value, 'Install').click&lt;br /&gt;  detail_frame.radio(:name, 'radioButton', 'local').click&lt;br /&gt; &lt;br /&gt;  # Upload the file (Note, file path cannot have space)&lt;br /&gt;  detail_frame.file_field(:name, 'localFilepath').set('c:\Work\Dukes\DukesBankEAR\build\artifacts\DukesBankEAR.ear')&lt;br /&gt;&lt;br /&gt;  # Clicking through the wizards&lt;br /&gt;  button = detail_frame.button(:value, 'Next')&lt;br /&gt;  while button.exists?&lt;br /&gt;    button.click&lt;br /&gt;    button = detail_frame.button(:value, 'Next')&lt;br /&gt;  end&lt;br /&gt;  detail_frame.button(:value, 'Finish').click&lt;br /&gt;  detail_frame.link(:text, 'Save to Master Configuration').click&lt;br /&gt;  detail_frame.button(:value, 'Save').click&lt;br /&gt;  navigation.link(:text, 'Enterprise Applications').click&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-112735518994889163?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/112735518994889163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=112735518994889163' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/112735518994889163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/112735518994889163'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2005/09/deployment-script-with-watir-take-that.html' title='Deployment Script with Watir (Take THAT, Websphere!)'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6678855.post-112633321124359456</id><published>2005-09-09T22:52:00.000-07:00</published><updated>2008-01-18T18:08:07.621-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IDE'/><category scheme='http://www.blogger.com/atom/ns#' term='Coach'/><title type='text'>Feedback from the Client</title><content type='html'>I have meant to post this a while ago, but with the traveling my daily schedule is still not settled. So I never found a good time that I can just quiet down and write some blog.&lt;br /&gt;&lt;br /&gt;This week is a short week due to the past long weekend. So we were able to convince the client that it is better for us to work from our home office so that we don't need to spend two days traveling for a four-day week. And once again, I am able to continue my routine of blogging.&lt;br /&gt;&lt;br /&gt;After my last enablement project (now the term is "transforming" because "enablement" has been used along with "training". I will explain that later), the client team had a project retrospective, discussing what they have learned during the project.&lt;br /&gt;&lt;br /&gt;With their still fresh memory, they were able to extrapolate the following, with which they gave the presentation to the rest of the organization. They are nice enough to let me publish this. I hope this can be useful for some of you who are still wondering about agile software engineering, or at least some of the "weird practices" that I have been defending from time to time. This is the first-handed note. Hopefully I can help them revise the format for more formal presentations.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Agile: One Developer's Perspective&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What methodology did we use in the past?&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;It doesn't have a name, as far as I know, but here are some features of it&lt;/li&gt;   &lt;li&gt;big upfront requirements-gathering, big upfront design, with some formal and some informal documentation&lt;/li&gt;   &lt;li&gt;one developer per application, or a couple of developers working in different tiers of an application&lt;/li&gt;   &lt;li&gt;integration &amp;amp; testing in a big bang at the end&lt;/li&gt;   &lt;li&gt;manual testing&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Some problems we had with this approach&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Big upfront...&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;late-breaking requirements changes combined with inflexible deadlines led to periodic frenzies of coding that eroded the integrity of the big upfront design&lt;/li&gt;   &lt;li&gt;sometimes we specified &amp;amp; designed more than we could actually implement with the time and resources we had &lt;/li&gt;   &lt;li&gt;integration late in the development cycle led to periodic frenzies of coding that eroded the integrity of the big upfront design&lt;/li&gt;   &lt;li&gt;disagreements about how open we should be to changes&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;One developer, or a couple of developers working in different tiers of an application...&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;we didn't always take advantage of possibilities for using some common code or common approaches across applications&lt;/li&gt;   &lt;li&gt;difficulty scaling up for larger efforts&lt;/li&gt;   &lt;li&gt;the culture of code ownership by individuals was sometimes at odds with our "esprit de corps"&lt;/li&gt; &lt;/ul&gt; Integration &amp;amp; testing in a big bang at the end; manual testing...&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;huge burden placed upon QA (when we had QA at all)&lt;/li&gt;   &lt;li&gt;difficulties detecting the ramifications of maintenance changes, so we became timid about upgrading applications and we ended up with multiple versions of the same module in production&lt;/li&gt;   &lt;li&gt;we often had as many opinions about how close we were to being finished as we had team members&lt;/li&gt;   &lt;li&gt;we did not know how to thoroughly test componentry; we could only test built apps&lt;/li&gt; &lt;/ul&gt; For me personally, the biggest problem was that I was unhappy. I felt that our team could be great, but we just couldn't get there, and I didn't know how to be "part of the solution".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Enter Thoughtworks, with a philosophy and a toolbox&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Some things I was immediately enthusiastic about...&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;Eclipse IDE (Great no matter what methodology you embrace)&lt;/li&gt;   &lt;li&gt;Automated testing&lt;/li&gt;   &lt;li&gt;Daily standup meeting&lt;/li&gt;   &lt;li&gt;Frequent discussions as a group about what is working and what isn't, so that we can make incremental corrections in our direction&lt;/li&gt;   &lt;li&gt;Realistic attitude towards estimating: as the project progresses, we can get more accurate in our predictions of a delivery date, but we can't expect perfect accuracy at the beginning.&lt;/li&gt;   &lt;li&gt;steady pace, avoiding individual heroics&lt;/li&gt;   &lt;li&gt;Simplicity--the art of maximizing the amount of work not done--is essential. (From "Principles behind the agile manifesto"     &lt;a href="http://agilemanifesto.org/principles.html"&gt;http://agilemanifesto.org/principles.html&lt;/a&gt;)&lt;/li&gt; &lt;/ul&gt; Some things I was skeptical but open-minded about...&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;TDD&lt;/li&gt;   &lt;li&gt;Test-driven development requires that a unit test be written for each tiny piece of functionality before you write any application code&lt;/li&gt;   &lt;li&gt;The unit tests are written by the developers, not QA&lt;/li&gt;   &lt;li&gt;Although "test" appears in its name, test-driven development is not so much about testing as it is about enforcing a development discipline that makes refactoring possible&lt;/li&gt;   &lt;li&gt; The unit tests serve as documentation of the developer's understanding of requirements&lt;/li&gt;   &lt;li&gt;"radical co-location"&lt;/li&gt;   &lt;li&gt;continuous integration&lt;/li&gt;   &lt;li&gt; fully automated build and test process that allows a team to build and test their software many times a day&lt;/li&gt;   &lt;li&gt; everybody using the same code base, checking in and updating their code very frequently&lt;/li&gt;   &lt;li&gt;at first, I was incredulous that checking in and building as frequently as once per day would even be possible; TWers viewed once a day as a minimum&lt;/li&gt; &lt;/ul&gt; Some things I was deeply skeptical about...&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;paired programming&lt;/li&gt;   &lt;li&gt;code ownership is to be avoided&lt;/li&gt;   &lt;li&gt;evolutionary design through refactoring&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Martin Fowler's definition&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What is Refactoring?&lt;/span&gt;&lt;br /&gt;Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. Its heart is a series of small behavior preserving transformations. Each transformation (called a 'refactoring') does little, but a sequence of transformations can produce a significant restructuring. Since each refactoring is small, it's less likely to go wrong. The system is also kept fully working after each small refactoring, reducing the chances that a system can get seriously broken during the restructuring.&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;very short iterations&lt;/li&gt;   &lt;li&gt;less emphasis on formal documentation&lt;/li&gt;   &lt;li&gt;"embrace change"&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;A year later&lt;/span&gt;&lt;br /&gt;Life on our team is completely different than before.  From my perspective, it is much better.&lt;br /&gt;Did the philosophy and the toolbox make a difference?&lt;br /&gt;Yes, but not all by themselves.  We had to have...&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;the right attitude&lt;/li&gt;   &lt;li&gt;one-on-one mentoring from experienced agile developers&lt;/li&gt;   &lt;li&gt;effective leadership&lt;/li&gt;   &lt;li&gt;discipline&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;Attitude&lt;br /&gt;We could not have made changes as extensive as this without&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;positive attitudes&lt;/li&gt;   &lt;li&gt;team spirit&lt;/li&gt;   &lt;li&gt;perseverance&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;one-on-one mentoring from experienced agile developers&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;from the agile manifesto: "value individuals and interactions over processes and tools"&lt;/li&gt;   &lt;li&gt;TDD feels initially so unnatural, that it is essential to have a patient, experienced person at your elbow&lt;/li&gt;   &lt;li&gt;without discipline, the agile philosophy can degenerate into "a license to hack", so it is important to have constant reminders about the discipline until it is second nature&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;effective leadership&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;the project manager may be an exception to the general principle that individual heroics should not be required&lt;/li&gt;   &lt;li&gt;protected the group from distractions&lt;/li&gt;   &lt;li&gt;keeps both the big picture and myriad details in mind&lt;/li&gt;   &lt;li&gt;inspires confidence&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;discipline&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;do not write even the smallest method without writing a test first; see the test fail, then write the minimum amount of code to make it pass&lt;/li&gt;   &lt;li&gt;update from the repository frequently, run the entire test suite before each check-in of your own&lt;/li&gt;   &lt;li&gt;builds &amp;amp; test suites run continuously; if your check-in breaks the build, STOP and fix&lt;/li&gt;   &lt;li&gt;to maintain design and code integrity, coding decisions are made in pairs...if the pair can agree, go forward&lt;/li&gt; &lt;/ul&gt; If the discipline is not observed, then we can't "embrace change" and "evolve the design through refactoring" because we can't be confident about extensive changes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Notes&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.martinfowler.com/articles/newMethodology.html#id2249560"&gt;http://www.martinfowler.com/articles/newMethodology.html#id2249560&lt;/a&gt;&lt;/li&gt;   &lt;li&gt;&lt;a href="http://loki.lokislabs.org/weblog/archives/2003/11/15/radical_colocation_is_a_good_thing.php"&gt;http://loki.lokislabs.org/weblog/archives/2003/11/15/radical_collocation_is_a_good_thing.php&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;Below is a summary of BTM/70, a methodology in use at a job I had 20 years ago at a company. It is probably an example of what the "value individuals and interactions over processes and tools" principle is a reaction against. All that I remember about BTM/70 is that there were big binders of sample forms, and every step of the way, one had to photocopy the appropriate forms and fill them out. I do not recall any specific benefits.&lt;br /&gt;The life cycle of an BTM/70 project consists of eight (8) phases ranging from Systems Requirements to System Implementation. Coupled with BTM/70 is ET/70, a Project Control tool set that is used for project planning and tracking. ET/70 assists in milestone planning, helps establish project target dates, supports activity tracking, and detail time reporting of each staff member down to the task level, within each activity, of each phase of the project&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6678855-112633321124359456?l=agileworks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://agileworks.blogspot.com/feeds/112633321124359456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6678855&amp;postID=112633321124359456' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/112633321124359456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6678855/posts/default/112633321124359456'/><link rel='alternate' type='text/html' href='http://agileworks.blogspot.com/2005/09/feedback-from-client.html' title='Feedback from the Client'/><author><name>Shane Duan</name><uri>http://www.blogger.com/profile/18237393455554069484</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='28' src='http://bp1.blogger.com/_1AIWiix4RXQ/R4hPtxjMZoI/AAAAAAAAAPE/fkqB6qLvxeM/S220/avatar.jpg'/></author><thr:total>0</thr:total></entry></feed>
