<?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-4084458860381242516</id><updated>2011-12-21T01:48:28.178-08:00</updated><title type='text'>Putting the tea into team</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>35</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-5657394719556278202</id><published>2011-01-24T14:08:00.000-08:00</published><updated>2011-01-24T14:20:39.202-08:00</updated><title type='text'>Do what works for you</title><content type='html'>I've received literally no emails complaining that my &lt;a href="http://ivan.truemesh.com/archives/000519.html"&gt;"do the right thing" methodology&lt;/a&gt; is too prescriptive, so I've come up with a new methodology called "do what works for you" which I hope will work for those people who find the "do the right thing" methodology too prescriptive.&lt;br /&gt;&lt;br /&gt;What you do in this methodology is whatever works for you.&lt;br /&gt;&lt;br /&gt;Copyright © 2011 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-5657394719556278202?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/5657394719556278202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=5657394719556278202' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5657394719556278202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5657394719556278202'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2011/01/do-what-works-for-you.html' title='Do what works for you'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-5430566578842627670</id><published>2011-01-16T03:04:00.000-08:00</published><updated>2011-01-16T03:12:31.304-08:00</updated><title type='text'>SPA 2011</title><content type='html'>&lt;a href="http://www.spaconference.org/spa2011/index.php"&gt;My favourite conference (SPA)&lt;/a&gt; is open for &lt;a href="http://www.bcs.org/content/ConWebDoc/5910"&gt;registrations&lt;/a&gt; and &lt;a href="http://www.spaconference.org/spa2011/index.php?page=lead-a-session"&gt;session proposals&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This year I'm honoured to be conference co-chair with &lt;a href="http://www.exdriven.co.uk/"&gt;Mike Hill&lt;/a&gt;. The programme will be organised by &lt;a href="http://www.willemvandenende.com/"&gt;Willem Van Den Ende&lt;/a&gt; and &lt;a href="http://robbowley.net/"&gt;Rob Bowley&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Please &lt;a href="http://www.bcs.org/content/ConWebDoc/5910"&gt;book your place&lt;/a&gt;, or &lt;a href="http://www.spaconference.org/spa2011/index.php?page=lead-a-session"&gt;propose a session&lt;/a&gt; (do that real soon - you'll have some time to improve your session once it is submitted).&lt;br /&gt;&lt;br /&gt;Copyright © 2011 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-5430566578842627670?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/5430566578842627670/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=5430566578842627670' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5430566578842627670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5430566578842627670'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2011/01/spa-2011.html' title='SPA 2011'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-1883117237766119734</id><published>2010-09-18T01:35:00.000-07:00</published><updated>2010-09-18T02:10:51.112-07:00</updated><title type='text'>The plural of anecdote is not data</title><content type='html'>I've just finished reading "&lt;a href="http://www.amazon.co.uk/Bad-Science-Ben-Goldacre/dp/000728487X"&gt;Bad Science&lt;/a&gt;" and it made me think of how little science has been done about software development.&lt;br /&gt;&lt;br /&gt;The only two areas where there has been some research that I can think of &lt;span style="opacity:0.5;filter:alpha(opacity=50)"&gt;(off the top of my head - without doing any research about research) (and that seems very relevant to my day-to-day work)&lt;/span&gt; are about &lt;a href="http://en.wikipedia.org/wiki/Pair_programming"&gt;pair programming&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;test driven development&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;While I think it is commendable that people have done some research for these topics - it's just not enough (in particular, not by enough different groups or people).&lt;br /&gt;&lt;br /&gt;So - what good science is there about software development? Comments welcome.&lt;br /&gt;&lt;br /&gt;Copyright © 2010 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-1883117237766119734?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/1883117237766119734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=1883117237766119734' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/1883117237766119734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/1883117237766119734'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2010/09/plural-of-anecdote-is-not-data.html' title='The plural of anecdote is not data'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-6584717850609183444</id><published>2010-09-04T04:57:00.000-07:00</published><updated>2010-09-04T06:24:42.541-07:00</updated><title type='text'>IDE effecting code</title><content type='html'>I don't write Java code exactly the same as I used to. Some of the ways my code has changed are due to using an &lt;a href="http://www.jetbrains.com/idea/"&gt;excellent IDE&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;One of these I mention in a &lt;a href="http://puttingtheteaintoteam.blogspot.com/2009/12/three-heresies.html"&gt;previous article&lt;/a&gt; was about having fields public in some circumstances - I won't repeat the arguments here, I just want to mention that one reason I'd now make a field public when before I would have had a getter/setter is that it is trivial to convert a public field into a getter/setter when you need to (a refactoring called "encapsulate field"** in IDEA). (I still prefer not to have the internals of a class public whether accessed by fields or getters/setters though - &lt;a href="http://www.pragprog.com/articles/tell-dont-ask"&gt;tell don't ask&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;Another example is that now I only introduce an interface when it's really needed and not in anticipation of it being needed. Again, it's trivial to introduce the interface when it's needed using the "extract interface" refactoring of the IDE.&lt;br /&gt;&lt;br /&gt;I was chatting to &lt;a href="http://www.natpryce.com/"&gt;Nat Pryce&lt;/a&gt; about this and he was agreeing that using an &lt;a href="http://www.jetbrains.com/idea/"&gt;excellent IDE&lt;/a&gt; has also changed the way he writes Java. I hope he and others will add comments to mention other ways their programming style has changed as a result of better IDEs.&lt;br /&gt;&lt;br /&gt;I know for some people the idea of changing your programming style as a result of what a tool supports is heresy - but I think good development practice means using the tools and language so they work well together.&lt;br /&gt;&lt;br /&gt;The examples given above refer to Java development where the team owns all the code rather than when writing an API - I'm not addressing API design here.&lt;br /&gt;&lt;br /&gt;** BTW, I think calling the refactoring "encapsulate" is a bit of an exaggeration - really it is just replacing one form of non-encapsulation with another.&lt;br /&gt;&lt;br /&gt;Copyright © 2010 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-6584717850609183444?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/6584717850609183444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=6584717850609183444' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/6584717850609183444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/6584717850609183444'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2010/09/ide-effecting-code.html' title='IDE effecting code'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-7990898932939301262</id><published>2010-08-18T13:00:00.000-07:00</published><updated>2010-08-18T13:17:16.068-07:00</updated><title type='text'>miniSPA 2010 - Friday September 10th - BCS London</title><content type='html'>&lt;a href="http://www.exdriven.co.uk/"&gt;Mike Hill&lt;/a&gt; and I have been volunteered to co-chair the miniSPA conference.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.spaconference.org/"&gt;SPA&lt;/a&gt; is a fantastic conference - miniSPA is a condensed (and free!) version - it'll be great - all the places will go, so book now.&lt;br /&gt;&lt;br /&gt;Here's the announcement and &lt;a href="http://www.bcs-spa.org/minispa-2010.html"&gt;registration link&lt;/a&gt; (sorry the registration system is really horrible):&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Experience some of the most popular sessions from this year's BCS SPA conference, for free, at miniSPA2010 on Friday September 10th at BCS London (near Covent Garden).&lt;br /&gt;&lt;br /&gt;The miniSPA2010 one-day programme features five sessions, in two streams, that give an excellent guide to the variety and quality you'll find at every SPA conference.&lt;br /&gt;&lt;br /&gt;We hope that attending miniSPA will encourage you to submit a session proposal for SPA2011, which will be taking place from June 12-15 (also at BCS London).&lt;br /&gt;&lt;br /&gt;For more information visit &lt;a href="http://bcs-spa.org/minispa-2010.html"&gt;http://bcs-spa.org/minispa-2010.html&lt;/a&gt;. Booking is essential. Places are limited so reserve yours now.&lt;br /&gt;&lt;br /&gt;See &lt;a href="http://bcs-spa.org/"&gt;http://bcs-spa.org/&lt;/a&gt; for details of our programme of regular events.&lt;br /&gt;&lt;br /&gt;©2010 BCS SPA | 5 Southampton Street | London | WC2E 7HA&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Copyright © 2010 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-7990898932939301262?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/7990898932939301262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=7990898932939301262' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7990898932939301262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7990898932939301262'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2010/08/minispa-2010-friday-september-10th-bcs.html' title='miniSPA 2010 - Friday September 10th - BCS London'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-3405817412555255365</id><published>2010-06-19T02:17:00.001-07:00</published><updated>2010-08-01T09:47:50.012-07:00</updated><title type='text'>Don't just put your documentation in source control</title><content type='html'>In the &lt;a href="http://www.cs.ucl.ac.uk/teaching/syllabus/mscsse/gs04.htm"&gt;GS04&lt;/a&gt; course at &lt;a href="http://www.ucl.ac.uk/"&gt;UCL&lt;/a&gt; I told the students to put everything into &lt;a href="http://puttingtheteaintoteam.blogspot.com/2010/03/tools-and-environments-scm-and-ci.html"&gt;source control&lt;/a&gt;; not just source code but also things like documentation and configuration files.&lt;br /&gt;&lt;br /&gt;That's all very well, but my current project at work has made me realise that you can do even better. You should not just put your documentation in source control, you should serve it from source control.&lt;br /&gt;&lt;br /&gt;On my current project we have all our documentation served directly from our &lt;a href="http://subversion.apache.org/"&gt;subversion&lt;/a&gt; repository, mostly as html.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;What about Wikis?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I used to be a big fan of having a project &lt;a href="http://en.wikipedia.org/wiki/Wiki"&gt;wiki&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A wiki can be great but:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;they do have a tendency to get out of date easily&lt;/li&gt;&lt;li&gt;they can accumulate lots of garbage&lt;/li&gt;&lt;li&gt;they can be difficult to version control well (difficult to keep in sync with the project's source code repository - I know there are things like &lt;a href="http://trac.edgewall.org/"&gt;Trac&lt;/a&gt; but in a lot of companies you don't get to choose what systems you use)&lt;/li&gt;&lt;li&gt;if the project is abandoned for a long time, the chances are that the wiki might disappear (I've seen it a few times - moving to another wiki system and not migrating old pages) but the source code repository will be around for a long time (and if it isn't then you're screwed anyway).&lt;/li&gt;&lt;/ol&gt;Wikis still have their place - when collaboration with lots of people is needed, but for developer written documentation I'm happier to have it in the same source control system as the code it refers to.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Taking my own advice&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I've updated my semi-abandoned project &lt;a href="http://build-o-matic.svn.sourceforge.net/viewvc/build-o-matic/trunk/website/index.html"&gt;build-o-matic&lt;/a&gt;, so its web site is now served directly from its source code repository. It's now &lt;span style="font-style: italic;"&gt;so &lt;/span&gt;much easier to update the web site (just edit and commit) that I might even get the web site up-to-date.&lt;br /&gt;&lt;br /&gt;But there again, the &lt;a href="http://www.fifa.com/index.html"&gt;World Cup&lt;/a&gt; is on TV today ...&lt;br /&gt;&lt;br /&gt;Copyright © 2010 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-3405817412555255365?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/3405817412555255365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=3405817412555255365' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3405817412555255365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3405817412555255365'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2010/06/dont-just-put-your-documentation-in.html' title='Don&apos;t just put your documentation in source control'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-8864642694870510346</id><published>2010-06-10T11:49:00.000-07:00</published><updated>2010-06-10T11:57:00.918-07:00</updated><title type='text'>throw null</title><content type='html'>My colleagues told me of some code they came across which included the statement: "throw null".&lt;br /&gt;&lt;br /&gt;I'd never seen that before - I didn't know what it would do or even if it was valid.&lt;br /&gt;&lt;br /&gt;I'll let you think about it. Have a go if you want to check your answer:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Surprise {&lt;br /&gt;    public static void main(String[] args) {&lt;br /&gt;        throw null;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Copyright © 2010 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-8864642694870510346?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/8864642694870510346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=8864642694870510346' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/8864642694870510346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/8864642694870510346'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2010/06/throw-null.html' title='throw null'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-2318171748109819141</id><published>2010-03-07T10:50:00.000-08:00</published><updated>2010-03-07T10:57:05.988-08:00</updated><title type='text'>Tools and Environments - SCM and CI</title><content type='html'>When I taught source control and continuous integration in 2007 (for the &lt;a href="http://www.cs.ucl.ac.uk/teaching/syllabus/mscsse/gs04.htm"&gt;GS04&lt;/a&gt; course at &lt;a href="http://www.ucl.ac.uk/"&gt;UCL&lt;/a&gt;) I used &lt;a href="http://subversion.apache.org/"&gt;Subversion&lt;/a&gt; for the source control lab and &lt;a href="http://build-o-matic.sourceforge.net/"&gt;build-o-matic&lt;/a&gt; for the continuous integration lab.&lt;br /&gt;&lt;br /&gt;In the labs this year, I'll be using &lt;a href="http://mercurial.selenic.com/"&gt;Mercurial&lt;/a&gt; instead of Subversion, and &lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt; instead of build-o-matic.&lt;br /&gt;&lt;br /&gt;What would you choose for teaching source control and continuous integration (and for bonus marks, why)?&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-2318171748109819141?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/2318171748109819141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=2318171748109819141' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/2318171748109819141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/2318171748109819141'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2010/03/tools-and-environments-scm-and-ci.html' title='Tools and Environments - SCM and CI'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-7796343587713190233</id><published>2010-02-27T03:39:00.000-08:00</published><updated>2010-02-27T04:06:24.924-08:00</updated><title type='text'>Tools and Environments</title><content type='html'>&lt;a href="http://www.m3p.co.uk/"&gt;Steve Freeman&lt;/a&gt; and I are teaching a course at &lt;a href="http://www.ucl.ac.uk/"&gt;UCL&lt;/a&gt; called "Tools and Environments".&lt;br /&gt;&lt;span style="font-style: italic;"&gt;The course we wish we’d had in college, only we didn’t know it at the time.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We cover subjects such as source control systems, automated builds, automated testing and continuous integration.&lt;br /&gt;&lt;br /&gt;In preparing for the course, I've been reminded of how few books there are which we can use as a "course text". There are plenty of books for specific tools (e.g. Ant) once you know that you need those tools, but few books which explain the sorts of things that you need for real software development projects, and why you need them.&lt;br /&gt;&lt;br /&gt;The book we're using for our "course text" is &lt;a href="http://www.amazon.co.uk/Practical-Development-Environments-Matthew-Doar/dp/0596007965"&gt;Practical Development Environments&lt;/a&gt; (and we'll also be recommending &lt;a href="http://www.amazon.co.uk/Continuous-Integration-Improving-Software-Signature/dp/0321336380"&gt;Continuous Integration&lt;/a&gt; as that also covers much of the material of the course).&lt;br /&gt;&lt;br /&gt;If you have other recommendations please add a comment!&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-7796343587713190233?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/7796343587713190233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=7796343587713190233' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7796343587713190233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7796343587713190233'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2010/02/tools-and-environments.html' title='Tools and Environments'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-7704648766552369837</id><published>2009-12-05T08:50:00.000-08:00</published><updated>2009-12-05T10:55:08.791-08:00</updated><title type='text'>Three heresies</title><content type='html'>&lt;div&gt;I encourage people to think for themselves rather than following cargo cults. You might or might not agree with the three heresies I've written about here, but do at least think about them.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Public fields&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;In Java code, instead of having a public getter and public setter for a field, why not just make the field public? It's much simpler and less code. If you later need a getter and setter for some reason you can always refactor to that (and many IDEs will give you help doing it). There is a comment by Richard Gomes at the end of this &lt;a href="http://puttingtheteaintoteam.blogspot.com/2008/10/is-that-pojo-or-nojo.html"&gt;previous article&lt;/a&gt; on the subject of public fields for data objects. I think public fields make most sense for NOJOs (data objects) (in the rare case where a NOJO is useful - not very often) but maybe it would sometimes make sense for  other sorts of classes too?&lt;br /&gt;&lt;br /&gt;Note that having public access to a field is not what I'm trying to encourage. The point I'm making is that if you &lt;span style="font-style: italic;"&gt;do &lt;/span&gt;have public access to a field then it doesn't matter much whether it is by getter/setter or making the field public, so you might as well use a public field as it is simpler. (But please, &lt;a href="http://www.pragprog.com/articles/tell-dont-ask"&gt;tell don't ask&lt;/a&gt; instead.)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Magic values instead of constants (in build files)&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Instead of always factoring out magic values as properties in your build file, consider just using the magic value where it makes sense. For example, maybe instead of "${src}" just use "src" (and get rid of the property) - this was suggested by &lt;a href="http://blog.jeffreyfredrick.com/"&gt;Jeffrey Fredrick&lt;/a&gt; at &lt;a href="http://citconf.com/paris2009/"&gt;CITCON Paris 2009&lt;/a&gt;. I think there is a lot of merit in this approach. What are the chances that you'd be able to just modify the value of the "src" property and everything would still work? Probably quite low - you'd probably do a text file search for "src" anyway. What are the chances that you'll want to change it anyway? I think it's worth thinking about whether it's better or worse to factor out constants in some cases.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Make the CI build fail fast rather than run all the tests&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Rather than running all the tests in your CI build, how about have the build fail as soon as any test fails? That way, a failing build uses less of your build farm's capacity. If your build farm capacity is limited, then this approach may result in getting a passing build sooner (as when the fix is committed there may be a build agent available for running the build with that commit sooner because it's time isn't being taken running a build which will eventually fail anyway). I think it's often more important to know which commit broke the build than which tests failed in order to know both who should fix the build and what caused the build breakage. This approach might not be so good if you have a &lt;a href="http://citconf.com/wiki/index.php?title=FlickeringBuilds"&gt;flickering build&lt;/a&gt; (i.e. randomly failing tests) - however, making the build reliable can be achieved and is worthwhile anyway.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;More heresies to follow&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have other heresies to write about. Please suggest your own in the comments.&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-7704648766552369837?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/7704648766552369837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=7704648766552369837' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7704648766552369837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7704648766552369837'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/12/three-heresies.html' title='Three heresies'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-3356850179376445063</id><published>2009-11-24T23:07:00.000-08:00</published><updated>2009-11-24T23:36:03.928-08:00</updated><title type='text'>Java Enums with constant-specific methods</title><content type='html'>One of my colleagues introduced me to this handy language feature of Java 1.5 and I wanted to write an article about it because I hadn't seen this before.&lt;br /&gt;&lt;br /&gt;Using google reveals that it is already well documented if you RTFM, but I will repeat it here because talking to other Java developers indicates that it isn't as well known as it deserves to be. Here's a slightly reworded extract from the first hit on google or bing for "&lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html"&gt;java enum&lt;/a&gt;":&lt;br /&gt;&lt;br /&gt;You can declare abstract methods in an enum and override them with a concrete method in each constant. Such methods are known as constant-specific methods. Here is an example using this technique:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public enum Operation {&lt;br /&gt;  PLUS   { double eval(double x, double y) { return x + y; } },&lt;br /&gt;  MINUS  { double eval(double x, double y) { return x - y; } },&lt;br /&gt;  TIMES  { double eval(double x, double y) { return x * y; } },&lt;br /&gt;  DIVIDE { double eval(double x, double y) { return x / y; } };&lt;br /&gt;&lt;br /&gt;  // Do arithmetic op represented by this constant&lt;br /&gt;  abstract double eval(double x, double y);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-3356850179376445063?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/3356850179376445063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=3356850179376445063' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3356850179376445063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3356850179376445063'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/11/java-enums-with-constant-specific.html' title='Java Enums with constant-specific methods'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-5301377930560901414</id><published>2009-11-24T06:54:00.000-08:00</published><updated>2009-11-24T07:52:10.670-08:00</updated><title type='text'>New version of Jester released</title><content type='html'>It's been a while since I last updated &lt;a href="http://jester.sourceforge.net/"&gt;Jester&lt;/a&gt; (a mutation testing tool).&lt;br /&gt;&lt;br /&gt;Today I released a new version of Jester - not much changed - but hopefully a bit easier to get it to work, based on my &lt;a href="http://ivan.truemesh.com/archives/000725.html"&gt;experiences of trying to use Jester&lt;/a&gt; when I haven't tried for a while.&lt;br /&gt;&lt;br /&gt;It now doesn't read configuration files from the classpath - instead you specify the relevant files on the command line.&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-5301377930560901414?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/5301377930560901414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=5301377930560901414' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5301377930560901414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5301377930560901414'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/11/new-version-of-jester-released.html' title='New version of Jester released'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-8137087250743733647</id><published>2009-11-08T05:49:00.000-08:00</published><updated>2009-11-08T06:15:42.686-08:00</updated><title type='text'>XpDay London, 7th &amp; 8th December 2009</title><content type='html'>It's &lt;a href="http://www.xpday.org/"&gt;XpDay&lt;/a&gt; soon - &lt;a href="http://booking.xpday.org/registration.php"&gt;book your place now&lt;/a&gt;. The &lt;a href="http://www.xpday.org/node/208"&gt;Keynotes&lt;/a&gt; look particularly good this year.&lt;br /&gt;&lt;br /&gt;On Monday there's an experience report that looks very interesting "&lt;a href="http://xpday-london.editme.com/WhenAgileMightNotBeTheBestSolution"&gt;When Agile Might Not Be The Best Solution&lt;/a&gt;" - it's good to see this sort of experience report on the programme because there's probably more to learn from it than one which goes something like "we did XP and it worked".&lt;br /&gt;&lt;br /&gt;There are lots of other &lt;a href="http://www.xpday.org/programme"&gt;interesting looking sessions&lt;/a&gt; too - plus lots of open space sessions which can be excellent.&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-8137087250743733647?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/8137087250743733647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=8137087250743733647' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/8137087250743733647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/8137087250743733647'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/11/xpday-london-7th-8th-december-2009.html' title='XpDay London, 7th &amp; 8th December 2009'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-5470784522054495517</id><published>2009-10-31T03:14:00.000-07:00</published><updated>2009-10-31T06:20:10.607-07:00</updated><title type='text'>Pair Programming interviews/auditions</title><content type='html'>I have done a lot of pair programming interviews for my client. I enjoy doing them and I think they are extremely valuable.&lt;br /&gt;&lt;br /&gt;Hiring is probably the most important thing to get right, and I think that pair programming interviews (or "auditions" as some like to call them) are usually &lt;a href="http://peripateticaxiom.blogspot.com/2008/09/programming-interview-questions.html"&gt;the best way to interview&lt;/a&gt; developers.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Setting up a pair programming interview&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For interviewing Java developers, I have a machine set up with a choice of &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ IDEA&lt;/a&gt; and &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; with an empty workspace. I think it is important to try to make the candidate as comfortable as possible with the development environment so that it isn't a distraction. If you work with Apple Macs, also provide Windows (and maybe Linux) machines for candidates who aren't familiar with Macs because otherwise the difference in IDE shortcuts gets in the way and the idea of a pair programming interview isn't to see how familiar the candidate is with a particular OS.&lt;br /&gt;&lt;br /&gt;I allow one hour for these interviews - I have found that is long enough to get a good idea about the suitability of a candidate.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Choosing a problem&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One of the most surprising things is how small the problem has to be in order to be achievable in one hour. Developers (including myself) are often very optimistic about how quickly they can program a solution to a simple problem. I would urge you to try out the problem you want to use for a pair programming interview with a trusted colleague, before using it with a candidate, to find out whether it is realistic. To give you an idea of the size of problem you need, I used to use the problem described in &lt;a href="http://puttingtheteaintoteam.blogspot.com/2009/02/two-styles.html"&gt;this article&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I know of another team at my client who provide a small code base pre-prepared for the interview which includes a bug which the candidate has to find. I think this is a great idea. Choose a problem which is realistic for the sort of code that the candidate will be writing (or the sort of work they will be doing, e.g. debugging legacy code) in the job you are hiring for. There is no point testing for whether a candidate can write &lt;a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/WeakHashMap.html"&gt;WeakHashMap &lt;/a&gt;from scratch if you are hiring for a typical enterprise IT project.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;What &lt;/span&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;pair programming interviews demonstrate&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Pair programming interviews aren't a silver bullet for recruiting developers - they are good at determining some qualities of a candidate but not all. In particular I think they are more valuable in demonstrating programming style and personal interaction rather than problem solving. However, in typical enterprise IT projects, more problems are caused by over complex solutions to simple problems, or by solving the wrong problem, than having problems that are unique and difficult and require a brand new algorithm.&lt;br /&gt;&lt;br /&gt;Sometimes it is good to use a problem which has some potential for ambiguities in the details of what is being asked for. This is a very good way to see whether a candidate asks for clarification or just makes assumptions which aren't justified. In enterprise IT systems, making assumptions about the desired behaviour of a system can cause a lot of rework and bugs so I look for candidates who demonstrate that they are thinking through possible ambiguities and who pro-actively ask for clarifications about the problem.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Being realistic&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I make it very clear to candidates that I am looking for production quality, simple code rather than for them to show off all the language features they know. The problems that I choose are simple enough that I'm not interested in just getting a solution. I am looking for code that I would be happy working with. My boss, Pippa Newbold, has a very good rule of thumb. "At the very least, don't hire someone who will make the code base worse". It seems obvious and yet at other companies I have sometimes observed panic hiring just to make up the numbers where this rule would have saved lots of rework and bugs.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Giving something back&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I try to teach the candidates something new in a pair programming interview where possible. Often this is something like an IDE shortcut but is occasionally a language feature or a "&lt;a href="http://ivan.truemesh.com/archives/cat_programming_in_the_small.html"&gt;programming in the small&lt;/a&gt;" style discussion. I like candidates to get something back for giving up their time to come in for an interview, and a pair programming interview can be very daunting for candidates not used to pair programming.&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Does it work?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;As far as I can tell, all candidates that I have "passed" using a pair programming interview have turned out to be worth hiring.&lt;br /&gt;&lt;br /&gt;However, that doesn't include those candidates that I've "passed" who didn't take the job and I don't know whether any of those candidates that I've "failed" would have been good either.&lt;br /&gt;&lt;br /&gt;My suspicion is that it is a technique which is slightly more prone to "failing" good candidates than hiring poor candidates, but that really is just a gut feeling. If anyone knows any studies on pair programming interviews I'd be very interested to hear more.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Where it probably doesn't work&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I guess that interviewing people for research or work which requires solving deep and difficult problems probably requires a different approach. Also, for hiring people with limited programming experience who you want to train up it might not be suitable.&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-5470784522054495517?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/5470784522054495517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=5470784522054495517' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5470784522054495517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5470784522054495517'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/10/pair-programming-interviewsauditions.html' title='Pair Programming interviews/auditions'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-8349682780380242076</id><published>2009-07-09T13:36:00.000-07:00</published><updated>2009-07-09T14:15:05.780-07:00</updated><title type='text'>Cleaner code</title><content type='html'>I recommend the book "&lt;a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882"&gt;Clean Code&lt;/a&gt;" - &lt;a href="http://puttingtheteaintoteam.blogspot.com/2008/11/in-my-previous-article-i-mentioned-book.html"&gt;I completely agree with its philosophy&lt;/a&gt; and have written a few articles of my own about "&lt;a href="http://ivan.truemesh.com/archives/cat_programming_in_the_small.html"&gt;programming in the small&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.exdriven.co.uk/"&gt;Mike Hill&lt;/a&gt; and I presented a session on "programming in the small" at the "&lt;a href="http://parlezuml.com/softwarecraftsmanship/"&gt;Software Craftsmanship&lt;/a&gt;" conference 2009 in London and at &lt;a href="http://qconlondon.com/"&gt;QCON London&lt;/a&gt; 2009 - and one of or examples was taken from "Clean Code".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Clean Code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One of the examples in "Clean Code" is some code for parsing command line arguments, written in Java by Bob Martin. It is shown as an example of code which has already been made clean. There is &lt;a href="http://www.objectmentor.com/resources/articles/Clean_Code_Args.pdf"&gt;an article&lt;/a&gt; (separate from the book) by Bob Martin about the code we use for this example. The source code is available from github:&lt;br /&gt;&lt;br /&gt;git clone git://github.com/unclebob/javaargs.git&lt;br /&gt;&lt;br /&gt;Mike and I chose this code because we wanted to take code which was already quite clean and show how even good code can sometimes be cleaned up even more - we wanted to push the cleanliness as far as possible in the session.&lt;br /&gt;&lt;br /&gt;Just looking at the "Args" class only, this method seemed the one most wanting some further work (sorry, formatting is ugly - reformatted to fit blog page width):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private void parseSchemaElement(String element)&lt;br /&gt;                           throws ArgsException {&lt;br /&gt;   char elementId = element.charAt(0);&lt;br /&gt;   String elementTail = element.substring(1);&lt;br /&gt;   validateSchemaElementId(elementId);&lt;br /&gt;   if (elementTail.length() == 0)&lt;br /&gt;       marshalers.put(elementId,&lt;br /&gt;                      new BooleanArgumentMarshaler());&lt;br /&gt;   else if (elementTail.equals("*"))&lt;br /&gt;       marshalers.put(elementId,&lt;br /&gt;                      new StringArgumentMarshaler());&lt;br /&gt;   else if (elementTail.equals("#"))&lt;br /&gt;       marshalers.put(elementId,&lt;br /&gt;                      new IntegerArgumentMarshaler());&lt;br /&gt;   else if (elementTail.equals("##"))&lt;br /&gt;       marshalers.put(elementId,&lt;br /&gt;                      new DoubleArgumentMarshaler());&lt;br /&gt;   else if (elementTail.equals("[*]"))&lt;br /&gt;       marshalers.put(elementId,&lt;br /&gt;                      new StringArrayArgumentMarshaler());&lt;br /&gt;   else&lt;br /&gt;       throw new ArgsException(INVALID_ARGUMENT_FORMAT,&lt;br /&gt;                               elementId, elementTail);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So - what could be better? What struck Mike and I was the duplication of "&lt;span style="font-family:courier new;"&gt;marshalers.put(elementId, new XXX());&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;To remove this duplication, first extract a variable called argumentMarshaler of type ArgumentMarshaler in each of the branches, then move the expression "&lt;span style="font-family:courier new;"&gt;marshalers.put(elementId, argumentMarshaler);&lt;/span&gt;" outside of the if statement, and the declaration of the variable "argumentMarshaler" before the if statement. You end up with:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private void parseSchemaElement(String element)&lt;br /&gt;                           throws ArgsException {&lt;br /&gt;   char elementId = element.charAt(0);&lt;br /&gt;   String elementTail = element.substring(1);&lt;br /&gt;   validateSchemaElementId(elementId);&lt;br /&gt;   ArgumentMarshaler argumentMarshaler;&lt;br /&gt;   if (elementTail.length() == 0) {&lt;br /&gt;       argumentMarshaler =&lt;br /&gt;                  new BooleanArgumentMarshaler();&lt;br /&gt;   } else if (elementTail.equals("*")) {&lt;br /&gt;       argumentMarshaler =&lt;br /&gt;                  new StringArgumentMarshaler();&lt;br /&gt;   } else if (elementTail.equals("#")) {&lt;br /&gt;       argumentMarshaler =&lt;br /&gt;                  new IntegerArgumentMarshaler();&lt;br /&gt;   } else if (elementTail.equals("##")) {&lt;br /&gt;       argumentMarshaler =&lt;br /&gt;                  new DoubleArgumentMarshaler();&lt;br /&gt;   } else if (elementTail.equals("[*]")) {&lt;br /&gt;       argumentMarshaler =&lt;br /&gt;                  new StringArrayArgumentMarshaler();&lt;br /&gt;   } else&lt;br /&gt;       throw new ArgsException(INVALID_ARGUMENT_FORMAT,&lt;br /&gt;                               elementId, elementTail);&lt;br /&gt;   marshalers.put(elementId, argumentMarshaler);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now it's clearer that this method is doing too many things - one of those things being to find the relevant marshaler. We can extract a method for finding the marshaler and, having been extracted can improve it further by removing unnecessary structured programmingness, ending up with:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private void parseSchemaElement(String element)&lt;br /&gt;                         throws ArgsException {&lt;br /&gt;   char elementId = element.charAt(0);&lt;br /&gt;   String elementTail = element.substring(1);&lt;br /&gt;   validateSchemaElementId(elementId);&lt;br /&gt;   marshalers.put(elementId,&lt;br /&gt;        findAppropriateArgumentMarshaler(elementId,&lt;br /&gt;                                         elementTail));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private ArgumentMarshaler findAppropriateArgumentMarshaler(&lt;br /&gt;                    char elementId, String elementTail)&lt;br /&gt;                                   throws ArgsException {&lt;br /&gt;   if (elementTail.length() == 0) {&lt;br /&gt;       return new BooleanArgumentMarshaler();&lt;br /&gt;   } else if (elementTail.equals("*")) {&lt;br /&gt;       return new StringArgumentMarshaler();&lt;br /&gt;   } else if (elementTail.equals("#")) {&lt;br /&gt;       return new IntegerArgumentMarshaler();&lt;br /&gt;   } else if (elementTail.equals("##")) {&lt;br /&gt;       return new DoubleArgumentMarshaler();&lt;br /&gt;   } else if (elementTail.equals("[*]")) {&lt;br /&gt;       return new StringArrayArgumentMarshaler();&lt;br /&gt;   } else&lt;br /&gt;       throw new ArgsException(INVALID_ARGUMENT_FORMAT,&lt;br /&gt;                               elementId, elementTail);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Notice that "elementId" is only used for the exception to throw if an appropriate ArgumentMarshaler cannot be found. Further investigation shows that actually this parameter isn't used in ArgsException for an "INVALID_ARGUMENT_FORMAT" and we can just delete this argument (and hence the "elementId" parameter of "findAppropriateArgumentMarshaler") with no change to the behaviour of the code!&lt;br /&gt;&lt;br /&gt;There is more that can be done with the Args class - but that is beyond the scope of this article.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I hope this has shown that even clean code can be made cleaner - without having to do anything too clever or drastic. It's often easier to see such opportunities in other people's code or code you haven't seen for a while - even the best programmers can miss opportunities for making code simpler.&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-8349682780380242076?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/8349682780380242076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=8349682780380242076' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/8349682780380242076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/8349682780380242076'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/07/cleaner-code.html' title='Cleaner code'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-4863698416913131122</id><published>2009-06-20T07:54:00.000-07:00</published><updated>2009-06-20T08:15:10.889-07:00</updated><title type='text'>Project management lessons - commitment</title><content type='html'>Have you ever heard (or said) something like "you've got to work [long hours/weekends] because the customer has been promised [some system/feature] by [some date]"?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Commitments can be made but not assigned&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;People only feel committed to things they have committed to themselves. Telling someone that they have to work long hours/weekends because of a commitment someone else has made can lead to demotivation and resentment. Productivity is very likely to suffer (quality decreasing, more rework due to mistakes, more stupid things done due to rushing or tiredness). Seeing that the work isn't being completed quickly enough, bad managers think that it just requires even more hours to be put in (they try to impose "more commitment" and concentrate on the inputs rather than the outputs). This is the recipe for a &lt;a href="http://en.wikipedia.org/wiki/Death_march_%28software_development%29"&gt;"death march" project&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Estimates are not commitments&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As a project manager, you have to understand the &lt;a href="http://ivan.truemesh.com/archives/000644.html"&gt;difference between an estimate and a quote&lt;/a&gt;. An estimate is not a commitment. As a project manager, if you make a commitment that something will be done by a certain date then do not rely on being able to just use estimates directly - you need to apply some project management techniques. One technique that I have found works well, as mentioned in my &lt;a href="http://puttingtheteaintoteam.blogspot.com/2009/04/project-management-lessons.html"&gt;previous article&lt;/a&gt; is "extreme planning".&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Commitment can work wonders&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When someone really feels committed to something, then they will be motivated and focused. Software developers will often work harder and more effectively on their pet open source project than they do at work due to this motivation. This sort of commitment cannot be forced onto someone. There are lots of ways to ensure it doesn't happen (sadly common) and a few things you can do to provide an environment in which it might happen - and hence see massive improvements in productivity and quality as a result.&lt;br /&gt;&lt;br /&gt;One factor is the level of technical autonomy. Many large companies have standards which are intended to reduce costs (for various reasons I won't go into). Unfortunately, I think in many cases these standards tend to reduce teams' technical autonomy, which reduces motivation, having a larger negative effect on productivity (hence cost) than the savings made by the standardization. I'm thinking of things like (for example) being told you have to use Wholly Pointless Server when some free open source app server would be a better choice.&lt;br /&gt;&lt;br /&gt;Another factor which I think is very important is how directly developers work with their customers. A lot of developers (and certainly the ones I like working with) like to do things which are useful and appreciated by the users of their software. Sometimes the way teams are set up there is a separation between developers and customers - often a business analyst who understands the business and is more available than the real customer(s). This does have benefits when a developer wants a question answered straight away (but the customer isn't available), because otherwise the developer would be blocked or have to context switch onto another area of work. However, I think the best arrangement (not always possible) is when the real customer is available all the time and the developers talk directly to them. The worst situation is when only the project manager or business analyst talks to the customer and approaches the developers with an attitude of demanding features rather than working collaboratively for the best solution.&lt;br /&gt;&lt;br /&gt;There are lots of other factors involved in motivation - I might write more in a future article - if I can be bothered. :-)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Bike ride commitment&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As an example of commitment - I said I'd do the &lt;a href="http://www.nas.org.uk/nas/jsp/polopoly.jsp?d=1970"&gt;London to Aachen bike ride&lt;/a&gt; and people &lt;a href="http://www.justgiving.com/ivanrmoore/"&gt;sponsored me&lt;/a&gt; to do it (many thanks), so I felt a commitment to do it. If I hadn't felt any commitment then I wouldn't have done it because, frankly, it wasn't much fun. Here's a quick summary of how it turned out:&lt;br /&gt;&lt;br /&gt;Day 1 - Gatwick to Dover/Dunkerque (85 miles cycling) - it wasn't too bad - a bit of drizzle, nice scenery and the cycling was not too tough. (We then got a ferry to Dunkerque - the staff at &lt;a href="http://www.norfolkline.com/ferry/"&gt;Norfolk line ferries&lt;/a&gt; were great, putting on a fantastic meal, and a tour of the bridge, specially for us).&lt;br /&gt;&lt;br /&gt;Day 2 - Dunkerque to Waterloo (139 miles) - we had an early start (breakfast at 6:30am local time, i.e. 5:30am UK time) - in order to do 70 miles before lunch - the roads were totally flat but it was into a headwind the whole way - it was &lt;span style="font-style: italic;"&gt;brutal&lt;/span&gt;. Some participants skipped the afternoon cycling and got a minivan to the hotel straight after lunch. Immediately before lunch I felt like going in the van too, but after some food felt much better and thought I'd try to keep going. The afternoon turned out to be much better - it was a bit hilly but much less windy. At around 100 miles for the day, 3 other particpants dropped out and got in the support van. At around 120 miles for the day I was knackered - but just about managed to finish the day's ride - going really slowly for the last 20 miles.&lt;br /&gt;&lt;br /&gt;Day 3 - Waterloo to Aachen (106 miles) - I was knackered from the day before - so I took it very easy, along with some of the others who had struggled to complete the previous day's ride. There were some cobbled roads, which on a race bike are very scary. Near the end of the day, going up a long climb (which features in the pro cycling "&lt;a href="http://en.wikipedia.org/wiki/Amstel_Gold_Race"&gt;Amstel Gold&lt;/a&gt;" race), we cycled through a thunder storm - we had hail, torrential rain (consequently very bad visibility), thunderbolts and lightning (very very frightening).&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-4863698416913131122?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/4863698416913131122/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=4863698416913131122' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/4863698416913131122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/4863698416913131122'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/06/project-management-lessons-commitment.html' title='Project management lessons - commitment'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-5550449746997968265</id><published>2009-05-17T06:29:00.000-07:00</published><updated>2009-05-17T06:42:04.233-07:00</updated><title type='text'>Signs</title><content type='html'>Unfortunately, I won't be going to &lt;a href="http://www2.xp2009.org/xp2009/"&gt;XP 2009&lt;/a&gt; - I'm sure it'll be great - enjoy it if you're going.&lt;br /&gt;&lt;br /&gt;While training for the &lt;a href="http://www.nas.org.uk/nas/jsp/polopoly.jsp?d=1970"&gt;London to Aachen bike ride&lt;/a&gt; (&lt;a href="http://www.justgiving.com/ivanrmoore"&gt;sponsor me&lt;/a&gt;) I regularly cycle past a couple of signs that somehow make me think of the XP conferences:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bWojgvr6MtU/ShAS4JfgdZI/AAAAAAAAAA8/jzrhLh04j0c/s1600-h/kent.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 240px; height: 320px;" src="http://3.bp.blogspot.com/_bWojgvr6MtU/ShAS4JfgdZI/AAAAAAAAAA8/jzrhLh04j0c/s320/kent.jpg" alt="Welcome to Kent" id="BLOGGER_PHOTO_ID_5336786314264081810" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_bWojgvr6MtU/ShATAM7gl4I/AAAAAAAAABE/WxoVrgwueKY/s1600-h/beck.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_bWojgvr6MtU/ShATAM7gl4I/AAAAAAAAABE/WxoVrgwueKY/s320/beck.jpg" alt="Beck Way" id="BLOGGER_PHOTO_ID_5336786452625790850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-5550449746997968265?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/5550449746997968265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=5550449746997968265' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5550449746997968265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5550449746997968265'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/05/signs.html' title='Signs'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_bWojgvr6MtU/ShAS4JfgdZI/AAAAAAAAAA8/jzrhLh04j0c/s72-c/kent.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-1494334187029798617</id><published>2009-04-26T05:25:00.000-07:00</published><updated>2009-04-26T05:40:39.003-07:00</updated><title type='text'>Project management lessons</title><content type='html'>I signed up for the &lt;a href="http://www.autism.org.uk/"&gt;National Autistic Society's&lt;/a&gt; &lt;a href="http://www.nas.org.uk/nas/jsp/polopoly.jsp?d=1970"&gt;London to Aachen bike ride&lt;/a&gt;. When I signed up it was 3 days, with the longest day being the second at about 100 miles (it was noted that this event hadn't been run before so the itinerary might not be 100% accurate).&lt;br /&gt;&lt;br /&gt;A few weeks later, I got an update on the itinerary - I was told that the organizer had done a recce (reconnaissance) of the route and the second day would now be 120 miles (last day longer too but not too bad).&lt;br /&gt;&lt;br /&gt;Just over a week ago, I got another update on the itinerary; actually the second day will be 137 miles (still not shown on the web page though!). To put that in perspective - that's only 4km less than the longest stage of the Tour-de-France - ouch.&lt;br /&gt;&lt;br /&gt;Therefore, of course, you should &lt;a href="http://www.justgiving.com/ivanrmoore"&gt;sponsor me&lt;/a&gt;. Also it gives me a good example of the sort of thing that happens with software projects very frequently; so here are some relevant lessons using this as an example.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;How to handle estimation&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Most people are rubbish at estimating - not only software developers about code, but lots of people about lots of other things too. The three most obvious reactions to that are (a) get better at estimating (b) take bad estimating into account (c) &lt;a href="http://blog.robbowley.net/2009/04/07/output-from-dealing-with-the-estimation-fallacy-session-spa2009/"&gt;don't estimate&lt;/a&gt; (or at least, not quite like most people do). I have found "extreme planning" (see &lt;a href="http://www.amazon.co.uk/Planning-Extreme-Programming-Tom-DeMarco/dp/0201710919"&gt;Planning Extreme Programming&lt;/a&gt; and &lt;a href="http://www.amazon.co.uk/Agile-Estimating-Planning-Robert-Martin/dp/0131479415"&gt;Agile Estimating and Planning&lt;/a&gt;) to work very well - however it is only really relevant to an incremental project. Quite literally, YMMV!&lt;br /&gt;&lt;br /&gt;For a one off event like the bike ride then there's not much I can do for this event (as consumer of the estimates). However, I will treat future event descriptions as being 40% inaccurate if they haven't been run before (i.e. using "yesterday's weather" in "extreme planning" style).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Admit when you have screwed up and don't know the answers&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first change to the itinerary was not entirely unexpected - I knew the route hadn't been done before - my expectations had been set that this was an estimate.&lt;br /&gt;&lt;br /&gt;The second change was a nasty surprise. There are two lessons here. When giving an estimate do not give it a level of confidence that it doesn't merit. If the first change to the mileage had said "and we still aren't quite sure" then the second change would not have been so unexpected. The second lesson is that if you have screwed up an estimate, then be extra generous with the re-estimate. If the first changed estimate had been 130 or 140 then 137 wouldn't have seemed so bad. If the second re-estimate had turned out to be 125 I wouldn't have been so bothered about it dropping from 130 or 140.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Mitigating risk&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If as a project manager you find out that something is going wrong (e.g. the first re-estimate of the itinerary) then do something to reduce the risk of that going even more wrong. In my case, I increased the amount of training I've been doing (hence I've been writing fewer blog articles because I'm knackered at the weekends!).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Some things you just can't predict - but maybe everything will work out OK anyway&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, my bike has developed a fault with the gears which may make it financially non-viable to repair so I may have to get a new bike - but given the new increased mileage that may be worthwhile even if my current bike can be fixed.&lt;br /&gt;&lt;br /&gt;I'm disappointed that the event doesn't appear as well prepared as the &lt;a href="http://ivan.truemesh.com/archives/000692.html"&gt;London to Paris bike ride&lt;/a&gt; that I did in 2007 and that I haven't raised as much money (yet) as in 2007, but &lt;a href="http://www.justgiving.com/ivanrmoore"&gt;you can help with that&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-1494334187029798617?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/1494334187029798617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=1494334187029798617' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/1494334187029798617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/1494334187029798617'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/04/project-management-lessons.html' title='Project management lessons'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-4268303711896862036</id><published>2009-03-08T06:44:00.000-07:00</published><updated>2009-03-08T07:14:54.619-07:00</updated><title type='text'>Save Bletchley Park - the birthplace of computing!</title><content type='html'>You've heard of &lt;a href="http://en.wikipedia.org/wiki/Alan_Turing"&gt;Alan Turing&lt;/a&gt;? &lt;a href="http://en.wikipedia.org/wiki/Turing_Award"&gt;Turing award&lt;/a&gt;? &lt;a href="http://en.wikipedia.org/wiki/Turing_test"&gt;Turing test&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;How about the &lt;a href="http://en.wikipedia.org/wiki/Enigma_machine"&gt;Enigma machines&lt;/a&gt; and encryption/decryption?&lt;br /&gt;&lt;br /&gt;What about the first computers?&lt;br /&gt;&lt;br /&gt;What's the connection between these three?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.bletchleypark.org.uk/"&gt;Bletchley Park&lt;/a&gt;. It's a great place and historically very significant - but underfunded and in need of maintenance otherwise it'll be lost forever. Please help &lt;a href="http://www.savingbletchleypark.org/"&gt;save Bletchley Park&lt;/a&gt; for future generations. Help support it by visiting - it's a great day out.&lt;br /&gt;&lt;br /&gt;If you are an Agile coach - go to the &lt;a href="http://www.agilecoachesgathering.org/wiki/index.php/Home"&gt;Agile Coaches Gathering&lt;/a&gt; which is being held at Bletchley Park.&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-4268303711896862036?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/4268303711896862036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=4268303711896862036' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/4268303711896862036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/4268303711896862036'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/03/save-bletchley-park-birthplace-of.html' title='Save Bletchley Park - the birthplace of computing!'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-3715378347904120597</id><published>2009-03-06T14:16:00.000-08:00</published><updated>2009-03-06T14:48:26.950-08:00</updated><title type='text'>Bootable USB sticks for conference presentations</title><content type='html'>If you have a programming workshop or tutorial to present at a conference, where people bring their own laptops and you want to give the participants programming things to do, then one of the things that always seems to take more time than you expect (during the session) is setting up environments etc before being able to actually do any programming.&lt;br /&gt;&lt;br /&gt;With Stuart Ervine, a colleague of mine who is running &lt;a href="http://www.spaconference.org/spa2009/sessions/session176.html"&gt;a session on GWT&lt;/a&gt; at &lt;a href="http://www.spaconference.org/spa2009/index.php"&gt;SPA2009&lt;/a&gt; (&lt;a href="http://www.spaconference.org/spa2009/index.php?page=booking"&gt;book now!&lt;/a&gt;), we have done some experimenting and now have a setup that I think works quite well - so I wanted to share it here in case it is helpful to others presenting similar sessions.&lt;br /&gt;&lt;br /&gt;Having presented "&lt;a href="http://parlezuml.com/softwarecraftsmanship/sessions/programming_in_the_small.htm"&gt;Programming In The Small&lt;/a&gt;" (PITS) with Mike Hill at "&lt;a href="http://parlezuml.com/softwarecraftsmanship/"&gt;Software Craftsmanship 2009&lt;/a&gt;" I can report that it worked quite well in practice (not perfect though - more on the glitches later).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Providing a complete environment:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Stuart and I wanted an identical environment / setup for all of the participants, so time wouldn't be wasted getting everything working on lots of different platforms. Even if you provide one click installers, participants may be understandably reluctant to install some software just for your session. They may even have things installed which conflict with whatever you want to give them. Therefore, we thought it would be better to provide a complete environment - OS and all.&lt;br /&gt;&lt;br /&gt;We considered two approaches, providing a virtual image (e.g. &lt;a href="http://www.vmware.com/"&gt;VMWare&lt;/a&gt; or &lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt;) with everything installed and configured, or using a bootable USB stick. I attended Lasse Koskela and Markus Hjort's excellent session "&lt;a href="http://www.xpday.org/node/40"&gt;Reading Code Without Psychic Powers&lt;/a&gt;" where they provided bootable CDs which included the complete environment for several different languages. It worked very well - if rather slow to initially boot up. Having had that experience as a participant, Stuart and I decided to try bootable USB sticks.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Making a bootable USB stick:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First - download the latest &lt;a href="http://www.ubuntu.com/getubuntu/download"&gt;Ubuntu&lt;/a&gt; (currently 8.10) - and burn it to a CD (good instructions available on the Ubuntu site). Boot your computer off the CD and be patient while Ubuntu starts (it's slow off a CD). These instructions are provided entirely at your risk.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Create two partitions on the USB stick:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;From the System menu, Administration submenu, select "Partition Editor"&lt;/li&gt;&lt;li&gt;Take a note of the device(s) available.&lt;/li&gt;&lt;li&gt;Insert a USB stick that you want to use for this (it will get &lt;span style="font-weight: bold;"&gt;completely overwritten&lt;/span&gt;, and must be at least 1Gb - we used 4Gb sticks).&lt;/li&gt;&lt;li&gt;Right click on the USB stick that has been recognised and "Unmount Volume".&lt;/li&gt;&lt;li&gt;In the "Partition Editor" (GParted) select menu item GParted -&gt; Refresh Devices&lt;/li&gt;&lt;li&gt;In the "Partition Editor" (GParted) select the USB stick from the menu GParted -&gt; Devices&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;if you proceed from this point with the wrong device selected then you'll trash your machine&lt;/span&gt;, so don't get it wrong. Clues about which device is the USB stick are the size of the device and that it wasn't on the list before you plugged it in.&lt;/li&gt;&lt;li&gt;For each of the partitions on the USB stick (there will usually only be one) right click and "Delete"&lt;/li&gt;&lt;li&gt;Click on the (now grey) bar which represents the partitions on the USB stick&lt;/li&gt;&lt;li&gt;Click "New"&lt;/li&gt;&lt;li&gt;Drag the right hand side of the bar and create a FAT32 partition large enough for the Ubuntu image (about 710Mb should be enough). See image below.&lt;/li&gt;&lt;li&gt;Click on the (now grey) bar which represents the unpartitioned space on the USB stick&lt;/li&gt;&lt;li&gt;Click "New"&lt;/li&gt;&lt;li&gt;Create another partition - can be FAT32 or ext2 - doesn't really matter much. (I found FAT32 to be fine).&lt;/li&gt;&lt;li&gt;Click "Apply"&lt;/li&gt;&lt;li&gt;Close the "Partition Editor" (GParted)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bWojgvr6MtU/SbGjUCMhcVI/AAAAAAAAAA0/DuY6enlcngY/s1600-h/firstPartition.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 220px;" src="http://1.bp.blogspot.com/_bWojgvr6MtU/SbGjUCMhcVI/AAAAAAAAAA0/DuY6enlcngY/s320/firstPartition.png" alt="" id="BLOGGER_PHOTO_ID_5310205000228630866" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;Write Ubuntu onto the USB stick:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;From the System menu, Administration submenu, select "Create a USB startup disk"&lt;/li&gt;&lt;li&gt;Select the device which is the USB stick (as noted above when creating the partitions). If you don't see your device in the list of "USB Disk to use", you might possibly have to unmount the newly created partitions of the USB stick, remove your USB stick and put it back in.&lt;/li&gt;&lt;li&gt;Click "Make Startup Disk"&lt;/li&gt;&lt;li&gt;Get a cup of tea - this'll take a few minutes&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Copy programs/files to the other partition:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can copy whatever programs, files etc the participants need to the other partition (the second one you created). For the PITS session this meant Eclipse, Harmony JDK and an Eclipse workspace with the projects for the session. Running from the USB stick won't be very fast but may be acceptable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;To make your software run faster:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you want the software to run faster, then set it up for participants to copy to the Ubuntu desktop (where it will be running from memory).&lt;br /&gt;&lt;br /&gt;If you want to run memory hogging software from the desktop then participants might not have enough RAM (they might run out of memory and I think the live Ubuntu won't try to use the hard disk for swap space). You can set up Ubuntu to use swap space on the USB stick. To create and mount a 1Gb swap file:&lt;br /&gt;&lt;br /&gt;Create an empty file the size of the swap space you want to provide (where /media/disk-1 is where the second partition created earlier is mounted) (this may take a few minutes):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;dd if=/dev/zero of=/media/disk-1/swapfile.swp bs=1024 count=1024k&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Provide an executable script in the second partition for participants to run if they need swap space, containing:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-family:courier new;" &gt;mkswap swapfile.swp&lt;/span&gt; &lt;span style="font-family: courier new;font-family:courier new;" &gt;&lt;br /&gt;sudo swapon swapfile.swp&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Mass production:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So far so good - however, you don't want to have to do this for every USB stick you need to create. Having created one USB stick which has everything set up just right, you can copy its entire contents (including partition table) to other USB sticks using the following (where /dev/sde is the "master" USB stick and /dev/sdf is the one you want to copy to):&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;dd if=/dev/sde of=/dev/sdf bs=8M count=250&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This copies the first 2Gb from USB stick &lt;span style="font-family:courier new;"&gt;/dev/sde&lt;/span&gt; to USB stick &lt;span style="font-family:courier new;"&gt;/dev/sdf&lt;/span&gt;. In order to make this mass copying faster, for the PITS session we didn't use all the space of the USB sticks. We created the second partition using only part of the remaining space. The numbers for "bs" and "count" were arrived at experimentally to minimize the time it took to make the copies. (Multiply them together to work out the amount copied - i.e. using "&lt;span style="font-family:courier new;"&gt;bs=4M count=500&lt;/span&gt;" copies the same amount, but with my USB sticks was slightly slower). The copying may take a few minutes per stick.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Glitches and gotchas:&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Be really careful about mount points (e.g. "&lt;span style="font-family:courier new;"&gt;/dev/sde&lt;/span&gt;") so as not to trash your hard disk.&lt;/li&gt;&lt;li&gt;Not all machines will boot off a USB. The big glitch is that Apple Macs don't seem to like booting from a USB stick (and even some regular PCs don't). One potential solution for such participants is to provide a bootable Ubuntu live CD and use the USB stick for the programs to run in the live Ubuntu.&lt;/li&gt;&lt;li&gt;Not all participants were overjoyed at using Ubuntu.&lt;/li&gt;&lt;li&gt;Participants already using Ubuntu couldn't just run the software included in the second partition because the paths were set up for the "live CD" user.&lt;/li&gt;&lt;li&gt;Participants need to have some easy way to go from having booted off the USB stick to running the software for the session - we provided a "run.sh" file but in the rush of people getting their machines to boot off the USB (trying to find which key to press to change the boot device) not everyone heard the instructions (which we should have given before handing out the USB sticks).&lt;/li&gt;&lt;li&gt;Some participants took a while to find the right key to press to boot off a USB device - a lot of machines print the message saying which key to press for such a short time it is difficult to read it. It may be an idea to suggest that participants figure this out before the session.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Other considerations:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It would have been nice to allow participants to keep the USB sticks but they cost money and we're not working for some large consultancy who might want to do this for promotion.&lt;br /&gt;&lt;br /&gt;You need one USB stick per machine (we had participants pairing).&lt;br /&gt;&lt;br /&gt;We provided other mechanisms for participants to get the materials for the session - it was fairly straightforward for the PITS session as it was pure Java - so we provided the source (and Eclipse and IntelliJ project files) for participants who already have a Java environment. A lot of participants were very organized and had downloaded these materials from the conference web site before the session. We provided the materials in password protected zips and gave participants the password at the session.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;And finally:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you want to see this in action - go to Stuart's GWT session at &lt;a href="http://www.spaconference.org/spa2009/index.php"&gt;SPA2009&lt;/a&gt;. Ubuntu rocks. GWT rocks. Stuart rocks. Mike rocks. SPA rocks.&lt;br /&gt;&lt;br /&gt;Many thanks to Stuart Ervine for help with working this all out and writing it up. Many thanks to Mike Hill for preparing and co-presenting PITS.&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-3715378347904120597?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/3715378347904120597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=3715378347904120597' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3715378347904120597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3715378347904120597'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/03/bootable-usb-sticks-for-conference.html' title='Bootable USB sticks for conference presentations'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_bWojgvr6MtU/SbGjUCMhcVI/AAAAAAAAAA0/DuY6enlcngY/s72-c/firstPartition.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-1870635964847147751</id><published>2009-02-14T02:12:00.000-08:00</published><updated>2009-02-16T12:24:17.924-08:00</updated><title type='text'>Two styles</title><content type='html'>Even simple programs can be written many different ways. This article shows an example of two different styles for a very simple program - I hope the difference is instructive.&lt;br /&gt;&lt;br /&gt;The code is shown in Java - but the two styles are applicable to any object-oriented programming language.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The problem to solve&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The problem is a slightly reduced version of the parsing part of this &lt;a href="http://icpcres.ecs.baylor.edu/onlinejudge/index.php?option=com_onlinejudge&amp;amp;Itemid=8&amp;amp;category=3&amp;amp;page=show_problem&amp;amp;problem=37"&gt;robot blocks programming contest problem&lt;/a&gt;. To slightly reduce the problem I just use the first two commands and treat the input as a string rather than a file.&lt;br /&gt;&lt;br /&gt;Therefore, the problem is to parse input that looks like this:&lt;br /&gt;&lt;pre&gt;10&lt;br /&gt;move 4 over 3&lt;br /&gt;move 3 onto 5&lt;br /&gt;quit&lt;br /&gt;&lt;/pre&gt;i.e. the first line is the number of blocks (used to set up the robot), the last line is "quit" (that's just how the input is - has no effect on the robot) and the lines in between are commands (each line is one command, e.g. "move over" is a single command with two parameters, the source block and the destination block).&lt;br /&gt;&lt;br /&gt;No validation is needed - the input will always be well formed - there are no tricks in the question - it is as it looks.&lt;br /&gt;&lt;br /&gt;The input will be used to control a robot. You can come up with whatever api you want - you can treat it as if you will be implementing the robot at some point too.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Now your turn&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Please have a go at implementing this in Java or a similar language - (parsing input like that shown) - allow a maximum of one hour. If you have any questions about the problem, take the answer as being whatever makes it simplest - there are no tricks to this.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;What did you end up with?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I've seen a lot of solutions to this over the last year. That is because I've been doing a lot of interviewing for my client (using &lt;a href="http://peripateticaxiom.blogspot.com/2008/09/programming-interview-questions.html"&gt;the best interview question&lt;/a&gt;) and have used this example many times.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;What most people end up with&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's a solution in the most popular style:&lt;br /&gt;&lt;pre&gt;package com.oocode;&lt;br /&gt;&lt;br /&gt;import static java.lang.Integer.parseInt;&lt;br /&gt;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;import com.oocode.Command.Type;&lt;br /&gt;&lt;br /&gt;public class RobotParser {&lt;br /&gt;  private final int numberOfBlocks;&lt;br /&gt;  private final List&lt;Command&gt; commands = new ArrayList&lt;Command&gt;();&lt;br /&gt;&lt;br /&gt;  public RobotParser(String input) {&lt;br /&gt;    String[] lines = input.split("\n");&lt;br /&gt;    numberOfBlocks = parseInt(lines[0]);&lt;br /&gt;    for (int i = 1; i &lt; lines.length - 1; i++) {&lt;br /&gt;      String line = lines[i];&lt;br /&gt;      String[] parts = line.split(" ");&lt;br /&gt;      int sourceBlock = parseInt(parts[1]);&lt;br /&gt;      int destinationBlock = parseInt(parts[3]);&lt;br /&gt;      Type type = parts[2].equals("over") ? &lt;br /&gt;            Command.Type.MOVE_OVER :&lt;br /&gt;            Command.Type.MOVE_ONTO;&lt;br /&gt;      commands.add(new Command(sourceBlock, &lt;br /&gt;                               destinationBlock, &lt;br /&gt;                               type));&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public int getNumberOfBlocks() {&lt;br /&gt;    return numberOfBlocks;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public List&lt;Command&gt; getCommands() {&lt;br /&gt;    return commands;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;and:&lt;br /&gt;&lt;pre&gt;package com.oocode;&lt;br /&gt;&lt;br /&gt;public class Command {&lt;br /&gt;  private final int sourceBlock;&lt;br /&gt;  private final int destinationBlock;&lt;br /&gt;  private final Type type;&lt;br /&gt;  &lt;br /&gt;  public Command(int sourceBlock, &lt;br /&gt;                 int destinationBlock, &lt;br /&gt;                 Type type) {&lt;br /&gt;    this.sourceBlock = sourceBlock;&lt;br /&gt;    this.destinationBlock = destinationBlock;&lt;br /&gt;    this.type = type;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public enum Type {&lt;br /&gt;    MOVE_OVER, &lt;br /&gt;    MOVE_ONTO&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public int getSourceBlock(){&lt;br /&gt;    return sourceBlock;&lt;br /&gt;  }&lt;br /&gt;  public int getDestinationBlock(){&lt;br /&gt;    return destinationBlock;&lt;br /&gt;  }&lt;br /&gt;  public Type getType() {&lt;br /&gt;    return type;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;This is a decent representative of this style. I've chosen a shortish variation of the style to keep down the amount of code you have to wade through (although it could have been slightly shorter still if I'd parsed the command type using the enum). A popular variation is to have a Command interface and different implementations for MoveOverCommand and MoveOntoCommand. One thing that is quite nice about the problem is that there is scope in the solutions for showing different programming style and taste.&lt;br /&gt;&lt;br /&gt;As far as the "two styles" that I'm talking about, the important feature is that the RobotParser has getters for the numberOfBlocks and the Commands, which are &lt;a href="http://puttingtheteaintoteam.blogspot.com/2008/10/is-that-pojo-or-nojo.html"&gt;NoJos&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;An alternative solution&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hardly anyone implements this alternative style:&lt;br /&gt;&lt;pre&gt;package com.oocode;&lt;br /&gt;&lt;br /&gt;import static java.lang.Integer.parseInt;&lt;br /&gt;&lt;br /&gt;public class RobotParser {&lt;br /&gt;  private final Robot robot;&lt;br /&gt;&lt;br /&gt;  public RobotParser(Robot robot) {&lt;br /&gt;    this.robot = robot;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public void parse(String input) {&lt;br /&gt;    String[] lines = input.split("\n");&lt;br /&gt;    int numberOfBlocks = parseInt(lines[0]);&lt;br /&gt;    robot.setNumberOfBlocks(numberOfBlocks);&lt;br /&gt;    for (int i = 1; i &lt; lines.length - 1; i++) {&lt;br /&gt;      String line = lines[i];&lt;br /&gt;      String[] parts = line.split(" ");&lt;br /&gt;      int sourceBlock = parseInt(parts[1]);&lt;br /&gt;      int destinationBlock = parseInt(parts[3]);&lt;br /&gt;      if(parts[2].equals("over")) {&lt;br /&gt;        robot.moveOver(sourceBlock, destinationBlock);&lt;br /&gt;      } else {&lt;br /&gt;        robot.moveOnto(sourceBlock, destinationBlock);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;and:&lt;br /&gt;&lt;pre&gt;package com.oocode;&lt;br /&gt;&lt;br /&gt;public interface Robot {&lt;br /&gt;  void moveOver(int sourceBlock, int destinationBlock);&lt;br /&gt;&lt;br /&gt;  void moveOnto(int sourceBlock, int destinationBlock);&lt;br /&gt;&lt;br /&gt;  void setNumberOfBlocks(int numberOfBlocks);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;A variation of this would be to have a RobotFactory which creates a Robot for a given number of blocks, to prevent the possibility of command methods being called before "setNumberOfBlocks". I would expect the implementation to use a BufferedReader if it were reading from a file rather than a string input. As before, I've gone for a short variation of this style.&lt;br /&gt;&lt;br /&gt;In this style, the important feature is that there are no getters, and no Command class or classes. You could possibly describe this solution as being an example of "&lt;a href="http://www.pragprog.com/articles/tell-dont-ask"&gt;tell don't ask&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;And finally ...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Most of the solutions I have seen to the problem have been during interviews that I have conducted. During these interviews, most solutions are the first style and hardly any of the second style.&lt;br /&gt;&lt;br /&gt;I don't know whether the popularity of the first style is skewed by it being an interview situation, by the demographics of the people I am interviewing or for some other reason. Most of the interviewees didn't use TDD but did write automated unit tests after the code. However, the majority of those using TDD still produced the first style.&lt;br /&gt;&lt;br /&gt;What do you think? What would you do? Which style is "better"? Is that a valid question? If you come up with a different solution that you think is interesting then please put a comment with a link to your blog - please don't paste code in your comments or they will get too long and probably won't format well anyway.&lt;br /&gt;&lt;br /&gt;I'm looking forward to seeing something completely different - regex anyone? I don't know - I'm sure there are other styles but the first one shown is, by far, the one I have seen most often when interviewing for Java developers. (And, of course, different languages could produce completely different styles).&lt;br /&gt;&lt;br /&gt;And finally - does anyone have good names for these two styles (maybe "getter style" vs "doer style")? &lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-1870635964847147751?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/1870635964847147751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=1870635964847147751' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/1870635964847147751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/1870635964847147751'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/02/two-styles.html' title='Two styles'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-5754134129394200555</id><published>2009-01-24T04:50:00.000-08:00</published><updated>2009-01-24T05:55:48.372-08:00</updated><title type='text'>Making fields and methods as private as possible - a postmodern Thatcher.</title><content type='html'>Fields and methods should be declared as private as possible. As I mentioned in &lt;a href="http://ivan.truemesh.com/archives/000602.html"&gt;an article on the subject&lt;/a&gt; "I thought of writing a tool to do this that I was going to call "Thatcher" - it would privatize as much as possible".&lt;br /&gt;&lt;br /&gt;I only realized a few days ago that I've already written it (I really am quite dense), and in fact had written it several years before writing that article.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;How do you tell if fields and methods can be made private?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I think the most popular ways for people to tell are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;look for all references to the field or method and see if any are outside the class it is declared in&lt;/li&gt;&lt;li&gt;change "public" to "private" and see if it fails to compile (e.g. red Xs in eclipse)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Unfortunately, both of these approaches have limitations for most enterprise java applications (particularly web applications). These approaches don't work if the field or method in question is used reflectively, e.g. by a template (e.g. &lt;a href="http://freemarker.sourceforge.net/"&gt;FreeMarker&lt;/a&gt;, JSP etc). That's the limitation of a static analysis implementation of "Thatcher".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;If you are paranoid, how do you tell if fields and methods can be made private?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The only safe way to tell, for a field or method that you want to see if it can be private, is to make it private and then see if the application still works.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;How to automate that?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you have good test coverage, then "the application still works" is automated as "the build (including tests) passes" (e.g. the build that you use on your CI server).&lt;br /&gt;&lt;br /&gt;Then you are left with the problem "how do I tell if "public" can be changed to "private" and the build (including tests) still passes?".&lt;br /&gt;&lt;br /&gt;Now that sounds familiar to me - it's rather close to what Jester does.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Jester - a mutation testing tool&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I wrote &lt;a href="http://jester.sourceforge.net/"&gt;Jester&lt;/a&gt; as a mutation testing tool. As it says on the web site: "Jester makes some change to your code, runs your tests, and if the tests pass Jester displays a message saying what it changed." The idea is that if you can change your code and the tests still pass then the tests aren't covering the code (other possibilities are that it's a behaviour preserving change, or the code is redundant).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Jester as a postmodern Thatcher&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Jester can be used to implement Thatcher by configuring it to mutate "public" to "private" and "protected" to "private" (package visibility is harder!). I think this could be described as a&lt;span style="text-decoration: underline;"&gt; &lt;/span&gt;&lt;a href="http://www.postmodernprogramming.org/"&gt;postmodern programming&lt;/a&gt; approach - (re)using some code to do something it wasn't designed for.&lt;br /&gt;&lt;br /&gt;I hadn't thought of doing this until it occurred to me a few days ago (and now it seems so obvious) because I had imagined that Thatcher would use static analysis and hence be very different (that's my modernist thinking, it would have to use static analysis to be a fast and "proper" implementation and the fact that it wouldn't always be correct would be a fault of the imperfect world).&lt;br /&gt;&lt;br /&gt;It might be that someone has proposed this before (in which case, sorry, I don't remember).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Limitations of &lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Thatcher &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;implemented using Jester&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;&lt;/span&gt;It should be noted that using Jester for implementing Thatcher only works if your build (including tests) has sufficient coverage that you are happy that if it passes then that means the application works.&lt;br /&gt;&lt;br /&gt;Also note that using Jester for this could take a really long time. If your build takes an hour then it would take many machine days to privatize even a very small amount of code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;An example run of Thatcher &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;implemented using Jester&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's an example of using the latest version of Jester ("simple jester" also &lt;a href="http://ivan.truemesh.com/archives/000725.html"&gt;described here&lt;/a&gt;) as Thatcher. For this example, I'm using Checkstyle as the code base for which I want to make fields and methods as private as possible. I chose Checkstyle for this example because the build is very fast!&lt;br /&gt;&lt;br /&gt;(To try this out for yourself, you will need Java installed with java, javac and ant on the path. These instructions are for Windows. Replace &lt;span style="font-family:courier new;"&gt;&amp;lt;wherever&amp;gt;&lt;/span&gt; as appropriate).&lt;br /&gt;&lt;ul&gt;&lt;li&gt;download &lt;a href="http://downloads.sourceforge.net/checkstyle/checkstyle-src-5.0-beta01.zip?modtime=1216305884&amp;amp;big_mirror=0"&gt;checkstyle &lt;/a&gt;&lt;/li&gt;&lt;li&gt;unzip&lt;/li&gt;&lt;li&gt;cd to &amp;lt;wherever&amp;gt;checkstyle-src-5.0-beta01&lt;/li&gt;&lt;li&gt;in order to check that everything is OK so far, execute "&lt;span style="font-family:courier new;"&gt;ant run.tests&lt;/span&gt;"&lt;/li&gt;&lt;/ul&gt;should get:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;BUILD SUCCESSFUL&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Total time: 33 seconds&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(or whatever time)&lt;br /&gt;&lt;ul&gt;&lt;li&gt;download &lt;a href="http://downloads.sourceforge.net/jester/simple-jester-1.1.zip?modtime=1200000724&amp;amp;big_mirror=0"&gt;Jester&lt;/a&gt; (the simple-jester variety) &lt;/li&gt;&lt;li&gt;unzip&lt;/li&gt;&lt;li&gt;cd to &amp;lt;wherever&amp;gt;simple-jester-1.1&lt;/li&gt;&lt;li&gt;for the step below to work, execute "&lt;span style="font-family:courier new;"&gt;setcp.bat&lt;/span&gt;"&lt;/li&gt;&lt;li&gt;in order to check that everything is OK so far, execute "&lt;span style="font-family:courier new;"&gt;test.bat&lt;/span&gt;"&lt;/li&gt;&lt;/ul&gt;should get:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;17 mutations survived out of 19 changes. Score = 11&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;took 0 minutes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(or whatever time)&lt;br /&gt;&lt;br /&gt;In order to check that the checkstyle build can be run from the jester directory (i.e. still in &amp;lt;wherever&amp;gt;simple-jester-1.1) (which makes it simpler for running Jester in this example)&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:courier new;"&gt;ant -f &amp;lt;wherever&amp;gt;checkstyle-src-5.0-beta01\build.xml run.tests&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;should get:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;BUILD SUCCESSFUL&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Total time: 21 seconds&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(or whatever time)&lt;br /&gt;&lt;br /&gt;Now edit "mutations.cfg" (in &amp;lt;wherever&amp;gt;simple-jester-1.1) and replace contents with:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;%public%private&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;%protected%private&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That configures Jester to try mutating "public" to "private" and "protected" to "private". Unfortunately, Jester cannot currently be configured to not mutate literal numbers - so in order to avoid Jester making mutations to literal numbers you have to be a bit cunning.&lt;br /&gt;&lt;br /&gt;Create a text file in folder "&amp;lt;wherever&amp;gt;simple-jester-1.1\\jester" called SimpleIntCodeMangler.java with contents:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;package jester;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;public class SimpleIntCodeMangler implements CodeMangler {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    public SimpleIntCodeMangler(ClassSourceCodeChanger sourceCodeSystem) {&lt;/span&gt;&lt;br /&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;    public boolean makeChangeToClass() throws SourceChangeException {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        return false;&lt;/span&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;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Then (in &amp;lt;wherever&amp;gt;simple-jester-1.1) execute "javac jester\SimpleIntCodeMangler.java".&lt;br /&gt;&lt;br /&gt;If "." is on the classpath before simple-jester.jar then the new version of SimpleIntCodeMangler will replace the version in simple-jester.jar, so Jester won't do the literal number mutations.&lt;br /&gt;&lt;br /&gt;Now to run Jester/Thatcher (just on the one class "Checker"), execute:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;java jester.TestTester "ant.bat -f &amp;lt;wherever&amp;gt;checkstyle-src-5.0-beta01\build.xml run.tests" &amp;lt;wherever&amp;gt;checkstyle-src-5.0-beta01\src\checkstyle\com\puppycrawl\tools\checkstyle\Checker.java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(note that on windows it &lt;span style="font-weight: bold;"&gt;has to be "ant.bat"&lt;/span&gt; and not just "ant")&lt;br /&gt;&lt;br /&gt;Now Jester will run for a while, and eventually you get:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;4 mutations survived out of 24 changes. Score = 84&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;took 5 minutes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you want a simple way to visualize the results, then run "&lt;span style="font-family:courier new;"&gt;python makeWebView.py&lt;/span&gt;" and have a look at "jester.html".&lt;br /&gt;&lt;br /&gt;To get the code changed to make methods and fields private which can be made private, then run "&lt;span style="font-family:courier new;"&gt;python makeAllChangesFiles.py jesterReport.xml&lt;/span&gt;" and you get a version of Checker.java called Checker.jester (in the same folder, i.e. "&amp;lt;wherever&amp;gt;checkstyle-src-5.0-beta01\src\checkstyle\com\puppycrawl\tools\checkstyle\") which has all the privatizations where the tests still pass.&lt;br /&gt;&lt;br /&gt;The results for Checker.java show that &lt;span style="font-family:courier new;"&gt;addFileSetCheck&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;setModuleFactory&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;setSeverity &lt;/span&gt;and &lt;span style="font-family:courier new;"&gt;setClassloader &lt;/span&gt;can be made private and the "&lt;span style="font-family: courier new;"&gt;ant &lt;/span&gt;&lt;span style="font-family: courier new;font-family:courier new;" &gt;run.tests&lt;/span&gt;" build still passes. Having had a look at the code - it might be that these methods need to be public for something not covered by the tests but are needed for the application to work (because the only tests are unit tests and not end-to-end tests; this is a limitation mentioned earlier).&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;And finally&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;If you like that (or even if you don't) then please &lt;a href="http://www.justgiving.com/ivanrmoore"&gt;donate&lt;/a&gt; to my 5 countries (300 miles) in 3 days bike ride to raise money for the &lt;a href="http://www.nas.org.uk/"&gt;National Autistic Society&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-5754134129394200555?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/5754134129394200555/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=5754134129394200555' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5754134129394200555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5754134129394200555'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/01/making-fields-and-methods-as-private-as.html' title='Making fields and methods as private as possible - a postmodern Thatcher.'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-2884834965316017495</id><published>2009-01-17T09:27:00.000-08:00</published><updated>2009-01-17T10:13:08.312-08:00</updated><title type='text'></title><content type='html'>&lt;a href="http://www.spaconference.org/spa2009/index.php"&gt;My favourite conference (SPA)&lt;/a&gt; is open for registrations. Book before 31 January to catch the early-bird discount rate.&lt;br /&gt;&lt;br /&gt;I'm programme co-chair (with Mike Hill) and very happy with the &lt;a href="http://www.spaconference.org/spa2009/index.php?page=programme"&gt;programme&lt;/a&gt; we've been able to assemble.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.spaconference.org/spa2009/index.php?page=booking"&gt;Book now&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-2884834965316017495?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/2884834965316017495/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=2884834965316017495' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/2884834965316017495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/2884834965316017495'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/01/my-favourite-conference-spa-is-open-for.html' title=''/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-8055609057589261446</id><published>2009-01-04T04:08:00.000-08:00</published><updated>2009-01-04T05:01:20.556-08:00</updated><title type='text'>Charity Day</title><content type='html'>I am doing a &lt;a href="http://www.nas.org.uk/nas/jsp/polopoly.jsp?d=1970"&gt;charity bike ride&lt;/a&gt; in June to raise money for the &lt;a href="http://www.nas.org.uk/"&gt;National Autistic Society&lt;/a&gt; (NAS). One of my sons is autistic and the NAS have been very helpful. I did a &lt;a href="http://ivan.truemesh.com/archives/000692.html"&gt;London to Paris bike ride&lt;/a&gt; for NAS in 2007.&lt;br /&gt;&lt;br /&gt;&lt;a style="font-weight: bold;" href="http://www.justgiving.com/ivanrmoore"&gt;Please donate!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Time is money&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For the 2007 bike ride I paid the costs myself so all money donated went to the NAS. For the 2009 bike ride I'd like to do something equivalent but slightly different. I'm offering a day of my time for a donation that more than covers the costs. (The alternative is that I pay using roughly a day of my usual billing - but I'd like a generous charity minded company to donate more than that).&lt;br /&gt;&lt;br /&gt;That day could be:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://puttingtheteaintoteam.blogspot.com/2008/12/refactoring-and-tdd-training-course.html"&gt;&lt;span style="font-weight: bold;"&gt;Refactoring and TDD Training&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;continuous integration&lt;/span&gt; - e.g. installing an automated CI system (e.g. TeamCity, build-o-matic or whatever)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Agile consulting&lt;/span&gt; (I've been doing "Agile" a long time - papers at XP2000, XP2001, XP2002, OOPSLA, TOOLS. Presentations at XPDay, SPA, ACCU etc)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;other stuff&lt;/span&gt; (dunno - email me and we can discuss)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;and there is more:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;publicity &lt;/span&gt;- I'll write a short blog article - anything from just the name of the company and the donation up to an article about what I did for you (you can review/edit before publication)&lt;/li&gt;&lt;li&gt;"&lt;span style="font-weight: bold;"&gt;small print&lt;/span&gt;" - I'm based in London, England. Anything outside of London might require you to pay expenses too.&lt;/li&gt;&lt;li&gt;"&lt;span style="font-weight: bold;"&gt;more small print&lt;/span&gt;" - If I get multiple offers then I'll choose whichever I prefer.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;To discuss this, or for more details, please email ivan at teamoptimization.com&lt;br /&gt;&lt;br /&gt;If you aren't in the market for a day of my time then please &lt;a href="http://www.justgiving.com/ivanrmoore"&gt;make a donation&lt;/a&gt; of any amount you'd like!&lt;br /&gt;&lt;br /&gt;Copyright © 2009 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-8055609057589261446?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/8055609057589261446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=8055609057589261446' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/8055609057589261446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/8055609057589261446'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2009/01/charity-day.html' title='Charity Day'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-3944496218077777581</id><published>2008-12-14T02:50:00.000-08:00</published><updated>2008-12-14T03:13:44.357-08:00</updated><title type='text'>Running builds for previous revisions</title><content type='html'>Can you run the build for a previous revision of your code? Can you do that fully automatically or do you need manual steps? Should you care?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;It's good to have an automated build&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;As &lt;a href="http://martinfowler.com/"&gt;Martin Fowler&lt;/a&gt; &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;says&lt;/a&gt; "... you should be able to walk up to the project with a virgin machine, do a checkout, and be able to fully build the system."&lt;br /&gt;&lt;br /&gt;There are lots of benefits of having a fully automated build. It means all developers are building in the same way, reducing "it works on my machine" problems. It helps with productivity - you don't make mistakes doing the build and then have to do it again to get it right. There are other benefits too - but there are lots of other articles about this topic so I don't want to repeat them here.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Turning the dials up&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What Martin Fowler doesn't say is "... do a checkout for &lt;span style="font-weight: bold;"&gt;any &lt;/span&gt;revision ..." (rather than just the most recent), but I think it is what you should aim to do.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Why "any revision"?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One reason you might need to run the build for any revision is in order to work out which commit broke the build in the case where you have multiple commits between builds and the build is broken. There are other reasons too - e.g. finding out what change introduced some bug that has been hiding undetected for a while (i.e. didn't cause the build to break but now you've found it and want to find out how to fix it or when/how it got introduced).&lt;br /&gt;&lt;br /&gt;(As an aside - some CI servers can help reduce the occurrence of multiple commits between builds, but even if you are running a CI server which builds multiple revisions in parallel on multiple build agents, if the build farm isn't large enough for the number of commits and the speed of the build, then you will end up with multiple commits between builds. Or if you take the approach of having the CI server run the build before committing then you end up with a bottleneck delaying commits if you don't have enough agents.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Can you run the build for a previous revision of your code?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If your system includes a database - how do you manage the database schema? In some teams, this is one of the dirty secrets - it's done by running some scripts manually as necessary - hence you can't run the build for a previous revision (or in some cases even the most recent revision) just by checking out the code (for that revision) and running the build.&lt;br /&gt;&lt;br /&gt;Many teams use something like &lt;a href="http://dbdeploy.com/"&gt;dbdeploy&lt;/a&gt; so changes to the database are made as delta scripts which make the necessary changes to the database in synch with code changes. Although this allows database migration forwards in time - how many teams implement the rollback scripts to allow the database to be reverted so that it is in synch with previous revisions of the code? Often you have to just rebuild the database from scratch in that case - and the build script might not do that automatically.&lt;br /&gt;&lt;br /&gt;What if you use maven and have snapshot dependencies? How do you build the code the same as it was built an hour ago?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Why fully automate?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Any manual steps in something that you don't do frequently makes it likely that you'll find it difficult to do when you need to. Furthermore, manual steps to build previous revisions prevent you from taking advantage of all of the features of some CI servers (TeamCity, Pulse and build-o-matic all allow manually triggered building of a previous revision of the code. build-o-matic will automatically build previous revisions of your code in some circumstances, so if your build doesn't support running the build automatically for a previous revision then it won't always work as expected).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;One of the logical conclusions - your development environment should be checked in&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Being able to run the build for any revision of your code might require you to have more things in your source control system than you are used to. This can be controversial (even though it's mentioned in Martin Fowler's well read &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;CI article&lt;/a&gt;). I like to have absolutely everything that the build depends on in the source control system - even when it isn't source.&lt;br /&gt;&lt;br /&gt;For example, on a Java project, I like to have Java itself, Ant etc all checked in. If you change which version of Java you use (which you are more likely to do than you might think) then you want to ensure that everyone is using the same version and that you can build the project as it was in the past (if Java isn't checked in then how are you going to be sure what version it is or was)? This can be controversial (Martin Fowler mentions "Java development environment" as something that you might not check in but I disagree with him on this specific case) - but if you take the ability to check out and build the code at any point in time it to it's logical conclusion then you have to include everything you need to build it - machine set up and all. One of the advantages of taking things to this level is that it is trivial to set up a new development machine - you just check out everything and you are ready. This isn't always possible - particularly on Windows - but is a worthy aim and more achievable than you might think.&lt;br /&gt;&lt;br /&gt;Copyright © 2008 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-3944496218077777581?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/3944496218077777581/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=3944496218077777581' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3944496218077777581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3944496218077777581'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/12/running-builds-for-previous-revisions.html' title='Running builds for previous revisions'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-3224912917848132890</id><published>2008-12-13T06:58:00.000-08:00</published><updated>2008-12-13T07:16:50.576-08:00</updated><title type='text'>Software Craftsmanship conference 2009</title><content type='html'>The &lt;a href="http://parlezuml.com/softwarecraftsmanship/index.htm"&gt;Software Craftsmanship conference 2009&lt;/a&gt; is &lt;a href="http://parlezuml.com/softwarecraftsmanship/propose.htm"&gt;open for session proposals&lt;/a&gt;. Please submit a session proposal. I think the conference is now fully booked for attendees but you can still get in to the conference if you get your proposal accepted.&lt;br /&gt;&lt;br /&gt;It's a great idea for a conference. I think a lot of progress has been made in our industry to improve processes. As teams become better in their processes, programming practices and code quality become relatively more important.&lt;br /&gt;&lt;br /&gt;The timing of the conference is great - with the release of more books now that concentrate on code quality (like &lt;a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882"&gt;clean code&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Copyright © 2008 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-3224912917848132890?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/3224912917848132890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=3224912917848132890' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3224912917848132890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3224912917848132890'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/12/software-craftsmanship-conference-2009.html' title='Software Craftsmanship conference 2009'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-2514869505093006906</id><published>2008-12-11T23:24:00.000-08:00</published><updated>2008-12-12T00:06:17.080-08:00</updated><title type='text'>Refactoring and TDD Training Course</title><content type='html'>I'm offering a completely new style of training course on refactoring, TDD and just programming better. It is pair programming with me (or others depending on demand).&lt;br /&gt;&lt;br /&gt;It'll be similar cost per person per day to other courses, but instead of a classroom, it's one-to-one instruction at your site. It's also working on your code base, improving it during the course (possibly adding features too). Attendees will retain more learning that is directly applicable compared to more regular classroom courses. They will learn things from this course in addition to refactoring and TDD, like better use of the IDE, frequent commits, retro-fitting unit tests to their actual code base rather than just in the abstract.&lt;br /&gt;&lt;br /&gt;See my "&lt;a href="http://ivan.truemesh.com/archives/cat_programming_in_the_small.html"&gt;programming in the small&lt;/a&gt;" and "&lt;a href="http://ivan.truemesh.com/archives/cat_programming_in_the_large.html"&gt;programming in the large&lt;/a&gt;" articles to get an idea of the sort of programming things that the course will include. (My PhD was in refactoring (completed 1996), I started using JUnit in 1998 and mock objects in 1999). Email me to book a course (and discuss course length - anything from one day upwards) - ivan at teamoptimization.com&lt;br /&gt;&lt;br /&gt;Copyright © 2008 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-2514869505093006906?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/2514869505093006906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=2514869505093006906' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/2514869505093006906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/2514869505093006906'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/12/refactoring-and-tdd-training-course.html' title='Refactoring and TDD Training Course'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-5851591874013528120</id><published>2008-12-10T13:07:00.000-08:00</published><updated>2008-12-10T13:16:38.851-08:00</updated><title type='text'>People over Process</title><content type='html'>The &lt;a href="http://agilemanifesto.org/"&gt;Agile Manifesto&lt;/a&gt; values "Individuals and interactions over processes and tools".&lt;br /&gt;&lt;br /&gt;I have heard a lot of people talk about "People over Process" somewhat differently than my interpretation.&lt;br /&gt;&lt;br /&gt;In this article, I'll refer to a fictional developer called Chuck - nothing is implied by the name.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Chuck doesn't want to write tests&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A frequent interpretation seems to be, if Chuck doesn't want to write tests (for example) then that's OK because people are more important than processes or tools. A lot of the time, people talk as if the question of whether Chuck is worth keeping in the team or not isn't a consideration - you just have to do the best you can with the team you've got; after all, people are more important than processes so that's OK (a non sequitur, but I've heard it said).&lt;br /&gt;&lt;br /&gt;This can be a difficult one to argue against. Whether someone is any good at software development or not, they &lt;span style="font-weight: bold;"&gt;are &lt;/span&gt;"more important" than process, tools, software - but that is a &lt;span style="font-style: italic;"&gt;different &lt;/span&gt;"important".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The worst sort of "Agile"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The worst examples of "Agile" software development are where people take the approach that as long as you do the currently accepted "Agile things" (or at least some easy subset like iterations/sprints, stand up meetings etc etc) and keep your current team (because "people are more important than processes or tools") then you are "Agile". This is the opposite of my interpretation of the agile manifesto - but quite common!&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;My interpretation of "People over Process"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The single most important thing is to get the right people in the team. Just making your existing team follow a set of processes (like iterations/sprints, stand up meetings etc etc) is much less important than having the right people in the team. I think that is what the Agile Manifesto is trying to say.&lt;br /&gt;&lt;br /&gt;As &lt;a href="http://www.think-box.co.uk/blog/2007/04/people-over-processes-and-tools.html"&gt;Simon Baker says&lt;/a&gt; "Put the right people in the right environment and trust them to get things done."&lt;br /&gt;&lt;br /&gt;The consequence of this is that you should hire the best developers you can (&lt;a href="http://peripateticaxiom.blogspot.com/2008/09/programming-interview-questions.html"&gt;this article&lt;/a&gt; describes the best way to interview them). The less palitable consequence is that you should remove developers from a team if they are not good for the team. That doesn't necessarily mean removing them from the company - it may be that there is another role or team in which they would contribute more. You should also consider whether a developer can improve - my experience has been that pair programming really helps to develop developers.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;So should Chuck be made to write tests (or whatever)?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm not sure this is the right question. Really the question should be "is Chuck any good for the team?". If Chuck doesn't want to write tests then I think it's unlikely (but not impossible) that Chuck is (what I consider to be) a good developer. It would probably be counter productive to "make" Chuck write tests, but I'd be happy to pair program with Chuck to show him how it works. If Chuck still doesn't want to write tests then I might prefer not to be on the same team as Chuck (one way or another).&lt;br /&gt;&lt;br /&gt;Copyright © 2008 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-5851591874013528120?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/5851591874013528120/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=5851591874013528120' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5851591874013528120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/5851591874013528120'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/12/people-over-process.html' title='People over Process'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-7149562677361737173</id><published>2008-11-23T06:32:00.000-08:00</published><updated>2008-11-23T07:45:06.623-08:00</updated><title type='text'>The problem with conventional continuous integration servers</title><content type='html'>I recently presented a talk on continuous integration at &lt;a href="http://www.agilenorth.net/"&gt;Agile North&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There was one topic in the talk that I think is so important that I decided to write an article about it. Suprisingly, it's a topic that many users of continuous integration (CI) servers (and even the developers of them in some cases!) don't seem to have thought much about.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Continuous integration&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This article assumes you already know what &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;continuous integration&lt;/a&gt; is.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The problem with conventional continuous integration servers&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Imagine there are three developers, Tom, Dick and Harriet, and a continuous integration server. There is some code in a source code repository and these three developers start with the code cleanly checked out.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Tom makes some changes and commits his changes.&lt;/li&gt;&lt;li&gt;The CI server starts running a build.&lt;/li&gt;&lt;li&gt;Harriet makes some changes and commits her changes.&lt;/li&gt;&lt;li&gt;Dick makes some changes and commits his changes.&lt;/li&gt;&lt;li&gt;The CI server reports that the build is OK.&lt;/li&gt;&lt;li&gt;The CI server starts running a build (because there are new changes for it to run the build on).&lt;/li&gt;&lt;li&gt;Tom makes some changes and commits his changes.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The CI server reports that the build is broken.&lt;/li&gt;&lt;/ol&gt;Here's a diagram representing that:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_bWojgvr6MtU/SSlp7yXiQDI/AAAAAAAAAAM/B_ru7DxxkfM/s1600-h/ciServerProblemTimeline.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 370px; height: 136px;" src="http://1.bp.blogspot.com/_bWojgvr6MtU/SSlp7yXiQDI/AAAAAAAAAAM/B_ru7DxxkfM/s320/ciServerProblemTimeline.PNG" alt="" id="BLOGGER_PHOTO_ID_5271861314667561010" border="0" /&gt;&lt;/a&gt;The question is - who broke the build?  (Left as an exercise for the reader). &lt;span style="font-weight: bold;"&gt;The problem with conventional continuous integration servers is that they can't tell you.&lt;/span&gt; A situation like this is inevitable with the vast majority of continuous integration server installations (that actually exist - I know you could install your favourite CI server differently if you had enough money - read on ...).&lt;br /&gt;&lt;br /&gt;BTW - Step 7 is a bit of a red herring. It is not necessary for the purpose of the main point of this article, but a common enough situation. Tom thinks he's committed on a green build, but really the build is already broken in terms of the committed code, just not in terms of what the CI server is saying.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Why it is a problem&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The problem with not knowing which commit broke the build is that it takes longer to work out who should look at the problem and how they can fix it. If you know which commit broke the build you know who should look at it and they can review their changes to work out why it broke. Furthermore, if you know which commit broke the build (even if you can't work out why), you can revert that change set while the problem is fixed "off line" from the rest of the team.&lt;br /&gt;&lt;br /&gt;I am convinced (from years of using CI servers on many teams) that not knowing which commit broke the build is a major contributor to sloppy CI practice - builds staying red for ages, nobody taking responsibility, reduction in commit frequency etc etc. Just knowing which test failed, or "why" the build broke isn't enough. The symptoms don't always tell you the cause. Knowing the cause - i.e. which commit - is what you need to know.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;When do you get this problem?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You suffer this problem more as the team gets larger, commits become more frequent, and the length of the build goes up. (Oh, and if developers get sloppier).&lt;br /&gt;&lt;br /&gt;You often can't do anything about the size of the team, you'd like to encourage people to commit more frequently and making the build faster can be really hard. (And you might be able to get rid of sloppy developers, but that's quite a different blog post). Ideally the build should be fast, but that is often easier said than done, and even if the build is fast, it doesn't completely eliminate the problem described in this article.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Solutions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Most continuous integration servers don't solve this problem, but some do. These are the solutions that I know about. The CI server can:&lt;br /&gt;&lt;br /&gt;a) run the build for the commits (revisions) between the last known good and the first known bad (provided that there is enough capacity in the build farm, e.g. people stop committing while the build is broken).&lt;br /&gt;b) check that the build passes (on a build agent) before committing changes.&lt;br /&gt;c) run multiple (preferably all) commits in parallel on different build agents in a build farm.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://build-o-matic.sourceforge.net/"&gt;build-o-matic&lt;/a&gt; does (a) automatically - using a binary search. &lt;a href="http://www.jetbrains.net/confluence/display/TW/TeamCity+EAP"&gt;TeamCity&lt;/a&gt; (version 4 EAP) and &lt;a href="http://zutubi.com/products/pulse/"&gt;Pulse&lt;/a&gt; (and maybe others) allow running of a previous revision so you can do the equivalent manually (maybe someone will write a plug-in for TeamCity to do what build-o-matic does? There is &lt;a href="http://code.google.com/p/team-piazza/"&gt;a precedent&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;TeamCity and Pulse do (b) (build-o-matic doesn't - it's a cool feature; I've used it in TeamCity and it works well but you do need a lot of build agents).&lt;br /&gt;&lt;br /&gt;build-o-matic does (c). I think TeamCity and possibly some others will too if you have enough build agents. The problem with this is approach is that you really might need &lt;span style="font-style: italic;"&gt;a lot&lt;/span&gt; of build agents, particularly if the team is large, commit frequently and the build is long.&lt;br /&gt;&lt;br /&gt;My preferred solution is to buy enough build agents to do (c) - computers are very cheap. Note however that just because a CI server supports a build farm, even if the build farm is infinitely large it doesn't &lt;span style="font-style: italic;"&gt;necessarily &lt;/span&gt;mean it'll run the build for all the commits - check your CI server documentation for details. I believe &lt;a href="http://www.atlassian.com/software/bamboo/"&gt;Bamboo&lt;/a&gt; has something up it's sleeve on this topic - but I'm not sure if it's public yet (I'll find out and add a comment as appropriate).&lt;br /&gt;&lt;br /&gt;There is another solution which is not to use a CI server at all, but instead have a "build token" or an "integration machine" - i.e. serialize all commits, that way you never commit while the build is running. That only works well for small co-located teams with a fast build. But when conditions are suitable, it really works well!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Conclusion&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are lots of CI servers to choose from. I consider working out which commit broke the build as a basic minimum feature of a CI server installation but suprisingly not all CI servers are capable of telling you - and you really need to understand this before you choose a CI server that will leave you with a broken build and not knowing which commit caused it.&lt;br /&gt;&lt;br /&gt;Copyright © 2008 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-7149562677361737173?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/7149562677361737173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=7149562677361737173' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7149562677361737173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7149562677361737173'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/11/problem-with-conventional-continuous.html' title='The problem with conventional continuous integration servers'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_bWojgvr6MtU/SSlp7yXiQDI/AAAAAAAAAAM/B_ru7DxxkfM/s72-c/ciServerProblemTimeline.PNG' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-7961105275306293964</id><published>2008-11-09T10:18:00.000-08:00</published><updated>2008-11-09T10:29:58.568-08:00</updated><title type='text'></title><content type='html'>In &lt;a href="http://puttingtheteaintoteam.blogspot.com/2008/11/programming-in-small-exceptions.html"&gt;my previous article&lt;/a&gt; I mentioned the book "&lt;a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882"&gt;Clean Code&lt;/a&gt;" - this article is a brief critique of it (in some cases you'll just have to read the book to see what I'm talking about because I'm not going to rewrite the book here!).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;What I liked&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The first chapter is excellent - particularly pages 4-6 (buy the book to find out what they contain). I got the same feeling of wanting to get everyone to read these pages as I had from the section about comments in Kent Beck's &lt;a href="http://www.amazon.com/Smalltalk-Best-Practice-Patterns-Kent/dp/013476904X"&gt;Smalltalk Best Practice Patterns&lt;/a&gt;. I wanted to shout (while shaking people by their lapels) "read this - it's what I've been trying to tell you all this time".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;What I didn't like - examples (particularly Chapter 3)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are some examples that aren't great. The one that stuck out particularly badly was in chapter 3 - HtmlUtil. The problem with HtmlUtil is that it is classic procedural style - which is OK as an example of bad style - but the refactored version does not address that aspect of it's badness.&lt;br /&gt;&lt;br /&gt;This example is a method on HtmlUtil with signature:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;public static String testableHtml(PageData pageData, boolean includeSuiteSetup) throws Exception&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;with lots of methods called on pageData. It gets nicely refactored into a short method of a different name but with the same signature.&lt;br /&gt;&lt;br /&gt;My main problem with this example is that it looks (to someone who doesn't know the codebase that it is taken from) as if this should be a method on PageData. Maybe there is a good reason it is a static method on HtmlUtil but the author doesn't explain whether there is or not. To me it seems like an obvious question and by not mentioning anything about &lt;a href="http://puttingtheteaintoteam.blogspot.com/2008/10/utils-classes-and-nojos.html"&gt;Utils&lt;/a&gt; with static methods that do things to &lt;a href="http://ivan.truemesh.com/archives/000733.html"&gt;objects that should be quite capable of doing stuff for themselves&lt;/a&gt;, it shows an example of arguably bad code, early on, with no explanation or apology for using such an example. I assume that they wanted to focus only on procedural refactoring for the example and deliberately wanted to avoid anything object-oriented - but if so, they should have said that very clearly.&lt;br /&gt;&lt;br /&gt;The second red flag that this example waved at me was declaring that the method throws Exception. It isn't clear from reading the code that it needs to. Maybe it does, but again I think if it does then the author should have explained why and apologised for that aspect of the example.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;What I didn't like - Structured Programming (Chapter 3)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the (very short) section on Structured Programming there is a claim for the rules of structured programming; "It is only in larger functions that such rules provide significant benefit." I almost screamed at my fellow passengers on the train into work. My blood pressure is rising as I write this. (Imagine me screaming at the top of my voice - "NO NO NO").&lt;br /&gt;&lt;br /&gt;&lt;a href="http://ivan.truemesh.com/archives/000611.html"&gt;I don't believe there is ANY benefit&lt;/a&gt;, let alone significant benefit, of applying the rules of structured programming to Java code. If there is, then the author should justify their comments rather than invoke the "proof by repeated assertion" that the cargo cult followers will no doubt spout in comments on this article.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;What I liked - formatting (Chapter 5)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Lots of good stuff - I didn't agree with it all but some of it has definitely made me rethink (or in some cases just think) about what I'm doing with formatting more than before.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What I didn't like - Chapter 11 (Systems)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Any chapter which starts with an analogy for building a software system as building a city, has already got off to a bad start as far as I'm concerned. Whenever I hear of such analogies I wonder what &lt;a href="http://en.wikipedia.org/wiki/Swiss_Toni"&gt;Swiss Toni&lt;/a&gt;'s analogy would be. "Building a system is very much like making love to a beautiful woman ..."&lt;br /&gt;&lt;br /&gt;Apart from the analogy - the author then goes on to talk about Spring somewhat implying that it's a Good Thing. Just don't get me started. That's a whole other blog post.&lt;br /&gt;&lt;br /&gt;Nevertheless, despite these things, there is also some good stuff in this chapter.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Overall&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Great. Buy it. It's full of good stuff and only very few things that make my blood boil.&lt;br /&gt;&lt;br /&gt;Copyright © 2008 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-7961105275306293964?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/7961105275306293964/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=7961105275306293964' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7961105275306293964'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7961105275306293964'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/11/in-my-previous-article-i-mentioned-book.html' title=''/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-4735879577402241395</id><published>2008-11-08T08:56:00.000-08:00</published><updated>2008-11-08T09:10:49.879-08:00</updated><title type='text'>Programming in the small - Exceptions</title><content type='html'>It's a long time since I wrote my previous "&lt;a href="http://ivan.truemesh.com/archives/cat_programming_in_the_small.html"&gt;programming in the small&lt;/a&gt;" article. This article is about Exceptions in Java. I've kept it very short just to cover the absolute minimum.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Handle or throw&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What is likely to be wrong with this code?&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    public void makeTea() {&lt;br /&gt;        teaPot.prepare();&lt;br /&gt;        try {&lt;br /&gt;            kettle.boil();&lt;br /&gt;        } catch (ElectricityCutOffException e) {&lt;br /&gt;            LOGGER.log("Didn't pay bill; no tea today.");&lt;br /&gt;        }&lt;br /&gt;        kettle.pourContentsInto(teaPot);&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Logging that some exception has been thrown is not handling it. In this case, "pourContentsInto" will still be called even if "boil" threw an exception. The exception indicates a problem, and to keep executing will probably mean that the system is in an unknown, inconsistent or bad state.&lt;br /&gt;&lt;br /&gt;In this case, I'll end up with cold water in the teaPot, ruining the tea in an unrecoverable way.&lt;br /&gt;&lt;br /&gt;In many cases, catching an exception and not handling it causes bugs which are tediously difficult to track down because the system ends up in an inconsistent state and the exception that eventually causes the system to fail, or the error in its functionality, ends up being somewhere that looks completely unrelated to the code that caused the problem by hiding the exception.&lt;br /&gt;&lt;br /&gt;If this method is a sensible place to fully handle the exception, then it should do that. For example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    public void makeTea() {&lt;br /&gt;        teaPot.prepare();&lt;br /&gt;        try {&lt;br /&gt;            kettle.boil();&lt;br /&gt;            kettle.pourContentsInto(teaPot);&lt;br /&gt;        } catch (ElectricityCutOffException e) {&lt;br /&gt;            butler.sendToTeaShop();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If it can't handle the exception (I don't have a butler), then the best thing is to just let the exception percolate up to the calling code to either handle or throw, that is:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    public void makeTea() throws ElectricityCutOffException {&lt;br /&gt;        teaPot.prepare();&lt;br /&gt;        kettle.boil();&lt;br /&gt;        kettle.pourContentsInto(teaPot);&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now calling code has to either handle or throw the exception.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Do NOT declare an exception that a method does not throw&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you declare that a method throws a checked exception that it cannot actually throw, then you are condemning callers to having to handle or throw an exception that cannot happen - percolating unnecessary try/catch code around the system. Don't do it.&lt;br /&gt;&lt;br /&gt;For a method which implements or overrides a method of an interface or superclass which declares that it throws an exception, do not make it also declare that it throws that exception unless it actually does.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Unchecked exceptions and more&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I have recently read "&lt;a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882"&gt;Clean Code&lt;/a&gt;" - I &lt;span style="font-weight:bold;"&gt;really &lt;/span&gt;like the first chapter - worth buying just for that. There is a chapter on exceptions, in which &lt;a href="http://www.michaelfeathers.com/"&gt;Michael Feathers&lt;/a&gt; writes about the use of unchecked exceptions and other things. I'm not going to write more myself - buy "Clean Code" instead.&lt;br /&gt;&lt;br /&gt;If you are too cheap to buy "Clean Code" or have read it and want a different opinion, then read my "&lt;a href="http://ivan.truemesh.com/archives/cat_programming_in_the_small.html"&gt;programming in the small&lt;/a&gt;" articles which cover some of the same ground (in some cases better, in some cases worse, and not a complete intersection of topics - in particular there is more stuff covered&lt;br /&gt;in "Clean Code").&lt;br /&gt;&lt;br /&gt;Copyright © 2008 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-4735879577402241395?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/4735879577402241395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=4735879577402241395' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/4735879577402241395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/4735879577402241395'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/11/programming-in-small-exceptions.html' title='Programming in the small - Exceptions'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-808420848918119807</id><published>2008-11-02T03:48:00.000-08:00</published><updated>2008-11-02T03:59:34.195-08:00</updated><title type='text'>Why are NOJOs so popular?</title><content type='html'>Following on from my previous articles on &lt;a href="http://puttingtheteaintoteam.blogspot.com/2008/10/is-that-pojo-or-nojo.html"&gt;NOJOs&lt;/a&gt; and their frequent complements, &lt;a href="http://puttingtheteaintoteam.blogspot.com/2008/10/utils-classes-and-nojos.html"&gt;Utils classes&lt;/a&gt;, I have talked to colleagues about why NOJOs are so popular in enterprise Java development.&lt;br /&gt;&lt;br /&gt;Here I will try to write up some of the ideas we discussed (thanks to Mike Hill, Nat Pryce, Pippa Newbold, Rob Dupuis and Tung Mac).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Education by frameworks&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A lot of the early examples in the &lt;a href="http://static.springframework.org/spring/docs/2.5.x/reference"&gt;Spring documentation&lt;/a&gt; are NOJOs. For example, on the page that introduces &lt;a href="http://static.springframework.org/spring/docs/2.5.x/reference/beans.html"&gt;The IoC container&lt;/a&gt; there are several (here's one):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package examples;&lt;br /&gt;&lt;br /&gt;public class ExampleBean {&lt;br /&gt;&lt;br /&gt;  // No. of years to the calculate the Ultimate Answer&lt;br /&gt;  private int years;&lt;br /&gt;&lt;br /&gt;  // The Answer to Life, the Universe, and Everything&lt;br /&gt;  private String ultimateAnswer;&lt;br /&gt;&lt;br /&gt;  public ExampleBean(int years, String ultimateAnswer) {&lt;br /&gt;      this.years = years;&lt;br /&gt;      this.ultimateAnswer = ultimateAnswer;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Similarly, have a look at the &lt;a href="http://en.wikipedia.org/wiki/JavaBeans"&gt;JavaBeans on wikipedia&lt;/a&gt; - PersonBean.java is a NOJO. I think that there are a lot of developers who think that JavaBeans are NOJOs - as indicated by one of the comments on my NOJO article.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Fear of using the framework incorrectly (the framework won't like it)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It is possible that developers think that the early examples are the "correct" way to use such frameworks - and are worried that if they add methods to their NOJO then the framework will do something peculiar. This isn't &lt;span style="font-style: italic;"&gt;entirely &lt;/span&gt;unreasonable as sometimes such frameworks do unexpected things due to the amount of behind-the-scenes-magic going on.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Fear of using the framework incorrectly (my colleagues won't like it)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another possible fear is that that the early examples are the "correct" way to use such frameworks - and doing anything else is not how the framework is intended to be used (even though the framework seems to still work).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Separation of concerns&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another fear is that of putting the behaviour in the wrong place - in particular in enterprise Java projects, I think there is a perception that there is no worse "crime" than putting behaviour in the wrong "layer" (or the wrong sort of class). Therefore, rather than risk putting the behaviour on the wrong object in the right layer, enterprise Java developers will choose to put the behaviour on the wrong class in the right layer. Related to this is a desire to stick to some prescribed pattern - e.g. DTOs. I have been in a situation when pair programming with someone where I was told, "you can't add a method to that" followed by some lame reasoning justified by some pattern that they wanted to stick to religiously.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Afraid of "new"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Yet another fear is that you might have to create a new object (shock, horror!). To avoid that, maybe some developers prefer to write static methods on some Utils class so they don't need to create any objects?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Object-oriented programming education and thinking&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Perhaps the popularity of NOJOs is just the manifestation of how developers (don't) learn object-oriented programming? Perhaps object-oriented programming simply doesn't suit how all developers think? Certainly, I've come across very good developers who prefer functional programming and don't really "get" object-oriented programming, so it's not meant to be a criticism (or at least, not in all cases). Many developers have learnt their programming from non object-oriented programming languages, like C. Perhaps it's not suprising that to a C programmer an object looks like a struct?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Intra-team APIs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another source of NOJO programming is that the APIs that people design for communicating between team's subsystems often involve setting up, sending and receiving NOJOs.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Automated Testing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another possibility is that developers who are not used to TDD find writing tests that use NOJOs easier than, for example, using Mock Objects.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;UML&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Using UML to "design" a system up front encourages thinking about the fields of objects rather than their behaviour - because that's what is easiest in notions like UML.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;IDEs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Java IDEs can do lots of good things. One of the arguably less good things they do is generate getters and setters if you want. It is possible that the easy generation of getters and setters encourages their use, leading to NOJOs rather than objects that do things with their own fields. Using setter injection (probably the most common way people use Spring) also tempts developers into generating the getters too - after all, it's probably an extra click to not generate getters and what harm can some getters do? (Rhetorical).&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Should I care that NOJOs are popular? Should I do anything about it?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Left as an exercise for the reader.&lt;br /&gt;&lt;br /&gt;Copyright © 2008 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-808420848918119807?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/808420848918119807/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=808420848918119807' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/808420848918119807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/808420848918119807'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/11/why-are-nojos-so-popular.html' title='Why are NOJOs so popular?'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-6151160268203575233</id><published>2008-10-24T14:31:00.000-07:00</published><updated>2008-10-24T14:40:17.178-07:00</updated><title type='text'>Utils classes and NOJOs</title><content type='html'>A style of class that is a frequent complement to NOJOs &lt;a href="http://puttingtheteaintoteam.blogspot.com/2008/10/is-that-pojo-or-nojo.html"&gt;(introduced in my previous article)&lt;/a&gt; are classes with only static methods. They might be called SomethingUtil or SomethingHelper.&lt;br /&gt;&lt;br /&gt;People will often know what you mean if you say "a Utils" class, so I won't propose anything different here. I had wanted to propose a catchier name - SOJOs (Static Only Java Object) but the acronym (with a completely different meaning) is already taken by the &lt;a href="http://sojo.sourceforge.net/"&gt;SOJO project&lt;/a&gt;. In a comment on my NOJO article, John Q Public said he uses the term "function buckets" and I'm sure he's talking about the same thing.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Why do people write Utils classes?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you have NOJOs then your methods have got to go somewhere. People who prefer the NOJO style often like to create static methods on Utils classes for those methods.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Are Utils classes a Good Thing?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Again, left as an exercise for the reader. An &lt;a href="http://ivan.truemesh.com/archives/000733.html"&gt;article from my old blog&lt;/a&gt; might help to hint about my views (although it is not specifically about this subject) without me having to stay up all night writing more. It seems like people aren't shy about expressing their opinions in comments - some of which I completely agree with, so I'll leave it as an exercise for comment writers as well as the reader (cheeky, I know).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;In defence of my previous article&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I didn't make any judgements in my previous article - mostly through lack of time but also because I want the term NOJO to be understood without being confused with whether it's any good or not. I am merely making an observation and suggesting a name for a thing I see frequently, that is poorly served by current names. I found it interesting how many people suggested that there was already a term for NOJO but none of their suggestions were entirely accurate.&lt;br /&gt;&lt;br /&gt;Copyright © 2008 Ivan Moore&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-6151160268203575233?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/6151160268203575233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=6151160268203575233' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/6151160268203575233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/6151160268203575233'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/10/utils-classes-and-nojos.html' title='Utils classes and NOJOs'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-7072838114183902365</id><published>2008-10-23T14:10:00.000-07:00</published><updated>2008-10-23T14:17:38.728-07:00</updated><title type='text'>Is that a POJO or a NOJO?</title><content type='html'>The term "&lt;a href="http://www.martinfowler.com/bliki/POJO.html"&gt;POJO&lt;/a&gt;" is widely used in the Java programming world, but is sometimes used to mean something more specific than what was originally intended.&lt;br /&gt;&lt;br /&gt;Furthermore, such code (whether called POJO or not by its authors) is a style which I think would be useful to give a specific name to.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;What's a POJO?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The original meaning of POJO was a plain old Java object - that is, an object that isn't tied to a framework (for example, having to implement specific interfaces). A concrete example of a &lt;span style="font-weight: bold;"&gt;non-POJO&lt;/span&gt; would be entity beans (from EJB).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Introducing NOJOs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;NOJOs are (instances of) classes which define fields, setters and getters but no other methods. They are popular in enterprise Java code and I think deserve a specific term, to distinguish them from the rather general term POJO.&lt;br /&gt;&lt;br /&gt;NOJO stands for "Non Object-oriented Java Object". Although it might sound "negative" it is merely intended to be accurate and have a catchy acronym.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;What defines an object?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;An "&lt;a href="http://en.wikipedia.org/wiki/Object_%28computer_science%29"&gt;object&lt;/a&gt;" (in object-oriented programming) has identity, state and behaviour. A NOJO has identity and state. A function has behaviour but not state. An object has identity, state and behaviour.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Why do you need a term for NOJO?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In many programming languages, there is a language construct for NOJOs (or something very similar) - e.g. "struct" in C, or "record" in Pascal. In Java there isn't an equivalent language construct - so the term NOJO is intended to mean the use of a Java class to implement such a thing, to make it easier to talk about such code.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Are NOJOs a Good Thing?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Left as an exercise for the reader.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-7072838114183902365?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/7072838114183902365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=7072838114183902365' title='25 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7072838114183902365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/7072838114183902365'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/10/is-that-pojo-or-nojo.html' title='Is that a POJO or a NOJO?'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>25</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4084458860381242516.post-3800302095371684474</id><published>2008-10-12T06:49:00.000-07:00</published><updated>2008-10-12T07:07:44.307-07:00</updated><title type='text'>Blog moved here</title><content type='html'>&lt;span style="font-family:arial;"&gt;&lt;a href="http://joe.truemesh.com/blog/"&gt;Joe Walnes&lt;/a&gt;, the best developer I've ever worked with, got me started blogging (many thanks Joe) by hosting &lt;a href="http://ivan.truemesh.com/"&gt;my blog on his server&lt;/a&gt;. Now the time has come for him to retire his server, and so my blog has moved &lt;a href="http://puttingtheteaintoteam.blogspot.com/"&gt;here&lt;/a&gt;. I'll be writing more articles soon - I've got a backlog of &lt;/span&gt;&lt;a style="font-family: arial;" href="http://ivan.truemesh.com/archives/cat_programming_in_the_small.html"&gt;programming in the small&lt;/a&gt;&lt;span style="font-family:arial;"&gt; ideas to write up - but have been very busy with work, being (co) programme chair of &lt;/span&gt;&lt;a style="font-family: arial;" href="http://www.spaconference.org/spa2009/index.php"&gt;my favourite conference (SPA)&lt;/a&gt;&lt;span style="font-family:arial;"&gt;, &lt;/span&gt;&lt;a style="font-family: arial;" href="http://build-o-matic.sourceforge.net/"&gt;build-o-matic&lt;/a&gt;&lt;span style="font-family:arial;"&gt; and just trying to keep up with the world.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4084458860381242516-3800302095371684474?l=puttingtheteaintoteam.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://puttingtheteaintoteam.blogspot.com/feeds/3800302095371684474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4084458860381242516&amp;postID=3800302095371684474' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3800302095371684474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4084458860381242516/posts/default/3800302095371684474'/><link rel='alternate' type='text/html' href='http://puttingtheteaintoteam.blogspot.com/2008/10/blog-moved-here.html' title='Blog moved here'/><author><name>Ivan Moore</name><uri>http://www.blogger.com/profile/09119134602348298270</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
