<?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-3215278939917454572</id><updated>2011-07-30T19:14:20.234+01:00</updated><category term='iWork'/><category term='Python'/><category term='Google Maps'/><category term='tools'/><category term='XP'/><category term='Remote'/><category term='Story Wall'/><category term='Ramaze'/><category term='MacBook Pro'/><category term='macs'/><category term='Windows'/><category term='conference'/><category term='Font'/><category term='train'/><category term='Web'/><category term='Shell'/><category term='bose'/><category term='trains'/><category term='log files'/><category term='monitor'/><category term='Mac'/><category term='W850i'/><category term='video'/><category term='performance'/><category term='Sony Ericsson'/><category term='Paring'/><category term='code'/><category term='review'/><category term='c++'/><category term='ant'/><category term='java'/><category term='refactoring'/><category term='Distributed'/><category term='programming'/><category term='deployment'/><category term='Sloth'/><category term='Functional Testing'/><category term='book'/><category term='Small is Beautiful'/><category term='wordpress'/><category term='cruisecontrol.rb'/><category term='Virtualisation'/><category term='flying'/><category term='Syntax'/><category term='Agile'/><category term='build'/><category term='coaching'/><category term='wireless'/><category term='Ruby'/><category term='FitNesse'/><category term='scmrss'/><category term='agile2008'/><category term='design'/><category term='Patterns'/><category term='modeling'/><category term='blogging'/><category term='TED'/><category term='talks'/><category term='subversion'/><title type='text'>Crafting Software</title><subtitle type='html'>Musings on software and software development</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>55</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-5032675362152236326</id><published>2010-06-20T02:48:00.001+01:00</published><updated>2010-06-20T02:49:45.702+01:00</updated><title type='text'></title><content type='html'>For anyone following this blog I have been doing most of my posts here &lt;a href="http://www.grahambrooks.com/blog"&gt;www.grahambrooks.com/blog&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-5032675362152236326?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/5032675362152236326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=5032675362152236326' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/5032675362152236326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/5032675362152236326'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2010/06/for-anyone-following-this-blog-i-have.html' title=''/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-8148959210023124837</id><published>2009-04-30T09:21:00.001+01:00</published><updated>2009-04-30T09:21:26.750+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><title type='text'>Programming in the small</title><content type='html'>A personal quick reminder of these excellent blog entries.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://ivan.truemesh.com/archives/cat_programming_in_the_small.html"&gt;http://ivan.truemesh.com/archives/cat_programming_in_the_small.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-8148959210023124837?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/8148959210023124837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=8148959210023124837' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/8148959210023124837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/8148959210023124837'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2009/04/programming-in-small.html' title='Programming in the small'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-1560534078901913679</id><published>2009-04-03T15:00:00.001+01:00</published><updated>2009-04-03T15:04:00.709+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video'/><category scheme='http://www.blogger.com/atom/ns#' term='coaching'/><category scheme='http://www.blogger.com/atom/ns#' term='TED'/><category scheme='http://www.blogger.com/atom/ns#' term='talks'/><title type='text'>John Wooden: Coaching for people, not points</title><content type='html'>I came across this really interesting talk by John Wooden about his coaching career and the measurement of success. Although the focus is basketball it is remarkable how many thoughts have relevance to other walks and works of life.&lt;br /&gt;&lt;br /&gt;"Success is peace of mind attained only through self-satisfaction in knowing that you made the effort to do the best of which you are capable."&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ted.com/talks/view/id/498"&gt;View the talk on TED&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width="334" height="326"&gt;&lt;param name="movie" value="http://video.ted.com/assets/player/swf/EmbedPlayer.swf"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;param name="bgColor" value="#ffffff"&gt;&lt;/param&gt; &lt;param name="flashvars" value="vu=http://video.ted.com/talks/embed/JohnWooden_2001-embed_high.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/JohnWooden-2001.embed_thumbnail.jpg&amp;vw=320&amp;vh=240&amp;ap=0&amp;ti=498" /&gt;&lt;embed src="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" pluginspace="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" wmode="transparent" bgColor="#ffffff" width="334" height="326" allowFullScreen="true" flashvars="vu=http://video.ted.com/talks/embed/JohnWooden_2001-embed_high.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/JohnWooden-2001.embed_thumbnail.jpg&amp;vw=320&amp;vh=240&amp;ap=0&amp;ti=498"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-1560534078901913679?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/1560534078901913679/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=1560534078901913679' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1560534078901913679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1560534078901913679'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2009/04/john-wooden-coaching-for-people-not.html' title='John Wooden: Coaching for people, not points'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-8534296040726086717</id><published>2009-03-01T16:07:00.001Z</published><updated>2009-03-01T16:07:21.789Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='deployment'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><title type='text'>Think about change</title><content type='html'>Over the last few years I have noticed a growing trend in software developers to constrain their thinking to static models.&lt;br /&gt;&lt;br /&gt;Static thinking is a great way of envisioning a system and we have many tools to support modelling systems in this way - class, deployment, network diagrams all fall into this category. But all these models are about a single state of the system - either historical, real (current) or imaginary (future).&lt;br /&gt;&lt;br /&gt;However many projects involve more difficult thinking. Typically these difficulties involve moving from one state to another and the most complex of these is migrating from one version of a system to another.&lt;br /&gt;&lt;br /&gt;It is at this point that I struggle to find an effective model that captures this transition. How do we model and capture the upgrade of a database, application and infrastructure requirements. And further these transitions occur at different times and are typically not instantaneous which can mean that the service is not available. How do we model this sequence of events so we can understand the effect of our evolving software design on the rolling out the new software.&lt;br /&gt;&lt;br /&gt;Quite often these rollout plans are written down (impact analysis, rollout network models, sequence diagrams, flow charts) and held in the minds of the project team. But these models are not easily tested. Organisations with a significant investment in their live environment often struggle to replicate that environment to allow the model and plans to be tested before hitting the production environment.&lt;br /&gt;&lt;br /&gt;I think finding an effective tool to model and execute software updates will be one of the key challenges for this decade - as it has for the last two.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-8534296040726086717?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/8534296040726086717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=8534296040726086717' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/8534296040726086717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/8534296040726086717'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2009/03/think-about-change.html' title='Think about change'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-3922588005353387550</id><published>2009-02-19T18:32:00.001Z</published><updated>2009-02-19T18:32:43.110Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='macs'/><category scheme='http://www.blogger.com/atom/ns#' term='train'/><category scheme='http://www.blogger.com/atom/ns#' term='trains'/><title type='text'>Macs on trains</title><content type='html'>On my current project I am travelling more that usual, mostly by train between London and the North West. The journey time is pretty manageable and the service (so far this year) has been pretty good leaving and arriving on time.&lt;br /&gt;&lt;br /&gt;The thing that struck me today was the number of Macs in coach B. Of the 10 computers in used well over half were macs. I remember some time ago that macs were a rarity for train travellers but no more. Ok most of them were MacBooks and not the shiny new aluminium ones but the trend was quite startling.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-3922588005353387550?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/3922588005353387550/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=3922588005353387550' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3922588005353387550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3922588005353387550'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2009/02/macs-on-trains.html' title='Macs on trains'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-1522332039180246622</id><published>2009-01-18T11:53:00.001Z</published><updated>2009-01-18T13:46:39.256Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='review'/><category scheme='http://www.blogger.com/atom/ns#' term='book'/><title type='text'>The Designful Company</title><content type='html'>&lt;h1&gt;&lt;a href="http://www.amazon.com/Designful-Company-culture-nonstop-innovation/dp/0321580060/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1232279338&amp;sr=8-1"&gt;The Designful Company&lt;/a&gt; by Marty Neumeier&lt;/h1&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I have to confess that when it comes to reading books related to work I have a short attention span. For technical books I tend to skim through the text and examples until I get a 'feel' for the content. Most of the time this is sufficient, after all if I need more details I can come back to the book and dig into them. The most important thing for me is to have a high level view of the technology and to know were to get more information.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So when it came to reading 'The Designful Company' by Marty Neumeier I kicked off with my usual skimming approach - but quickly found myself changing tack and putting my novel hat on - reading every word!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Quoting &lt;a href="http://en.wikipedia.org/wiki/Thomas_Aquinas"&gt;Thomas Aquinas&lt;/a&gt; "Ad pulcritudenum tria requiruntur integritas, consonantia, claritas". Design requires 3 qualities&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;integrity&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;harmoney&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;radiance&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;Reading this I was struck by the thought that these are the things I am looking for in the architecture and design of a software system.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In fact many of the ideas presented by the book (intended for a wide variety of companies) resonate with current agile software development trends.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The bit on agility (p21) brought a smile to my face&lt;/p&gt;&lt;br /&gt;&lt;p&gt;'The Designful Company' is an easy thought provoking read. Presenting a strong argument for corporate adoption of design to drive growth in the 21 century.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Given my reading habbits it also helps that the book is small and layed out well with large print.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;It may be just me but I am seeing a convergence in thinking across many different disciplines - or maybe software development practitioners are still learning from others.&lt;/p&gt;				   &lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-1522332039180246622?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/1522332039180246622/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=1522332039180246622' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1522332039180246622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1522332039180246622'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2009/01/designful-company.html' title='The Designful Company'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-9034590887972866382</id><published>2008-12-21T17:29:00.001Z</published><updated>2008-12-21T17:29:27.943Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='scmrss'/><category scheme='http://www.blogger.com/atom/ns#' term='Ramaze'/><title type='text'>SCMRSS reaches Alpha 1 release</title><content type='html'>&lt;p&gt;&lt;a href="http://rubyforge.org/projects/scmrss/"&gt;SCMRSS&lt;/a&gt; is a simple web application that turns Source Control events into an RSS feed. Written in Ruby using the &lt;a href="http://ramaze.net/"&gt;Ramaze&lt;/a&gt; web framework. Once configured the web server polls the source control repository for changes and when found delivers those changes as a simple RSS feed.&lt;/&gt;&lt;br /&gt;&lt;p&gt;This is the first alpha release so I would welcome any and all feedback either here or as issues at RubyForge&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-9034590887972866382?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/9034590887972866382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=9034590887972866382' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/9034590887972866382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/9034590887972866382'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/12/scmrss-reaches-alpha-1-release.html' title='SCMRSS reaches Alpha 1 release'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-4155182094959872349</id><published>2008-12-20T13:33:00.001Z</published><updated>2009-01-06T20:40:46.604Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Paring'/><category scheme='http://www.blogger.com/atom/ns#' term='Distributed'/><category scheme='http://www.blogger.com/atom/ns#' term='XP'/><category scheme='http://www.blogger.com/atom/ns#' term='Remote'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Remote Pair Programming setup</title><content type='html'> &lt;br /&gt;&lt;p&gt;For a few years now I have been looking for a solution that allows two or more people to share an editing session who are not sat side by side.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Each OS has its own preferred way of sharing a desctop/workspace for collaborative working. Some work cross platform (e.g. VNC) and some work via the internet (e.g. &lt;a href="http://www.gotomypc.com"&gt;GoToMyPC&lt;/a&gt;). But for much of my daily work I want a nice fast way of sharing the code that I am working on with a collegue. One or both of us are likely to be behind firewalls, proxies and all sort of important security that makes collaborative remote working so very very hard.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;On my current project we are using Eclipse as our development IDE, a local IRC server for ad-hoc team communication and point to point instant messaging. Backed up by Skype for person to person video and occasionaly more traditional email and phone for that personal touch.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;All in all this is working fiine and I have to admit I had forgotten how useful IRC is in comparison to IM when it comes to team working. Just having everyone aware of the conversations that are taking place can be a real boon.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I had some spare time last evening and decided to see if I could track down a viable solution to the remote pair programming. Confining my requirements to either complete desktop sharing or Eclipse based paring helped quite a bit because the other added complication is that we have a mixed OS development team including Windows, Linux and Mac OS X. The number of OSs is likely to settle down to just two but at the moment we have quite a mixed bag - which is actually quite refreshing.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So back to the remote pairing issue. I quickly realised that sharing the editing session is likely to be sufficient to our needs and that other tools could provide text, voice and video quite effectively and did not need to be replaced.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;My first efforts involved the Eclipse Communication Framework (ECF). I had played about with much earlier versions and concluded that it was a little fussy and difficult to work with for my tastes but decided to give it a go. Working behind a proxy with limited ports meant setting up and running a local server.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I can see a lot of promise in the ECF but it just feels far to heavy weight. I might have made some errors but I could not get it to work, connecting to the server seemed ok (although there were a lot of stack backtraces on startup - now I really cant understand why people still dump these things to the console with the idea that users - even developer users will have a hope of understanding what went wrong. With 3 pages of small text flying past it is just too easy to spot the line that tells you what when wrong. So after an unhappy hour or two trying to get two instances of Eclipse to open a shared editing setting I gave up and went back to searching for alternative.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;After a little bit more searching I cam up with &lt;a href="http://xpairtise.sourceforge.net/"&gt;XPairtise&lt;/a&gt; and open source project that seemed to do exactly what I now wanted - share an editing session. Unusually for an open source project the documentation is pretty good although it was early in the morning and I almost missed that there are two downloads; one for the eclipse plugin and the other for the server.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The setup which I eventually came up with involved the XParitise server and Eclipse running natively on my Mac and a Ubuntu VM mimicing a remote pair. The server is nice and quiet just reporting that it is up and running - a refreshing change. After setting up accounts through the Eclipse preferences pane (a little quirky on the UI the first time around) but it was heart warming to receive the 'account created' message.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Getting the shared editing session to work took some time. First when creating a shared workspace all the files from the project are shipped up to the server. When joining the shared workspace again the project files are brought down so take heed of the backup dialog or work in a different Eclipse workspace for shared working.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;It took at least 2 Eclipse restarts to get the shared editing to work and there is a note on the XPairtise site about using the eclipse -clean option to refresh all the plug-ins&lt;/p&gt;&lt;br /&gt;&lt;p&gt;But after this initial setup headache I have a configuration that will allow remote pair programming.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Result!!&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I have just rerun the setup within a distributed team (2 locations) and after a bit of a lag in synchronising the project contents everything worked fine with 3 concurrent users (Driver, Navigator and Spectator).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-4155182094959872349?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/4155182094959872349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=4155182094959872349' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4155182094959872349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4155182094959872349'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/12/remote-pair-programming-setup.html' title='Remote Pair Programming setup'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-1844376525838592576</id><published>2008-10-05T11:41:00.001+01:00</published><updated>2008-10-05T11:41:59.214+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Font'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='Shell'/><title type='text'>Setting Windows Shell Font</title><content type='html'>I keep loosing track of this little tidbit&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont" /v 00 /d Consolas&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;logoff&lt;br /&gt;&lt;br /&gt;The full article can be found here &lt;a href="http://blogs.msdn.com/ie/archive/2008/04/22/give-your-eyes-a-treat.aspx"&gt;http://blogs.msdn.com/ie/archive/2008/04/22/give-your-eyes-a-treat.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-1844376525838592576?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/1844376525838592576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=1844376525838592576' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1844376525838592576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1844376525838592576'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/10/setting-windows-shell-font.html' title='Setting Windows Shell Font'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-7825757357083950517</id><published>2008-10-04T21:40:00.001+01:00</published><updated>2008-10-04T21:40:21.895+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Timewarp</title><content type='html'>About a month ago I was asked to look at an application that has been&lt;br /&gt;under active development and support for quite some time. Written in C&lt;br /&gt;and C++ (my old stomping grounds for 20 years) I was really looking&lt;br /&gt;forward to getting stuck into the code.&lt;br /&gt;&lt;br /&gt;What I was not expecting was the lack of tool support. I sort of knew&lt;br /&gt;that refatoring tools, tests and code coverage would be a bit of a&lt;br /&gt;challenge but I did not think that it would be the challenge that it&lt;br /&gt;turned out to be.&lt;br /&gt;&lt;br /&gt;I have gotten used to being able to download tools, try them out and&lt;br /&gt;if appropriate buy them and add them to my toolbox. Ideally there&lt;br /&gt;would be an open source tool I could use instead to get the job&lt;br /&gt;done. Moving back into the C++ world also took me back in time to an&lt;br /&gt;era where evaluation downloads are not available. Instead I would have&lt;br /&gt;to register my interest and someone would be in touch to talk to me&lt;br /&gt;about the wonders of their application and to perhaps run the&lt;br /&gt;application over my source code. Well first I tend to get about a bit&lt;br /&gt;and at the time I was out of my home country and well away from the&lt;br /&gt;tool vendors timezone. I was up against the clock in putting together&lt;br /&gt;some initial findings and recommendations, and lastly it was not my&lt;br /&gt;source code so I could not offer it up to someone else to go poking&lt;br /&gt;around in anyway.&lt;br /&gt;&lt;br /&gt;Strike one - keep on searching for someone with a little less of a&lt;br /&gt;protectionist attitude.&lt;br /&gt;&lt;br /&gt;Unfortunately this seemed to become a theme. Other suppliers had no&lt;br /&gt;evaluations and insisted on money up front and land shipping. In a way&lt;br /&gt;they may have been doing me a favour, if the software is so complex&lt;br /&gt;that it needs to be demonstrated and the licencing enforcement so&lt;br /&gt;strong that it becomes difficult to use (I have been hit before by&lt;br /&gt;node locked liceses to machines that decide to die) then maybe this&lt;br /&gt;approach has just saved me a lot of heart ache and pain.&lt;br /&gt;&lt;br /&gt;On the plus side there are tools out in 'open source' land that can&lt;br /&gt;help and there *are* a few companies that have moved with the times&lt;br /&gt;and provide a more open licensing scheme. When I have time I will list&lt;br /&gt;out the toolkit that I came up with.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-7825757357083950517?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/7825757357083950517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=7825757357083950517' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7825757357083950517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7825757357083950517'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/10/timewarp.html' title='Timewarp'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-5871249317910112856</id><published>2008-09-25T16:55:00.001+01:00</published><updated>2008-09-25T16:55:52.238+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtualisation'/><title type='text'>Too many VMs</title><content type='html'>As part of my work life I regularly need to run windows development software on my Mac. Typically for a client engagement. This is a really convenient setup. I can take a snapshot before I start work on something new and then at the end roll back to the original state ready to work on the next project.&lt;br /&gt;&lt;br /&gt;One of the downsides I have encountered recently is the need to keep all these machines up to date with patches and other software updates that seem to be part of everyday life.&lt;br /&gt;&lt;br /&gt;Don't get me wrong I think its great that we have this steady stream of updates to make things better but when you start multiplying this up for the VMs I have on my machine the effort to keep them up to date starts to be become a bit of a pain.&lt;br /&gt;&lt;br /&gt;I think it is time to start rationalising to a smaller number - just so I can keep them up to date.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-5871249317910112856?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/5871249317910112856/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=5871249317910112856' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/5871249317910112856'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/5871249317910112856'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/09/too-many-vms.html' title='Too many VMs'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-4950490896094030424</id><published>2008-08-04T01:41:00.001+01:00</published><updated>2008-08-04T01:41:23.819+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flying'/><category scheme='http://www.blogger.com/atom/ns#' term='bose'/><title type='text'>Quietly Does it</title><content type='html'>&lt;table&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;img src="http://www.bose.com/images/home_entertainment/products/p_qc3_m.jpg"/&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      I have had my eye on a pair of &lt;a href="http://www.bose.com"&gt;Bose&lt;/a&gt; headphones for some time but never managed to justify the cost. And to be honest I am not sure that I ever will. Except that they are truly fabulous and on my first tip with them on a plane left me feeling relaxed and comfortable. The noise onboard a plane seem to raise my tension levels but removing that noise really helped me enjoy the flight.&lt;br/&gt;&lt;br /&gt;I was told when I bought them that the batteries were fully charged and would each last 10 hours. I can only testify to 8 on one battery with almost continuous use.&lt;br/&gt;&lt;br /&gt;I will confess that I have tried a number of different headphones, both in and out of ear, with and without noise cancelling but nothing comes close to the peace that these phones bring with them.&lt;br/&gt;So maybe I have justified them :)&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-4950490896094030424?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/4950490896094030424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=4950490896094030424' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4950490896094030424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4950490896094030424'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/08/quietly-does-it.html' title='Quietly Does it'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-4254199539283526124</id><published>2008-08-04T01:16:00.001+01:00</published><updated>2008-08-04T01:16:35.221+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='agile2008'/><title type='text'>Toronto - Sunday</title><content type='html'>&lt;br /&gt;&lt;table&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;img src="http://lh5.ggpht.com/wookie870/SJZJVZE17HI/AAAAAAAAAEM/W8gVq-Myx4s/DSC00146.JPG?imgmax=800" alt="DSC00146.JPG" border="0" width="116" height="155" /&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;p&gt;&lt;br /&gt;        Today is my first day in Toronto, preparing for &lt;a href="http://www.agile2008.org"&gt;Agile 2008&lt;/a&gt;. After a surprisingly smooth and peaceful crossing from the UK, and an even smoother journey to downtown Toronto I find myself preparing some slides for my short experience report 'TeamPace - Keeping the build times down' on Thursday.&lt;br /&gt;      &lt;/p&gt;&lt;br /&gt;      &lt;p&gt;I am staying at the Hilton just across the street from the conference at the Sheraton Centre for an early morning start.&lt;/p&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-4254199539283526124?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/4254199539283526124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=4254199539283526124' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4254199539283526124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4254199539283526124'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/08/toronto-sunday.html' title='Toronto - Sunday'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/wookie870/SJZJVZE17HI/AAAAAAAAAEM/W8gVq-Myx4s/s72-c/DSC00146.JPG?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-3568404576031494648</id><published>2008-08-01T21:35:00.001+01:00</published><updated>2008-08-01T21:35:51.844+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wordpress'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Code is Poetry</title><content type='html'>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"&gt;&lt;br /&gt;&lt;html&gt;&lt;br /&gt;  &lt;head&gt;&lt;br /&gt;    &lt;title&gt;&lt;/title&gt;&lt;br /&gt;  &lt;/head&gt;&lt;br /&gt;  &lt;body&gt;&lt;br /&gt;    &lt;p&gt;&lt;br /&gt;      On a recent visit to the &lt;a href="http://wordpress.org"&gt;Wordpress&lt;/a&gt; sight I was struck by their tag line "Code is poetry". I have been searching for some time for a phrase that would sum up how I feel about well crafted code; code that is easy to understand, read and generally feels 'just right'.&lt;br /&gt;    &lt;/p&gt;&lt;br /&gt;    &lt;p&gt;I am not completely convinced that code is poetry - but it comes pretty close.&lt;/p&gt;&lt;br /&gt;  &lt;/body&gt;&lt;br /&gt;&lt;/html&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-3568404576031494648?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/3568404576031494648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=3568404576031494648' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3568404576031494648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3568404576031494648'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/08/code-is-poetry.html' title='Code is Poetry'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-2608070638222169828</id><published>2008-08-01T21:19:00.001+01:00</published><updated>2008-08-01T21:22:59.329+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='agile2008'/><title type='text'>Agile2008</title><content type='html'>&lt;p&gt;Next week I will be in Toronto for Agile 2008 to present a short experience report, catch up with friends and immerse myself in all things Agile :)&lt;/p&gt;&lt;br /&gt;&lt;a href="http://www.agile2008.org"&gt;&lt;br /&gt;&lt;img src="http://www.agile2008.org/images/Agile2008button.gif" border="0"/&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-2608070638222169828?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/2608070638222169828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=2608070638222169828' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2608070638222169828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2608070638222169828'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/08/agile2008.html' title='Agile2008'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-6628766495574758479</id><published>2008-05-19T15:49:00.001+01:00</published><updated>2008-05-19T16:02:29.439+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='train'/><category scheme='http://www.blogger.com/atom/ns#' term='wireless'/><title type='text'>Trains and WiFi</title><content type='html'>I am just returning from Leeds to London by train with power and free Wireless internet. Ok it is not the fastest link but works well - even for blogging &lt;img src="http://i32.photobucket.com/albums/d19/xdomains/smilies/small/1.gif" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-6628766495574758479?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/6628766495574758479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=6628766495574758479' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/6628766495574758479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/6628766495574758479'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/05/trains-and-wifi.html' title='Trains and WiFi'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-6914666290594806450</id><published>2008-05-13T13:26:00.001+01:00</published><updated>2008-05-13T13:26:46.506+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='monitor'/><title type='text'>Keyboard touching</title><content type='html'>&lt;p&gt;I am definitely with &lt;a href="http://www.codinghorror.com/blog"&gt;Jeff Atwood&lt;/a&gt; on when it is appropriate to &lt;a href="http://www.codinghorror.com/blog/archives/001115.html"&gt;touch monitors&lt;/a&gt; - NEVER.&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-6914666290594806450?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/6914666290594806450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=6914666290594806450' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/6914666290594806450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/6914666290594806450'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/05/keyboard-touching.html' title='Keyboard touching'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-3377018980529808536</id><published>2008-04-29T11:26:00.001+01:00</published><updated>2008-04-29T11:26:41.186+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Further perf ruby, python C++ file reading</title><content type='html'>&lt;p&gt;Following on from the log files article I decided to do some basic perf checks of ruby and python reading text files. The results were a little disapointing - performance was roughly the same, so my ruby log file reading optimisation was complete rot.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Further experimentation required.&lt;/p&gt; &lt;br /&gt;&lt;table border="1"&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;!-- Generator: GNU source-highlight 2.9&lt;br /&gt;by Lorenzo Bettini&lt;br /&gt;http://www.lorenzobettini.it&lt;br /&gt;http://www.gnu.org/software/src-highlite --&gt;&lt;br /&gt;&lt;pre&gt;&lt;tt&gt;&lt;br /&gt;ARGV&lt;font color="#990000"&gt;.&lt;/font&gt;each &lt;b&gt;&lt;font color="#0000FF"&gt;do&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;|&lt;/font&gt; param &lt;font color="#990000"&gt;|&lt;/font&gt;&lt;br /&gt;  cc &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;br /&gt;  File&lt;font color="#990000"&gt;.&lt;/font&gt;new&lt;font color="#990000"&gt;(&lt;/font&gt;param&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;'r'&lt;/font&gt;&lt;font color="#990000"&gt;).&lt;/font&gt;each_line &lt;b&gt;&lt;font color="#0000FF"&gt;do&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;|&lt;/font&gt;line&lt;font color="#990000"&gt;|&lt;/font&gt;&lt;br /&gt;    cc &lt;font color="#990000"&gt;+=&lt;/font&gt; line&lt;font color="#990000"&gt;.&lt;/font&gt;size&lt;br /&gt;  &lt;b&gt;&lt;font color="#0000FF"&gt;end&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;  puts &lt;font color="#FF0000"&gt;"File has #{cc} characters"&lt;/font&gt;&lt;br /&gt;&lt;b&gt;&lt;font color="#0000FF"&gt;end&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;br /&gt;Processing /Users/gcb/work/log-analysis/cc.rb ... created /Users/gcb/work/log-analysis/cc.rb.html&lt;br /&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      Realy simple script - and probably the most obvious - add up the length of all the lines in the file.&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;pre&gt;&lt;br /&gt;      File has 1673435763 characters&lt;br /&gt;&lt;br /&gt;real	0m56.035s&lt;br /&gt;user	0m33.873s&lt;br /&gt;sys	0m3.609s&lt;br /&gt;&lt;br /&gt;      &lt;/pre&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;!-- Generator: GNU source-highlight 2.9&lt;br /&gt;by Lorenzo Bettini&lt;br /&gt;http://www.lorenzobettini.it&lt;br /&gt;http://www.gnu.org/software/src-highlite --&gt;&lt;br /&gt;&lt;pre&gt;&lt;tt&gt;&lt;br /&gt;ARGV&lt;font color="#990000"&gt;.&lt;/font&gt;each &lt;b&gt;&lt;font color="#0000FF"&gt;do&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;|&lt;/font&gt; param &lt;font color="#990000"&gt;|&lt;/font&gt;&lt;br /&gt;  cc &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;br /&gt;  i &lt;font color="#990000"&gt;=&lt;/font&gt; File&lt;font color="#990000"&gt;.&lt;/font&gt;open&lt;font color="#990000"&gt;(&lt;/font&gt;param&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;"r"&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;  &lt;b&gt;&lt;font color="#0000FF"&gt;begin&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;    line &lt;font color="#990000"&gt;=&lt;/font&gt; i&lt;font color="#990000"&gt;.&lt;/font&gt;readline&lt;font color="#990000"&gt;()&lt;/font&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#0000FF"&gt;until&lt;/font&gt;&lt;/b&gt; line&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#0000FF"&gt;nil&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;?&lt;/font&gt;&lt;br /&gt;      cc &lt;font color="#990000"&gt;+=&lt;/font&gt; line&lt;font color="#990000"&gt;.&lt;/font&gt;size&lt;br /&gt;      line &lt;font color="#990000"&gt;=&lt;/font&gt; i&lt;font color="#990000"&gt;.&lt;/font&gt;readline&lt;font color="#990000"&gt;()&lt;/font&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#0000FF"&gt;end&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;  &lt;b&gt;&lt;font color="#0000FF"&gt;rescue&lt;/font&gt;&lt;/b&gt; Exception &lt;font color="#990000"&gt;=&amp;gt;&lt;/font&gt; e&lt;br /&gt;  &lt;b&gt;&lt;font color="#0000FF"&gt;ensure&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;    i&lt;font color="#990000"&gt;.&lt;/font&gt;close&lt;br /&gt;  &lt;b&gt;&lt;font color="#0000FF"&gt;end&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;  puts &lt;font color="#FF0000"&gt;"File has #{cc} characters"&lt;/font&gt;&lt;br /&gt;&lt;b&gt;&lt;font color="#0000FF"&gt;end&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;br /&gt;Processing /Users/gcb/work/log-analysis/cc1.rb ... created /Users/gcb/work/log-analysis/cc1.rb.html&lt;br /&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      Based on previoud observations this one uses the realine method from the IO library but did not affect the performance.&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;pre&gt;&lt;br /&gt;      File has 1673435763 characters&lt;br /&gt;&lt;br /&gt;real	0m55.569s&lt;br /&gt;user	0m35.506s&lt;br /&gt;sys	0m3.451s&lt;br /&gt;&lt;br /&gt;      &lt;/pre&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;!-- Generator: GNU source-highlight 2.9&lt;br /&gt;by Lorenzo Bettini&lt;br /&gt;http://www.lorenzobettini.it&lt;br /&gt;http://www.gnu.org/software/src-highlite --&gt;&lt;br /&gt;&lt;pre&gt;&lt;tt&gt;&lt;b&gt;&lt;font color="#000080"&gt;import&lt;/font&gt;&lt;/b&gt; sys&lt;br /&gt;cc &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;source &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;open&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;sys&lt;font color="#990000"&gt;.&lt;/font&gt;argv&lt;font color="#990000"&gt;[&lt;/font&gt;&lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;])&lt;/font&gt;&lt;br /&gt;&lt;b&gt;&lt;font color="#0000FF"&gt;for&lt;/font&gt;&lt;/b&gt; line &lt;b&gt;&lt;font color="#0000FF"&gt;in&lt;/font&gt;&lt;/b&gt; source&lt;font color="#990000"&gt;:&lt;/font&gt;&lt;br /&gt;  cc &lt;font color="#990000"&gt;+=&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;len&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;line&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;source&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;close&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;()&lt;/font&gt;&lt;br /&gt;&lt;b&gt;&lt;font color="#0000FF"&gt;print&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;'file has '&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; cc&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;' characters'&lt;/font&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;br /&gt;Processing /Users/gcb/work/log-analysis/cc.py ... created /Users/gcb/work/log-analysis/cc.py.html&lt;br /&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      As a benchmark a simple python scrpt - again adding up all the line lengths in the file.&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;pre&gt;&lt;br /&gt;      file has  1673435763  characters&lt;br /&gt;&lt;br /&gt;real	0m53.462s&lt;br /&gt;user	0m23.147s&lt;br /&gt;sys	0m3.781s&lt;br /&gt;&lt;br /&gt;      &lt;/pre&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;!-- Generator: GNU source-highlight 2.9&lt;br /&gt;by Lorenzo Bettini&lt;br /&gt;http://www.lorenzobettini.it&lt;br /&gt;http://www.gnu.org/software/src-highlite --&gt;&lt;br /&gt;&lt;pre&gt;&lt;tt&gt;&lt;b&gt;&lt;font color="#000080"&gt;#include&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;&amp;lt;stdio.h&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font color="#009900"&gt;int&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;main&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#009900"&gt;int&lt;/font&gt; argc&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#009900"&gt;char&lt;/font&gt;&lt;font color="#990000"&gt;**&lt;/font&gt; argv&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;&lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;  &lt;font color="#009900"&gt;int&lt;/font&gt; count &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;  FILE&lt;font color="#990000"&gt;*&lt;/font&gt; f &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;fopen&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;argv&lt;font color="#990000"&gt;[&lt;/font&gt;&lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;],&lt;/font&gt; &lt;font color="#FF0000"&gt;"r"&lt;/font&gt;&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;&lt;font color="#0000FF"&gt;while&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;getc&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;f&lt;font color="#990000"&gt;))&lt;/font&gt;&lt;br /&gt;    count&lt;font color="#990000"&gt;++;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;&lt;font color="#000000"&gt;printf&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;"File has %d characters&lt;/font&gt;&lt;font color="#CC33CC"&gt;\n&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; count&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;&lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;br /&gt;Processing /Users/gcb/work/log-analysis/cc.cpp ... created /Users/gcb/work/log-analysis/cc.cpp.html&lt;br /&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      Baseline written in C++&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;pre&gt;&lt;br /&gt;      File has 1673392372 characters&lt;br /&gt;&lt;br /&gt;real	0m53.167s&lt;br /&gt;user	0m31.473s&lt;br /&gt;sys	0m3.094s&lt;br /&gt;&lt;br /&gt;      &lt;/pre&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;!-- Generator: GNU source-highlight 2.9&lt;br /&gt;by Lorenzo Bettini&lt;br /&gt;http://www.lorenzobettini.it&lt;br /&gt;http://www.gnu.org/software/src-highlite --&gt;&lt;br /&gt;&lt;pre&gt;&lt;tt&gt;&lt;b&gt;&lt;font color="#000080"&gt;#include&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;&amp;lt;stdio.h&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font color="#009900"&gt;int&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;main&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#009900"&gt;int&lt;/font&gt; argc&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#009900"&gt;char&lt;/font&gt;&lt;font color="#990000"&gt;**&lt;/font&gt; argv&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;&lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;  &lt;font color="#009900"&gt;int&lt;/font&gt; count &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;  FILE&lt;font color="#990000"&gt;*&lt;/font&gt; f &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;fopen&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;argv&lt;font color="#990000"&gt;[&lt;/font&gt;&lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;],&lt;/font&gt; &lt;font color="#FF0000"&gt;"r"&lt;/font&gt;&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;  &lt;font color="#009900"&gt;char&lt;/font&gt; buffer&lt;font color="#990000"&gt;[&lt;/font&gt;&lt;font color="#993399"&gt;512&lt;/font&gt;&lt;font color="#990000"&gt;];&lt;/font&gt;&lt;br /&gt;  &lt;font color="#009900"&gt;int&lt;/font&gt; read &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;fread&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;buffer&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#993399"&gt;512&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; f&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;&lt;font color="#0000FF"&gt;while&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;read &lt;font color="#990000"&gt;&amp;gt;&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;    count &lt;font color="#990000"&gt;+=&lt;/font&gt; read&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;    read &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;fread&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;buffer&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#993399"&gt;512&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; f&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;  &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;&lt;font color="#000000"&gt;printf&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;"File has %d characters&lt;/font&gt;&lt;font color="#CC33CC"&gt;\n&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; count&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;&lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;br /&gt;Processing /Users/gcb/work/log-analysis/cc1.cpp ... created /Users/gcb/work/log-analysis/cc1.cpp.html&lt;br /&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      A (poor) buffered version of the baseline written in C++&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td&gt;&lt;br /&gt;      &lt;pre&gt;&lt;br /&gt;      File has 1673435763 characters&lt;br /&gt;&lt;br /&gt;real	0m52.425s&lt;br /&gt;user	0m1.526s&lt;br /&gt;sys	0m4.473s&lt;br /&gt;&lt;br /&gt;      &lt;/pre&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;  &lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-3377018980529808536?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/3377018980529808536/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=3377018980529808536' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3377018980529808536'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3377018980529808536'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/04/further-perf-ruby-python-c-file-reading.html' title='Further perf ruby, python C++ file reading'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-4632624092668864034</id><published>2008-04-27T19:18:00.001+01:00</published><updated>2008-04-27T19:35:58.431+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='blogging'/><title type='text'>Blogging Code</title><content type='html'>&lt;html&gt;&lt;br /&gt;&lt;head&gt;&lt;br /&gt;&lt;title&gt;Blogging Code&lt;/title&gt;&lt;br /&gt;&lt;/head&gt;&lt;br /&gt;&lt;body&gt;&lt;br /&gt;&lt;p&gt;I quite often find myself blogging about program source code, that code is typically stored in source files which I then run through a pretty printer (something like source-highlight). Combining everyting together means some copy and pasting - not the most repeatable process and quite often the code and article evolve together - so I end up copying and pasting quite often.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So I came up with mashup. A small ruby program to process html files and handle include directives to do inline include of another file and for this purpose the results of a process&lt;p&gt;&lt;br /&gt;&lt;p&gt;The following source was include with&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;x:include value="source-highlight -o STDOUT ~/projects/mashup/mashup"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;By running:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;mashup blogging-code.html &amp;gt; blogging-code-publish.html&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;!-- Generator: GNU source-highlight 2.9&lt;br /&gt;by Lorenzo Bettini&lt;br /&gt;http://www.lorenzobettini.it&lt;br /&gt;http://www.gnu.org/software/src-highlite --&gt;&lt;br /&gt;&lt;pre&gt;&lt;tt&gt;&lt;i&gt;&lt;font color="#9A1900"&gt;#!/usr/bin/ruby&lt;/font&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;ARGV&lt;font color="#990000"&gt;.&lt;/font&gt;each &lt;b&gt;&lt;font color="#0000FF"&gt;do&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;|&lt;/font&gt;arg&lt;font color="#990000"&gt;|&lt;/font&gt;&lt;br /&gt;  contents &lt;font color="#990000"&gt;=&lt;/font&gt; File&lt;font color="#990000"&gt;.&lt;/font&gt;new&lt;font color="#990000"&gt;(&lt;/font&gt;arg&lt;font color="#990000"&gt;).&lt;/font&gt;read&lt;font color="#990000"&gt;()&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;  contents&lt;font color="#990000"&gt;.&lt;/font&gt;sub!&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF6600"&gt;/&amp;lt;s:include\s+value="([^"]*)"\s*\/&amp;gt;/&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;do&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;|&lt;/font&gt;match&lt;font color="#990000"&gt;|&lt;/font&gt;&lt;br /&gt;    replacement &lt;font color="#990000"&gt;=&lt;/font&gt; File&lt;font color="#990000"&gt;.&lt;/font&gt;new&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#009900"&gt;$1&lt;/font&gt;&lt;font color="#990000"&gt;).&lt;/font&gt;read&lt;font color="#990000"&gt;()&lt;/font&gt;&lt;br /&gt;    replacement&lt;font color="#990000"&gt;.&lt;/font&gt;gsub!&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF6600"&gt;/.*&amp;lt;body&amp;gt;/&lt;/font&gt;m&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;''&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;    replacement&lt;font color="#990000"&gt;.&lt;/font&gt;gsub!&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF6600"&gt;/&amp;lt;\/body&amp;gt;.*/&lt;/font&gt;m&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;''&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;    replacement&lt;br /&gt;  &lt;b&gt;&lt;font color="#0000FF"&gt;end&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;  contents&lt;font color="#990000"&gt;.&lt;/font&gt;sub!&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF6600"&gt;/&amp;lt;x:include\s+value="([^"]*)"\s*\/&amp;gt;/&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;do&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;|&lt;/font&gt;match&lt;font color="#990000"&gt;|&lt;/font&gt;&lt;br /&gt;    replacement &lt;font color="#990000"&gt;=&lt;/font&gt; `&lt;font color="#990000"&gt;#&lt;/font&gt;&lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;font color="#009900"&gt;$1&lt;/font&gt;&lt;font color="#FF0000"&gt;}&lt;/font&gt;`&lt;br /&gt;    replacement&lt;font color="#990000"&gt;.&lt;/font&gt;gsub!&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF6600"&gt;/.*&amp;lt;body&amp;gt;/&lt;/font&gt;m&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;''&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;    replacement&lt;font color="#990000"&gt;.&lt;/font&gt;gsub!&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF6600"&gt;/&amp;lt;\/body&amp;gt;.*/&lt;/font&gt;m&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;''&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;    replacement&lt;br /&gt;  &lt;b&gt;&lt;font color="#0000FF"&gt;end&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;  puts contents&lt;br /&gt;&lt;b&gt;&lt;font color="#0000FF"&gt;end&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;&lt;/tt&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/body&gt;&lt;br /&gt;&lt;/html&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-4632624092668864034?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/4632624092668864034/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=4632624092668864034' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4632624092668864034'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4632624092668864034'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/04/blogging-code.html' title='Blogging Code'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-6724376469884382325</id><published>2008-04-14T10:34:00.001+01:00</published><updated>2008-04-14T10:34:06.974+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='log files'/><title type='text'>Log files</title><content type='html'>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"&gt;&lt;br /&gt;&lt;html&gt;&lt;br /&gt;  &lt;head&gt;&lt;br /&gt;    &lt;title&gt;&lt;br /&gt;      Log Files&lt;br /&gt;    &lt;/title&gt;&lt;br /&gt;  &lt;/head&gt;&lt;br /&gt;  &lt;body&gt;&lt;br /&gt;    &lt;p&gt;&lt;br /&gt;      Log files are one of those must have things for any web application. It is just so hard to predict all of the possible ways users are going to interact with the site that gathering post live information about application behaviour is essential. It does however produce quite a lot of data.&lt;br /&gt;    &lt;/p&gt;&lt;br /&gt;    &lt;p&gt;&lt;br /&gt;      On my current project, after a fairly significant release we resolved to check the log files to see if there were any unexpected incidents that required fixes or web content changes. The log files ran to several gigabytes containing entries not only from the application but also from a very noisy subsystems. After a quick look it became evident that it would not be effective just scanning through the log files but that some cleaning or automated analysis was required.&lt;br /&gt;    &lt;/p&gt;&lt;br /&gt;    &lt;p&gt;&lt;br /&gt;      On the initial scan we noticed that there were some Java stack traces being repeated so something that could capture the distinct stack traces and then list the errors that caused them. In this was we could look at the general issues based on priority (number of occurrences).&lt;br /&gt;    &lt;/p&gt;&lt;br /&gt;    &lt;p&gt;&lt;br /&gt;      Our first effort was to write a fairly simple ruby script using a hash map keyed on the text of the stack trace. Each map entry contained an array of error lines from the log files. We kicked the script off after testing with a small log file and went to lunch.&lt;br /&gt;    &lt;/p&gt;&lt;br /&gt;    &lt;p&gt;&lt;br /&gt;      When we came back the script was still running. Sometime later it ran out of memory - not ideal.&lt;br /&gt;    &lt;/p&gt;&lt;br /&gt;    &lt;p&gt;&lt;br /&gt;      It has been sometime since I have written any C++. Most of my work these days involves Java, C# and a little bit of Ruby for work around the codebase so it took a little while for my C++ brain to kick in. A colleague also took up the challenge by writing a solution in Python.&lt;br /&gt;    &lt;/p&gt;&lt;br /&gt;    &lt;p&gt;&lt;br /&gt;      The results were quite startling with the Python script performing almost as well as the C++ at around 500,000 lines per second.&lt;br /&gt;    &lt;/p&gt;&lt;br /&gt;    &lt;!-- Generator: GNU source-highlight 2.9&lt;br /&gt;    by Lorenzo Bettini&lt;br /&gt;    http://www.lorenzobettini.it&lt;br /&gt;    http://www.gnu.org/software/src-highlite --&gt;&lt;br /&gt;    &lt;pre&gt;&lt;tt&gt;&lt;b&gt;&lt;font color="#000080"&gt;#include&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;&amp;lt;iostream&amp;gt;&lt;/font&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#000080"&gt;#include&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;&amp;lt;fstream&amp;gt;&lt;/font&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#000080"&gt;#include&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;&amp;lt;sstream&amp;gt;&lt;/font&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#000080"&gt;#include&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;&amp;lt;string&amp;gt;&lt;/font&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#000080"&gt;#include&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;&amp;lt;map&amp;gt;&lt;/font&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#000080"&gt;#include&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;&amp;lt;vector&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#0000FF"&gt;using&lt;/font&gt;&lt;/b&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;namespace&lt;/font&gt;&lt;/b&gt; std&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#0000FF"&gt;class&lt;/font&gt;&lt;/b&gt; &lt;font color="#009900"&gt;progress&lt;/font&gt; &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;       &lt;font color="#009900"&gt;int&lt;/font&gt; count&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#0000FF"&gt;public&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;:&lt;/font&gt;&lt;br /&gt;       &lt;b&gt;&lt;font color="#000000"&gt;progress&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;()&lt;/font&gt; &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;          count &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;       &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;       &lt;font color="#009900"&gt;void&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;ping&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;()&lt;/font&gt;&lt;br /&gt;       &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;          cerr &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#CC33CC"&gt;\b&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt; &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#FF0000"&gt;"|/-&lt;/font&gt;&lt;font color="#CC33CC"&gt;\\&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#990000"&gt;[&lt;/font&gt;count&lt;font color="#990000"&gt;++%&lt;/font&gt;&lt;font color="#993399"&gt;4&lt;/font&gt;&lt;font color="#990000"&gt;];&lt;/font&gt;&lt;br /&gt;       &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;    &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#0000FF"&gt;typedef&lt;/font&gt;&lt;/b&gt; map&lt;font color="#990000"&gt;&amp;lt;&lt;/font&gt;string&lt;font color="#990000"&gt;,&lt;/font&gt; vector&lt;font color="#990000"&gt;&amp;lt;&lt;/font&gt;string&lt;font color="#990000"&gt;&amp;gt;*&amp;gt;&lt;/font&gt; error_map&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    &lt;font color="#009900"&gt;void&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;print_errors&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;error_map&lt;font color="#990000"&gt;&amp;amp;&lt;/font&gt; errors&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;    &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;       &lt;b&gt;&lt;font color="#0000FF"&gt;for&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;error_map&lt;font color="#990000"&gt;::&lt;/font&gt;iterator iter &lt;font color="#990000"&gt;=&lt;/font&gt; errors&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;begin&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;();&lt;/font&gt; iter &lt;font color="#990000"&gt;!=&lt;/font&gt; errors&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;end&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;();&lt;/font&gt; iter&lt;font color="#990000"&gt;++&lt;/font&gt; &lt;font color="#990000"&gt;)&lt;/font&gt; &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;          vector&lt;font color="#990000"&gt;&amp;lt;&lt;/font&gt;string&lt;font color="#990000"&gt;&amp;gt;*&lt;/font&gt; reports &lt;font color="#990000"&gt;=&lt;/font&gt; iter&lt;font color="#990000"&gt;-&amp;gt;&lt;/font&gt;second&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;          &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;reports&lt;font color="#990000"&gt;-&amp;gt;&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;size&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;()&lt;/font&gt; &lt;font color="#990000"&gt;&amp;gt;&lt;/font&gt; &lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;          &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;             string first &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#990000"&gt;(*&lt;/font&gt;reports&lt;font color="#990000"&gt;)[&lt;/font&gt;&lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;];&lt;/font&gt;&lt;br /&gt;             cout &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#CC33CC"&gt;\n\n\n&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;             cout &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; reports&lt;font color="#990000"&gt;-&amp;gt;&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;size&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;()&lt;/font&gt; &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#FF0000"&gt;" instances of&lt;/font&gt;&lt;font color="#CC33CC"&gt;\n&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;             cout &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#FF0000"&gt;"FIRST instance "&lt;/font&gt; &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; first &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#CC33CC"&gt;\n&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;             &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;reports&lt;font color="#990000"&gt;-&amp;gt;&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;size&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;()&lt;/font&gt; &lt;font color="#990000"&gt;&amp;gt;&lt;/font&gt; &lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;                cout &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#FF0000"&gt;"LAST  instance "&lt;/font&gt; &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#990000"&gt;(*&lt;/font&gt;reports&lt;font color="#990000"&gt;)[&lt;/font&gt;reports&lt;font color="#990000"&gt;-&amp;gt;&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;size&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;()&lt;/font&gt; &lt;font color="#990000"&gt;-&lt;/font&gt;&lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;]&lt;/font&gt; &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#CC33CC"&gt;\n&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;             cout &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; iter&lt;font color="#990000"&gt;-&amp;gt;&lt;/font&gt;first&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;          &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;       &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;    &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    &lt;font color="#009900"&gt;void&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;process_file&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#009900"&gt;char&lt;/font&gt;&lt;font color="#990000"&gt;*&lt;/font&gt; filename&lt;font color="#990000"&gt;,&lt;/font&gt; error_map&lt;font color="#990000"&gt;&amp;amp;&lt;/font&gt; errors&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;    &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;       progress p&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;       cerr &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#CC33CC"&gt;\b&lt;/font&gt;&lt;font color="#FF0000"&gt;Processing "&lt;/font&gt; &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; filename &lt;font color="#990000"&gt;&amp;lt;&amp;lt;&lt;/font&gt; &lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#CC33CC"&gt;\n&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;       ifstream &lt;b&gt;&lt;font color="#000000"&gt;file&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;filename&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;       string line&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;       string pending_error&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;       string pending_stack&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;       &lt;font color="#009900"&gt;int&lt;/font&gt; stack_lines &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;       &lt;font color="#009900"&gt;int&lt;/font&gt; line_number &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;       &lt;font color="#009900"&gt;bool&lt;/font&gt; skipping &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;false&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;       &lt;b&gt;&lt;font color="#0000FF"&gt;while&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;getline&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;file&lt;font color="#990000"&gt;,&lt;/font&gt; line&lt;font color="#990000"&gt;))&lt;/font&gt;&lt;br /&gt;       &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;          &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;line_number &lt;font color="#990000"&gt;%&lt;/font&gt; &lt;font color="#993399"&gt;100000&lt;/font&gt; &lt;font color="#990000"&gt;==&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;             p&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;ping&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;();&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;          line_number&lt;font color="#990000"&gt;++;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;          &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;line&lt;font color="#990000"&gt;[&lt;/font&gt;&lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;]&lt;/font&gt; &lt;font color="#990000"&gt;==&lt;/font&gt; &lt;font color="#FF0000"&gt;'#'&lt;/font&gt; &lt;font color="#990000"&gt;||&lt;/font&gt; line&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;find&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;"Notice"&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;font color="#990000"&gt;!=&lt;/font&gt; string&lt;font color="#990000"&gt;::&lt;/font&gt;npos&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;          &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;             &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;pending_stack&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;size&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;()&lt;/font&gt; &lt;font color="#990000"&gt;!=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;             &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;                &lt;i&gt;&lt;font color="#9A1900"&gt;// Process stack trace&lt;/font&gt;&lt;/i&gt;&lt;br /&gt;                &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;errors&lt;font color="#990000"&gt;[&lt;/font&gt;pending_stack&lt;font color="#990000"&gt;]&lt;/font&gt; &lt;font color="#990000"&gt;==&lt;/font&gt; NULL&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;                   errors&lt;font color="#990000"&gt;[&lt;/font&gt;pending_stack&lt;font color="#990000"&gt;]&lt;/font&gt; &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;new&lt;/font&gt;&lt;/b&gt; vector&lt;font color="#990000"&gt;&amp;lt;&lt;/font&gt;string&lt;font color="#990000"&gt;&amp;gt;();&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;                errors&lt;font color="#990000"&gt;[&lt;/font&gt;pending_stack&lt;font color="#990000"&gt;]-&amp;gt;&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;insert&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;errors&lt;font color="#990000"&gt;[&lt;/font&gt;pending_stack&lt;font color="#990000"&gt;]-&amp;gt;&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;end&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(),&lt;/font&gt; pending_error&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;                pending_stack&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;clear&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;();&lt;/font&gt;&lt;br /&gt;             &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;             &lt;i&gt;&lt;font color="#9A1900"&gt;// Ignore lines from systems we are not interested in&lt;/font&gt;&lt;/i&gt;&lt;br /&gt;             skipping &lt;font color="#990000"&gt;=&lt;/font&gt; line&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;find&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;"ignore-one"&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;font color="#990000"&gt;!=&lt;/font&gt; string&lt;font color="#990000"&gt;::&lt;/font&gt;npos&lt;br /&gt;             &lt;font color="#990000"&gt;||&lt;/font&gt; line&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;find&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;"ignore-two"&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;font color="#990000"&gt;!=&lt;/font&gt; string&lt;font color="#990000"&gt;::&lt;/font&gt;npos&lt;br /&gt;             &lt;font color="#990000"&gt;||&lt;/font&gt; line&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;find&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;"ignore-three"&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;font color="#990000"&gt;!=&lt;/font&gt; string&lt;font color="#990000"&gt;::&lt;/font&gt;npos&lt;br /&gt;             &lt;font color="#990000"&gt;||&lt;/font&gt; line&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;find&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;"INFO"&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;font color="#990000"&gt;!=&lt;/font&gt; string&lt;font color="#990000"&gt;::&lt;/font&gt;npos&lt;br /&gt;             &lt;font color="#990000"&gt;||&lt;/font&gt; line&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;find&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;"WARN"&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;font color="#990000"&gt;!=&lt;/font&gt; string&lt;font color="#990000"&gt;::&lt;/font&gt;npos&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;             &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(!&lt;/font&gt;skipping&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;                pending_error &lt;font color="#990000"&gt;=&lt;/font&gt; line&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;             stack_lines &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;          &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;          &lt;b&gt;&lt;font color="#0000FF"&gt;else&lt;/font&gt;&lt;/b&gt;&lt;br /&gt;          &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;             &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(!&lt;/font&gt;skipping &lt;font color="#990000"&gt;&amp;amp;&amp;amp;&lt;/font&gt; stack_lines &lt;font color="#990000"&gt;&amp;lt;&lt;/font&gt; &lt;font color="#993399"&gt;20&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;             &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;                pending_stack&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;append&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;line&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;                pending_stack&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;append&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#CC33CC"&gt;\n&lt;/font&gt;&lt;font color="#FF0000"&gt;"&lt;/font&gt;&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;             &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;             stack_lines&lt;font color="#990000"&gt;++;&lt;/font&gt;&lt;br /&gt;          &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;       &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;    &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;font color="#009900"&gt;int&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;main &lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#009900"&gt;int&lt;/font&gt; argc&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#009900"&gt;char&lt;/font&gt; &lt;font color="#990000"&gt;*&lt;/font&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;const&lt;/font&gt;&lt;/b&gt; argv&lt;font color="#990000"&gt;[])&lt;/font&gt; &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;       error_map&lt;font color="#990000"&gt;*&lt;/font&gt; e &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;new&lt;/font&gt;&lt;/b&gt; map&lt;font color="#990000"&gt;&amp;lt;&lt;/font&gt;string&lt;font color="#990000"&gt;,&lt;/font&gt; vector&lt;font color="#990000"&gt;&amp;lt;&lt;/font&gt;string&lt;font color="#990000"&gt;&amp;gt;*&amp;gt;();&lt;/font&gt;&lt;br /&gt;       error_map&lt;font color="#990000"&gt;&amp;amp;&lt;/font&gt; errors &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#990000"&gt;*&lt;/font&gt;e&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;       &lt;b&gt;&lt;font color="#0000FF"&gt;for&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#009900"&gt;int&lt;/font&gt; i &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt; i &lt;font color="#990000"&gt;&amp;lt;&lt;/font&gt; argc&lt;font color="#990000"&gt;;&lt;/font&gt; i&lt;font color="#990000"&gt;++)&lt;/font&gt;&lt;br /&gt;       &lt;font color="#FF0000"&gt;{&lt;/font&gt;&lt;br /&gt;          &lt;b&gt;&lt;font color="#000000"&gt;process_file&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;argv&lt;font color="#990000"&gt;[&lt;/font&gt;i&lt;font color="#990000"&gt;],&lt;/font&gt; errors&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;       &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;       &lt;b&gt;&lt;font color="#000000"&gt;print_errors&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;errors&lt;font color="#990000"&gt;);&lt;/font&gt;  &lt;br /&gt;       &lt;b&gt;&lt;font color="#0000FF"&gt;return&lt;/font&gt;&lt;/b&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;;&lt;/font&gt;&lt;br /&gt;    &lt;font color="#FF0000"&gt;}&lt;/font&gt;&lt;br /&gt;    &lt;/tt&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;    &lt;p&gt;&lt;br /&gt;      The Python solution is a little shorter however&lt;br /&gt;    &lt;/p&gt;&lt;br /&gt;    &lt;!-- Generator: GNU source-highlight 2.9&lt;br /&gt;    by Lorenzo Bettini&lt;br /&gt;    http://www.lorenzobettini.it&lt;br /&gt;    http://www.gnu.org/software/src-highlite --&gt;&lt;br /&gt;    &lt;pre&gt;&lt;tt&gt;&lt;b&gt;&lt;font color="#000080"&gt;import&lt;/font&gt;&lt;/b&gt; os&lt;font color="#990000"&gt;,&lt;/font&gt; sys&lt;br /&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#0000FF"&gt;def&lt;/font&gt;&lt;/b&gt; &lt;b&gt;&lt;font color="#000000"&gt;is_valid&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;item&lt;font color="#990000"&gt;):&lt;/font&gt;&lt;br /&gt;        &lt;b&gt;&lt;font color="#0000FF"&gt;for&lt;/font&gt;&lt;/b&gt; token &lt;b&gt;&lt;font color="#0000FF"&gt;in&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;[&lt;/font&gt;&lt;font color="#FF0000"&gt;'ignore-one'&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;'ignore-two'&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;'ignore-tree'&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;'NavigationLink instance'&lt;/font&gt;&lt;font color="#990000"&gt;]:&lt;/font&gt;&lt;br /&gt;            &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; token &lt;b&gt;&lt;font color="#0000FF"&gt;in&lt;/font&gt;&lt;/b&gt; item&lt;font color="#990000"&gt;:&lt;/font&gt;&lt;br /&gt;                &lt;b&gt;&lt;font color="#0000FF"&gt;return&lt;/font&gt;&lt;/b&gt; &lt;font color="#009900"&gt;False&lt;/font&gt;&lt;br /&gt;        &lt;b&gt;&lt;font color="#0000FF"&gt;return&lt;/font&gt;&lt;/b&gt; &lt;font color="#009900"&gt;True&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    directory &lt;font color="#990000"&gt;=&lt;/font&gt; sys&lt;font color="#990000"&gt;.&lt;/font&gt;argv&lt;font color="#990000"&gt;[&lt;/font&gt;&lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;]&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    errors &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#990000"&gt;{}&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#0000FF"&gt;for&lt;/font&gt;&lt;/b&gt; filename &lt;b&gt;&lt;font color="#0000FF"&gt;in&lt;/font&gt;&lt;/b&gt; os&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;listdir&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;directory&lt;font color="#990000"&gt;):&lt;/font&gt;&lt;br /&gt;        last&lt;font color="#009900"&gt;_&lt;/font&gt;error &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#FF0000"&gt;''&lt;/font&gt;&lt;br /&gt;        last&lt;font color="#009900"&gt;_&lt;/font&gt;stack &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#FF0000"&gt;''&lt;/font&gt;&lt;br /&gt;        stack&lt;font color="#009900"&gt;_&lt;/font&gt;count &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;        file&lt;font color="#009900"&gt;_&lt;/font&gt;path &lt;font color="#990000"&gt;=&lt;/font&gt; os&lt;font color="#990000"&gt;.&lt;/font&gt;path&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;join&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;directory&lt;font color="#990000"&gt;,&lt;/font&gt; filename&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;        &lt;b&gt;&lt;font color="#0000FF"&gt;print&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;'Processing'&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; file&lt;font color="#009900"&gt;_&lt;/font&gt;path&lt;br /&gt;&lt;br /&gt;        source &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;open&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;file&lt;font color="#009900"&gt;_&lt;/font&gt;path&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;        &lt;b&gt;&lt;font color="#0000FF"&gt;for&lt;/font&gt;&lt;/b&gt; line &lt;b&gt;&lt;font color="#0000FF"&gt;in&lt;/font&gt;&lt;/b&gt; source&lt;font color="#990000"&gt;:&lt;/font&gt;&lt;br /&gt;            &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; line&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;startswith&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;'#'&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;or&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;'&amp;lt;Notice&amp;gt;'&lt;/font&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;in&lt;/font&gt;&lt;/b&gt; line&lt;font color="#990000"&gt;):&lt;/font&gt;&lt;br /&gt;                &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; &lt;b&gt;&lt;font color="#000000"&gt;is_valid&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;last&lt;font color="#009900"&gt;_&lt;/font&gt;stack&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;and&lt;/font&gt;&lt;/b&gt; &lt;b&gt;&lt;font color="#000000"&gt;is_valid&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;last&lt;font color="#009900"&gt;_&lt;/font&gt;error&lt;font color="#990000"&gt;):&lt;/font&gt;&lt;br /&gt;                    errors&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;setdefault&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;last&lt;font color="#009900"&gt;_&lt;/font&gt;stack&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#990000"&gt;[]).&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;append&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;last&lt;font color="#009900"&gt;_&lt;/font&gt;error&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;                last&lt;font color="#009900"&gt;_&lt;/font&gt;error &lt;font color="#990000"&gt;=&lt;/font&gt; line&lt;br /&gt;                last&lt;font color="#009900"&gt;_&lt;/font&gt;stack &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#FF0000"&gt;''&lt;/font&gt;&lt;br /&gt;                stack&lt;font color="#009900"&gt;_&lt;/font&gt;count &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;br /&gt;            &lt;b&gt;&lt;font color="#0000FF"&gt;else&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;:&lt;/font&gt;&lt;br /&gt;                stack&lt;font color="#009900"&gt;_&lt;/font&gt;count &lt;font color="#990000"&gt;+=&lt;/font&gt; &lt;font color="#993399"&gt;1&lt;/font&gt;&lt;br /&gt;                &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; stack&lt;font color="#009900"&gt;_&lt;/font&gt;count &lt;font color="#990000"&gt;&amp;lt;=&lt;/font&gt; &lt;font color="#993399"&gt;20&lt;/font&gt;&lt;font color="#990000"&gt;:&lt;/font&gt;&lt;br /&gt;                    last&lt;font color="#009900"&gt;_&lt;/font&gt;stack &lt;font color="#990000"&gt;+=&lt;/font&gt; line&lt;br /&gt;&lt;br /&gt;        source&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;close&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;()&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#0000FF"&gt;print&lt;/font&gt;&lt;/b&gt; &lt;font color="#FF0000"&gt;'Writing report to grok.txt'&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    out&lt;font color="#009900"&gt;_&lt;/font&gt;file &lt;font color="#990000"&gt;=&lt;/font&gt; &lt;b&gt;&lt;font color="#000000"&gt;open&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;'grok.txt'&lt;/font&gt;&lt;font color="#990000"&gt;,&lt;/font&gt; &lt;font color="#FF0000"&gt;'w'&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    &lt;b&gt;&lt;font color="#0000FF"&gt;for&lt;/font&gt;&lt;/b&gt; stack&lt;font color="#990000"&gt;,&lt;/font&gt; error&lt;font color="#009900"&gt;_&lt;/font&gt;list &lt;b&gt;&lt;font color="#0000FF"&gt;in&lt;/font&gt;&lt;/b&gt; errors&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;iteritems&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;():&lt;/font&gt;&lt;br /&gt;        &lt;b&gt;&lt;font color="#0000FF"&gt;if&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;len&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;error&lt;font color="#009900"&gt;_&lt;/font&gt;list&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;font color="#990000"&gt;&amp;gt;&lt;/font&gt; &lt;font color="#993399"&gt;1&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt; &lt;b&gt;&lt;font color="#0000FF"&gt;and&lt;/font&gt;&lt;/b&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;len&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;stack&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;strip&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;())&lt;/font&gt; &lt;font color="#990000"&gt;&amp;gt;&lt;/font&gt; &lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;):&lt;/font&gt;&lt;br /&gt;            out&lt;font color="#009900"&gt;_&lt;/font&gt;file&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;write&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;'Found %d items like: %s'&lt;/font&gt; &lt;font color="#990000"&gt;%&lt;/font&gt; &lt;font color="#990000"&gt;(&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;len&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;error&lt;font color="#009900"&gt;_&lt;/font&gt;list&lt;font color="#990000"&gt;),&lt;/font&gt; error&lt;font color="#009900"&gt;_&lt;/font&gt;list&lt;font color="#990000"&gt;[&lt;/font&gt;&lt;font color="#993399"&gt;0&lt;/font&gt;&lt;font color="#990000"&gt;]))&lt;/font&gt;&lt;br /&gt;            out&lt;font color="#009900"&gt;_&lt;/font&gt;file&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;write&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;stack&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;            out&lt;font color="#009900"&gt;_&lt;/font&gt;file&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;write&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;'\n\n'&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;            out&lt;font color="#009900"&gt;_&lt;/font&gt;file&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;write&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;'---------------------------------------------------------'&lt;/font&gt;&lt;font color="#990000"&gt;);&lt;/font&gt;&lt;br /&gt;            out&lt;font color="#009900"&gt;_&lt;/font&gt;file&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;write&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;(&lt;/font&gt;&lt;font color="#FF0000"&gt;'\n\n'&lt;/font&gt;&lt;font color="#990000"&gt;)&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    out&lt;font color="#009900"&gt;_&lt;/font&gt;file&lt;font color="#990000"&gt;.&lt;/font&gt;&lt;b&gt;&lt;font color="#000000"&gt;close&lt;/font&gt;&lt;/b&gt;&lt;font color="#990000"&gt;()&lt;/font&gt;&lt;br /&gt;    &lt;/tt&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Both solutions limited the number of lines in the stack trace used for the key to 20. This was fine for non-reflected methods.&lt;/p&gt;&lt;br /&gt;  &lt;/body&gt;&lt;br /&gt;&lt;/html&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-6724376469884382325?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/6724376469884382325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=6724376469884382325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/6724376469884382325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/6724376469884382325'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/04/log-files.html' title='Log files'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-313835238374462203</id><published>2008-03-01T16:21:00.001Z</published><updated>2008-03-01T16:21:57.322Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Syntax'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Ruby initialise array and add in one step</title><content type='html'>I keep forgetting the syntax of this so perhaps this will help.&lt;br /&gt;&lt;br /&gt;Given a hash where each value is an array of values this gives a nice concise way of setting things up (even if it is a little obscure).&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;map = {}&lt;br /&gt;&lt;br /&gt;(map[:key] ||= []) &lt;&lt; :value&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The above results in a hash containing a key value of :key with an array containing :value&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-313835238374462203?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/313835238374462203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=313835238374462203' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/313835238374462203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/313835238374462203'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/03/ruby-initialise-array-and-add-in-one.html' title='Ruby initialise array and add in one step'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-2066564228026336499</id><published>2008-02-26T11:34:00.001Z</published><updated>2008-02-26T11:34:15.943Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='cruisecontrol.rb'/><title type='text'>cruisecontrolrb and java</title><content type='html'>I have been meaning to setup a &lt;a href="cruisecontrolrb.thoughtworks.com"&gt;cruisecontrol.rb&lt;/a&gt; instance for some time. Cruisecontrol.rb is a implementation of continuous integration build server in ruby. It is a simple self-contained download with a really quick initial setup time.&lt;br /&gt;&lt;br /&gt;I have just started an open source java project for stack trance analysis called &lt;a href="https://sourceforge.net/projects/why/"&gt;why&lt;/a&gt; and wanted a build server so thought I would give cruisecontrol.rb a go.&lt;br /&gt;&lt;br /&gt;The download took a couple of minutes. Adding the project (cruise add why --url https://why.svn.sourceforge.net/svnroot/why) took a few more minutes to do the initial checkout.&lt;br /&gt;&lt;br /&gt;Started cruise (cruise start) in a command shell and...build failed.&lt;br /&gt;&lt;br /&gt;I needed to provide a custom build command in the cruise_config.rb file in projects/why:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Project.configure do |project|&lt;br /&gt;  &lt;br /&gt;  project.build_command = 'b'&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I already had a shell script called b to run ant and build the project. Result - build failed.&lt;br /&gt;&lt;br /&gt;Small scratching of head and a chmod +x b later and - build passed.&lt;br /&gt;&lt;br /&gt;From start to finish about 20 mins - most of which was download and initial checkout.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-2066564228026336499?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/2066564228026336499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=2066564228026336499' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2066564228026336499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2066564228026336499'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/02/cruisecontrolrb-and-java.html' title='cruisecontrolrb and java'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-269753133619905925</id><published>2008-02-03T22:23:00.002Z</published><updated>2008-02-14T15:10:32.878Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Tagging builds in subversion</title><content type='html'>&lt;p&gt;At the end of every build I like to add a tag to the project source repository. Although the build log contains the revision of the source being built and so the build can be re-created, I like the fact that all the information about the source and the build is in one place.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &amp;lt;target name="tag-build" description="tag the build revision" &amp;gt;&lt;br /&gt;     &amp;lt;svn javahl="false"&amp;gt;&lt;br /&gt;        &amp;lt;status path="${basedir}" revisionProperty="svn.revision" /&amp;gt;&lt;br /&gt;     &amp;lt;/svn&amp;gt;&lt;br /&gt;     &amp;lt;echo message="Tagging revision ${svn.revision} as tag ${label}" /&amp;gt;&lt;br /&gt;     &amp;lt;svn username="cruise" password="cruise" javahl="false"&amp;gt;&lt;br /&gt;        &amp;lt;copy srcURL="http://repository/path/trunk" revision="${svn.revision}" destUrl="http://repository/path/tags/${label}" message="Cruise: Tagging build ${label}" /&amp;gt;&lt;br /&gt;     &amp;lt;/svn&amp;gt;&lt;br /&gt;  &amp;lt;/target&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-269753133619905925?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/269753133619905925/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=269753133619905925' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/269753133619905925'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/269753133619905925'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/02/tagging-builds-in-subversion.html' title='Tagging builds in subversion'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-5029366979402237931</id><published>2008-01-21T11:52:00.001Z</published><updated>2008-01-21T11:52:59.467Z</updated><title type='text'>Project Kit List</title><content type='html'>&lt;body&gt;&lt;br /&gt; &lt;br /&gt;  &lt;p&gt;Essential Items for Software Projects&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;A recent conversation with a friend made me realise that things I have come to think of as standard practice for software projects are by no means universal and that problems I had thought not relevant any more are still around and causing mayhem and chaos around the world for developers and managers alike.&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;So casting caution to the wind I thought I would draw up a list of things I find essential for a project&lt;/p&gt;&lt;br /&gt;  &lt;ul&gt;&lt;br /&gt;    &lt;li&gt;Version Control&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Build server&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Wiki&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Issue tracking&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Text Editor&lt;/li&gt;&lt;br /&gt;  &lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;  &lt;h2&gt;Version Control&lt;/h2&gt;&lt;br /&gt;  &lt;p&gt;It is difficult to understand why any project would not use version control. No decision is final and no PC or server is 100% reliable. At the very least Version Control is a personal safety net for things that can and will go wrong&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;I like to take things a little further and make version control the only way of communicating changes to the build server. This ensures that &lt;strong&gt;everything&lt;/strong&gt; is under version control and that those little change that I will remember forever (hah) are written down somewhere. (The build server config should also be in version control - makes rebuilding a build server a breeze)&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;My personal preference is &lt;a href="http://subversion.tigres.org"&gt;subversion&lt;/a&gt;. Its free, open source and works really really well. If you are using a version control system with features not supported by subversion think seriously about whether you really need those features. No really many version control systems have features that promote complex processes and practices that can really get in the way.&lt;/p&gt; &lt;br /&gt;&lt;br /&gt;  &lt;h2&gt;Build Server&lt;/h2&gt;&lt;br /&gt;  &lt;p&gt;My second essential item of kit is a build server. Hardware is now so inexpensive that there are few excuses for not having one of these&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;If you cannot afford an additional server or it is not practical (on the road with a laptop perhaps) then invest in a good virtualisation system had run your build server on the same hardware or one of the dev boxes if you are working in a team.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;  &lt;h2&gt;Wiki&lt;/h2&gt;&lt;br /&gt;  &lt;p&gt;If you are working in a team or even by yourself using a wiki to record things as the project goes along is great. Especially if your memory is anything like mine. Wikis are especially useful if you need to share information about the project or team with people out of your office.&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;Wiki's such as track also have a bug tracking system built in and integrate with a subversion version control&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;  &lt;h2&gt;Issue Tracking&lt;/h2&gt;&lt;br /&gt;  &lt;p&gt;As your code base matures you are going to need something to keep track of the problems and changes that people want.&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;Don't go overboard. Putting too much reliance on an issue tracking system is that same as code generators and wizards in your ide - they stop you thinking about the problem and generate a lot of noise&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;Having said that I am a great fan of code generators :)&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;&lt;br /&gt;&lt;br /&gt;    &lt;h2&gt;Text Editor&lt;/h2&gt;&lt;br /&gt;  &lt;p&gt;Ok so why put a text editor in the same rankings as version control wikis and such?&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;I am with the &lt;a href="http://www.pragmaticprogrammers.com"&gt;Pragmatic Programmers&lt;/a&gt; on this one. Having a &lt;strong&gt;good&lt;/strong&gt; text editor to call upon is essential. By good I mean it fits your work, you and the things you need do do. But like all good tools you need to spend time with it learning what it is good at. My personal choices are TextMate on the Mac and Emacs just about everywhere.&lt;/p&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;    &lt;h1&gt;Best Practice&lt;/h1&gt;&lt;br /&gt;  &lt;p&gt;Ok now the preachy bit. But as with tools make sure you need the practice before you use it. I have seen project adopt practices because they have seen them work well on other projects without considering the impact or relevance to the current project. Having said that some things really are universal.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;  &lt;h2&gt;Build servers and pipelines&lt;/h2&gt;&lt;br /&gt;  &lt;p&gt;I have talked a bit about having a build server. If you hav'nt got one look into getting one.&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;If you have one then there are some additional things you should consider.&lt;/p&gt;&lt;br /&gt;  &lt;ul&gt;&lt;br /&gt;    &lt;li&gt;Everything on the server came through version control. Ok maybe everything is a bit steep. Your going to need an OS, runtime and build software and other stuff that is just not practical to put through version control. But perhaps scripting the intallation and putting that script in version control would work. It would certainly make it easier to set up another build box.&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Everything going to production comes from a build server. Yep no more quick file deployes and patches from dev boxes. If it is important enough to put through testing it is important enough to have traceability through the build.&lt;/li&gt;&lt;br /&gt;  &lt;/ul&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;p&gt;In some situations one build server is not enough. Perhaps you are maintaining multiple versions of the application or there are complex integration points that are tested as part of a different build. (It is often useful to have a fast developer build to provide rapid feedback to the developers and then a longer integration build that makes sure the application works in its intended envioronment.)&lt;/p&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;h2&gt;Integration builds&lt;/h2&gt;&lt;br /&gt;  &lt;p&gt;Having mentioned Integraion builds I had better expand on what I mean by integration builds and integration as a concept&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;Integration and Continuous Integration (CI) (as part of build systems such as CruiseControl CruiseControl.net etc) are talked about a lot but what does this mean in practice and how best to make use of these tools.&lt;/p&gt;&lt;br /&gt;  &lt;p&gt;The word integration and continuous integration covers a lot of concepts. Perhpas the first level of integration and I believe the original intent for work integration of the changes made by eack developer in the team.&lt;/p&gt;&lt;br /&gt;&lt;/body&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-5029366979402237931?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/5029366979402237931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=5029366979402237931' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/5029366979402237931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/5029366979402237931'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/01/project-kit-list.html' title='Project Kit List'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-2975392682361276249</id><published>2008-01-21T11:48:00.001Z</published><updated>2008-01-21T11:50:34.077Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><title type='text'>Managing session state in persitent objects</title><content type='html'>&lt;html&gt;&lt;br /&gt;&lt;head&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.ln { color: rgb(0,0,0); font-weight: normal; font-style: normal; }&lt;br /&gt;.s0 { color: rgb(0,0,128); font-weight: bold; }&lt;br /&gt;.s1 { }&lt;br /&gt;.s2 { color: rgb(128,128,128); font-style: italic; }&lt;br /&gt;.s3 { color: rgb(0,128,0); font-weight: bold; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;/head&gt;&lt;br /&gt;&lt;body&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;On my current web project, like most web projects, needed a way of managing user session state. We wanted a clean separation from the web tier and a way of managing warnings or annotations to the supplied user data incase the data was not valid.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;We decided to store information supplied in a GET or POST request in document objects. These document objects would then be used by the service tiers to perform the requested operation. Each document object was kept simple by only allowing fields/attributes. The documents would be validated by a validator for each document type, the validators using a utiltity class of validations to keep the duplicate code count low. The documents can be presisted for long running user transactions.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Perhaps the best way to illustrate how this works is with an example. Lets assume that we have a request handler for a registration service that takes a map of name/value pairs for the values the user has supplied on the registration form. For simpliity the response and error handling paths have been ignored.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="l1"&gt;&lt;span class="s0"&gt;import &lt;/span&gt;&lt;span class="s1"&gt;java.util.Map; &lt;br /&gt;&lt;a name="l2"&gt; &lt;br /&gt;&lt;a name="l3"&gt;&lt;/span&gt;&lt;span class="s0"&gt;public class &lt;/span&gt;&lt;span class="s1"&gt;RegisterRequestHandler { &lt;br /&gt;&lt;a name="l4"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;private &lt;/span&gt;&lt;span class="s1"&gt;RegistrationService registrationService; &lt;br /&gt;&lt;a name="l5"&gt; &lt;br /&gt;&lt;a name="l6"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public &lt;/span&gt;&lt;span class="s1"&gt;RegisterRequestHandler(RegistrationService registrationService) { &lt;br /&gt;&lt;a name="l7"&gt; &lt;br /&gt;&lt;a name="l8"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;this&lt;/span&gt;&lt;span class="s1"&gt;.registrationService = registrationService; &lt;br /&gt;&lt;a name="l9"&gt;    } &lt;br /&gt;&lt;a name="l10"&gt; &lt;br /&gt;&lt;a name="l11"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public void &lt;/span&gt;&lt;span class="s1"&gt;handlePost(Map&amp;lt;String, String&amp;gt; params) { &lt;br /&gt;&lt;a name="l12"&gt;        RegisterDocument document = readDocument(params); &lt;br /&gt;&lt;a name="l13"&gt; &lt;br /&gt;&lt;a name="l14"&gt;        RegisterDocumentValidator validator = &lt;/span&gt;&lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;RegisterDocumentValidator(); &lt;br /&gt;&lt;a name="l15"&gt; &lt;br /&gt;&lt;a name="l16"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;if &lt;/span&gt;&lt;span class="s1"&gt;(validator.validate(document)) { &lt;br /&gt;&lt;a name="l17"&gt;            registrationService.register(document); &lt;br /&gt;&lt;a name="l18"&gt;            redirectToSuccessfulConfirmation(); &lt;br /&gt;&lt;a name="l19"&gt;        } &lt;/span&gt;&lt;span class="s0"&gt;else &lt;/span&gt;&lt;span class="s1"&gt;{ &lt;br /&gt;&lt;a name="l20"&gt;            persistDocument(document); &lt;br /&gt;&lt;a name="l21"&gt;            redirectToRegisterPath(); &lt;br /&gt;&lt;a name="l22"&gt;        } &lt;br /&gt;&lt;a name="l23"&gt; &lt;br /&gt;&lt;a name="l24"&gt;    } &lt;br /&gt;&lt;a name="l25"&gt; &lt;br /&gt;&lt;a name="l26"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;private void &lt;/span&gt;&lt;span class="s1"&gt;redirectToSuccessfulConfirmation() { &lt;br /&gt;&lt;a name="l27"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;// ...&lt;/span&gt;&lt;span class="s1"&gt; &lt;br /&gt;&lt;a name="l28"&gt;    } &lt;br /&gt;&lt;a name="l29"&gt; &lt;br /&gt;&lt;a name="l30"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;private void &lt;/span&gt;&lt;span class="s1"&gt;persistDocument(RegisterDocument document) { &lt;br /&gt;&lt;a name="l31"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;// ...&lt;/span&gt;&lt;span class="s1"&gt; &lt;br /&gt;&lt;a name="l32"&gt;    } &lt;br /&gt;&lt;a name="l33"&gt; &lt;br /&gt;&lt;a name="l34"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;private void &lt;/span&gt;&lt;span class="s1"&gt;redirectToRegisterPath() { &lt;br /&gt;&lt;a name="l35"&gt;        &lt;/span&gt;&lt;span class="s2"&gt;// ...&lt;/span&gt;&lt;span class="s1"&gt; &lt;br /&gt;&lt;a name="l36"&gt;    } &lt;br /&gt;&lt;a name="l37"&gt; &lt;br /&gt;&lt;a name="l38"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;private &lt;/span&gt;&lt;span class="s1"&gt;RegisterDocument readDocument(Map&amp;lt;String, String&amp;gt; params) { &lt;br /&gt;&lt;a name="l39"&gt;        RegisterDocument registerDocument = &lt;/span&gt;&lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;RegisterDocument(); &lt;br /&gt;&lt;a name="l40"&gt;        registerDocument.name = &lt;/span&gt;&lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;Field(params.get(&lt;/span&gt;&lt;span class="s3"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;)); &lt;br /&gt;&lt;a name="l41"&gt;        registerDocument.password = &lt;/span&gt;&lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;Field(params.get(&lt;/span&gt;&lt;span class="s3"&gt;&amp;quot;password&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;)); &lt;br /&gt;&lt;a name="l42"&gt;        registerDocument.userName = &lt;/span&gt;&lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;Field(params.get(&lt;/span&gt;&lt;span class="s3"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;)); &lt;br /&gt;&lt;a name="l43"&gt; &lt;br /&gt;&lt;a name="l44"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;return &lt;/span&gt;&lt;span class="s1"&gt;registerDocument; &lt;br /&gt;&lt;a name="l45"&gt;    } &lt;br /&gt;&lt;a name="l46"&gt;} &lt;br /&gt;&lt;a name="l47"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The handlePost entry point turns the name/value pair of parameters into a registraion document representing the users application for an account. The document is validated and if valid a request for a new account is passed on the appropriate service. If the document is not valid the user is redirected to the registraion application form with any warnings identified int he persisted registrtion document.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The registration document contains the fields we expect from the UI and very simple helper methods.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="l1"&gt;&lt;span class="s0"&gt;public class &lt;/span&gt;&lt;span class="s1"&gt;RegisterDocument { &lt;br /&gt;&lt;a name="l2"&gt;    Field userName; &lt;br /&gt;&lt;a name="l3"&gt;    Field password; &lt;br /&gt;&lt;a name="l4"&gt;    Field name; &lt;br /&gt;&lt;a name="l5"&gt; &lt;br /&gt;&lt;a name="l6"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public boolean &lt;/span&gt;&lt;span class="s1"&gt;hasWarning() { &lt;br /&gt;&lt;a name="l7"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;return &lt;/span&gt;&lt;span class="s1"&gt;userName.hasWarning() || password.hasWarning() || name.hasWarning(); &lt;br /&gt;&lt;a name="l8"&gt;    } &lt;br /&gt;&lt;a name="l9"&gt;} &lt;br /&gt;&lt;a name="l10"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The field class manages the value and any warnings.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="l1"&gt;&lt;span class="s0"&gt;public class &lt;/span&gt;&lt;span class="s1"&gt;Field { &lt;br /&gt;&lt;a name="l2"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;private &lt;/span&gt;&lt;span class="s1"&gt;String value; &lt;br /&gt;&lt;a name="l3"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;private &lt;/span&gt;&lt;span class="s1"&gt;Annotation annotation; &lt;br /&gt;&lt;a name="l4"&gt; &lt;br /&gt;&lt;a name="l5"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public &lt;/span&gt;&lt;span class="s1"&gt;Field(String value, Annotation annotation) { &lt;br /&gt;&lt;a name="l6"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;this&lt;/span&gt;&lt;span class="s1"&gt;.value = value; &lt;br /&gt;&lt;a name="l7"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;this&lt;/span&gt;&lt;span class="s1"&gt;.annotation = annotation; &lt;br /&gt;&lt;a name="l8"&gt;    } &lt;br /&gt;&lt;a name="l9"&gt; &lt;br /&gt;&lt;a name="l10"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public &lt;/span&gt;&lt;span class="s1"&gt;Field(String value) { &lt;br /&gt;&lt;a name="l11"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;this&lt;/span&gt;&lt;span class="s1"&gt;(value, Annotation.none); &lt;br /&gt;&lt;a name="l12"&gt;    } &lt;br /&gt;&lt;a name="l13"&gt; &lt;br /&gt;&lt;a name="l14"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public &lt;/span&gt;&lt;span class="s1"&gt;String getValue() { &lt;br /&gt;&lt;a name="l15"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;return &lt;/span&gt;&lt;span class="s1"&gt;value; &lt;br /&gt;&lt;a name="l16"&gt;    } &lt;br /&gt;&lt;a name="l17"&gt; &lt;br /&gt;&lt;a name="l18"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public void &lt;/span&gt;&lt;span class="s1"&gt;addWarning(String warning) { &lt;br /&gt;&lt;a name="l19"&gt;        annotation = &lt;/span&gt;&lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;Annotation(warning, Annotation.AnnotationType.warning); &lt;br /&gt;&lt;a name="l20"&gt;    } &lt;br /&gt;&lt;a name="l21"&gt; &lt;br /&gt;&lt;a name="l22"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public boolean &lt;/span&gt;&lt;span class="s1"&gt;hasWarning() { &lt;br /&gt;&lt;a name="l23"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;return &lt;/span&gt;&lt;span class="s1"&gt;annotation.getType() == Annotation.AnnotationType.warning; &lt;br /&gt;&lt;a name="l24"&gt;    } &lt;br /&gt;&lt;a name="l25"&gt;} &lt;br /&gt;&lt;a name="l26"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Perhpas choosing the most overloaded name (Annotation) this class models the validators response. Allowing warnings or infomation to be associated with the value. Used to report problems back to the user.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="l1"&gt;&lt;span class="s0"&gt;public class &lt;/span&gt;&lt;span class="s1"&gt;Annotation { &lt;br /&gt;&lt;a name="l2"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;enum &lt;/span&gt;&lt;span class="s1"&gt;AnnotationType { &lt;br /&gt;&lt;a name="l3"&gt;        warning, info, none &lt;br /&gt;&lt;a name="l4"&gt;    } &lt;br /&gt;&lt;a name="l5"&gt; &lt;br /&gt;&lt;a name="l6"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;private &lt;/span&gt;&lt;span class="s1"&gt;AnnotationType type; &lt;br /&gt;&lt;a name="l7"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;private &lt;/span&gt;&lt;span class="s1"&gt;String value; &lt;br /&gt;&lt;a name="l8"&gt; &lt;br /&gt;&lt;a name="l9"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public static &lt;/span&gt;&lt;span class="s1"&gt;Annotation none = &lt;/span&gt;&lt;span class="s0"&gt;new &lt;/span&gt;&lt;span class="s1"&gt;Annotation(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;, AnnotationType.none); &lt;br /&gt;&lt;a name="l10"&gt; &lt;br /&gt;&lt;a name="l11"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public &lt;/span&gt;&lt;span class="s1"&gt;Annotation(String value, AnnotationType type) { &lt;br /&gt;&lt;a name="l12"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;this&lt;/span&gt;&lt;span class="s1"&gt;.value = value; &lt;br /&gt;&lt;a name="l13"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;this&lt;/span&gt;&lt;span class="s1"&gt;.type = type; &lt;br /&gt;&lt;a name="l14"&gt;    } &lt;br /&gt;&lt;a name="l15"&gt; &lt;br /&gt;&lt;a name="l16"&gt; &lt;br /&gt;&lt;a name="l17"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public &lt;/span&gt;&lt;span class="s1"&gt;AnnotationType getType() { &lt;br /&gt;&lt;a name="l18"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;return &lt;/span&gt;&lt;span class="s1"&gt;type; &lt;br /&gt;&lt;a name="l19"&gt;    } &lt;br /&gt;&lt;a name="l20"&gt;} &lt;br /&gt;&lt;a name="l21"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="l1"&gt;&lt;span class="s0"&gt;public class &lt;/span&gt;&lt;span class="s1"&gt;RegisterDocumentValidator { &lt;br /&gt;&lt;a name="l2"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;public boolean &lt;/span&gt;&lt;span class="s1"&gt;validate(RegisterDocument document) { &lt;br /&gt;&lt;a name="l3"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;if &lt;/span&gt;&lt;span class="s1"&gt;(isEmpty(document.name.getValue())) { &lt;br /&gt;&lt;a name="l4"&gt;            document.name.addWarning(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;You must supply a name&amp;quot;&lt;/span&gt;&lt;span class="s1"&gt;); &lt;br /&gt;&lt;a name="l5"&gt;        } &lt;br /&gt;&lt;a name="l6"&gt; &lt;br /&gt;&lt;a name="l7"&gt;        &lt;/span&gt;&lt;span class="s3"&gt;// ...&lt;/span&gt;&lt;span class="s1"&gt; &lt;br /&gt;&lt;a name="l8"&gt; &lt;br /&gt;&lt;a name="l9"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;return &lt;/span&gt;&lt;span class="s1"&gt;document.hasWarning(); &lt;br /&gt;&lt;a name="l10"&gt;    } &lt;br /&gt;&lt;a name="l11"&gt; &lt;br /&gt;&lt;a name="l12"&gt;    &lt;/span&gt;&lt;span class="s0"&gt;private boolean &lt;/span&gt;&lt;span class="s1"&gt;isEmpty(String name) { &lt;br /&gt;&lt;a name="l13"&gt;        &lt;/span&gt;&lt;span class="s0"&gt;return &lt;/span&gt;&lt;span class="s1"&gt;(name == &lt;/span&gt;&lt;span class="s0"&gt;null &lt;/span&gt;&lt;span class="s1"&gt;|| name.length() == &lt;/span&gt;&lt;span class="s4"&gt;0&lt;/span&gt;&lt;span class="s1"&gt;); &lt;br /&gt;&lt;a name="l14"&gt;    } &lt;br /&gt;&lt;a name="l15"&gt;} &lt;br /&gt;&lt;a name="l16"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Any services use the documents as parameters. They are decoupled from the UI and can be more easily unit tested.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name="l5"&gt;&lt;/span&gt;&lt;span class="s2"&gt;public interface &lt;/span&gt;&lt;span class="s1"&gt;RegistrationService { &lt;br /&gt;&lt;a name="l6"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;void &lt;/span&gt;&lt;span class="s1"&gt;register(RegisterDocument document); &lt;br /&gt;&lt;a name="l7"&gt;} &lt;br /&gt;&lt;a name="l8"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/body&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/body&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-2975392682361276249?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/2975392682361276249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=2975392682361276249' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2975392682361276249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2975392682361276249'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2008/01/managing-session-state-in-persitent.html' title='Managing session state in persitent objects'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-8198616289062919910</id><published>2007-12-10T00:00:00.001Z</published><updated>2007-12-10T00:00:13.823Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sony Ericsson'/><category scheme='http://www.blogger.com/atom/ns#' term='W850i'/><category scheme='http://www.blogger.com/atom/ns#' term='Google Maps'/><title type='text'>Google Maps and the Sony Ericsson W850i</title><content type='html'>A friend of mine demoed &lt;a href="http://www.google.com/gmm/index.html"&gt;Google Maps&lt;/a&gt; My Location feature on his mobile phone. I had been using google maps for a while so downloaded the latest version - but alas no 'My Location' feature.&lt;br /&gt;&lt;br /&gt;Time for a firmware update&lt;br /&gt;&lt;br /&gt;Sony have a couple of apps required for the job. The PC Suite contains all the drivers and an update program for the firmware. Installation under &lt;a href="www.vmware.com"&gt;VMWare&lt;/a&gt; Fusion was seamless. The UI is quite flash but it still took me a couple of goes to realise that the 'C' button the instructions referred to was the Cancel button rather than the 3 button (it was late in the evening).&lt;br /&gt;&lt;br /&gt;Once the firmware was updated and GMM installed the location feature got me to within 100m - not bad as I was sitting in a basement flat! The directions feature is fab - working off a postcode the route to work (driving) was pretty good.&lt;br /&gt;&lt;br /&gt;As a bonus the software on the phone felt a lot more responsive - although some of the options had move around.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-8198616289062919910?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/8198616289062919910/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=8198616289062919910' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/8198616289062919910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/8198616289062919910'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/12/google-maps-and-sony-ericsson-w850i.html' title='Google Maps and the Sony Ericsson W850i'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-6538604187414898041</id><published>2007-10-29T20:28:00.001Z</published><updated>2007-10-29T20:28:32.576Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Polygot Programming analogy</title><content type='html'>I have been following a short email thread at work on &lt;a href="http://en.wikipedia.org/wiki/Polyglot_%28computing%29"&gt;Polygot&lt;/a&gt; programming (developing applications in more than one language). In its simplest form it is unlikely that an application contains a single language. Most applications involve some sort of XML :)&lt;br /&gt;&lt;br /&gt;While reading the thread and a side note on construction I was struck by the thought that one could draw an analogy between a computer language and a construction material.&lt;br /&gt;&lt;br /&gt;When putting together a car for example the designers choose materials that are suited to the job at hand. Each material chosen for its properties and application. A car made entirely using a material with a small set of properties (e.g. metal) would at the very least be very uncomfortable (steel tires).&lt;br /&gt;&lt;br /&gt;With this thought it mind it is surprising that people continue to maintain the premise that a software application should be written in a single language. At best you get an explosion of code around the areas where the chosen language is not that good. At worst you see huge frameworks to get around the limitations.&lt;br /&gt;&lt;br /&gt;Getting different languages to behave nicely together is not easy. Recent developments in leveraging runtime environments (JRuby, IronPython) make this interoperability simpler to manage but the problems rarely go away. The analogy with car manufacture works quite well - it is usually the interfaces between one material and the next where problems turn up.&lt;br /&gt;&lt;br /&gt;Pushing the analogy even further it has been some time since carpenters have joined pieces of wood using wooden pegs preferring in the main to use screws. Steel screws are stronger than brass but brass is preferred for wooden boats because it resists the effects of sea water (as well as being more aesthetically pleasing).&lt;br /&gt;&lt;br /&gt;Going back to automobile analogy the instrumentation systems use many different materials to delivery the required user interface, whilst the business end (engine) uses a more constrained list of materials (although in recent years this too has been growing). You could consider the instrumentation to be the equivalent of JavaScript on web applications whilst the engine corresponds to the back end systems (just a thought).&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-6538604187414898041?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/6538604187414898041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=6538604187414898041' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/6538604187414898041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/6538604187414898041'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/10/polygot-programming-analogy.html' title='Polygot Programming analogy'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-3425203797000014705</id><published>2007-10-18T01:01:00.001+01:00</published><updated>2007-10-18T01:01:05.453+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><title type='text'>Subversion missing tools</title><content type='html'>Recently our team source code repository developed a problem. To be fair I don't believe that the problem was with subversion but with a disk fault but the effect was the same - subversion had a problem with one of the revision files.&lt;br /&gt;&lt;br /&gt;After talking through the options we thought that we could replay the revisions using the svnadmin dump command and pipe the output into a new repository. Once for all the revisions up to the faulty one and again for those past the problem to HEAD. This did not work the receiving repository did not like having discontinuous build numbers.&lt;br /&gt;&lt;br /&gt;I tried various utilities that reported they could fix fsfs format svn databases but non found or fixed the problem.&lt;br /&gt;&lt;br /&gt;I ended up copying the previous revision over the faulty one - giving me nightmares about that missing revision. Now time to start digging through the backups for a good version of that file.&lt;br /&gt;&lt;br /&gt;If anyone knows of a good tool that can dig into the svn filesystem to allow hand patches of revisions please let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-3425203797000014705?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/3425203797000014705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=3425203797000014705' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3425203797000014705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3425203797000014705'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/10/subversion-missing-tools.html' title='Subversion missing tools'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-7301030607396532552</id><published>2007-10-11T00:26:00.001+01:00</published><updated>2007-10-11T00:27:57.988+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='iWork'/><title type='text'>Starting out with Numbers</title><content type='html'>I managed to hold out for quite some time (for me some time is past the launch date) before splashing out on a copy of &lt;a href="http://www.apple.com/iwork"&gt;iWork&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I have been using &lt;a href="http://www.microsoft.com/office"&gt;Excel&lt;/a&gt; on my Mac but wanted to know if Numbers (part of iWork) gave a fresh perspective on how a spreadsheet should work.&lt;br /&gt;&lt;br /&gt;I have to confess I have not spent a lot of time with Numbers yet but so far I have not been disappointed.&lt;br /&gt;&lt;br /&gt;Key features that work for me&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Column and row headers as explicit items but still addressable&lt;br /&gt;&lt;li&gt;Inline computation of results as a formula is filled into other columns&lt;br /&gt;&lt;li&gt;More intuitive insertion of newlines in cells (got it on the 2nd try)&lt;br /&gt;&lt;li&gt;Simple menus and text wrapping as an option on the toolbar&lt;br /&gt;&lt;li&gt;Sheets start small and grow as the data grows.&lt;br /&gt;&lt;li&gt;Easy import of my existing spreadsheets&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;It is still early days but so far very pleased :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-7301030607396532552?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/7301030607396532552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=7301030607396532552' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7301030607396532552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7301030607396532552'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/10/starting-out-with-numbers.html' title='Starting out with Numbers'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-464676626601815130</id><published>2007-10-04T18:25:00.001+01:00</published><updated>2007-10-04T18:25:18.718+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Small is Beautiful'/><title type='text'>The beauty of small applications</title><content type='html'>A great colleague of mine just posted an article suggesting the &lt;a href="http://blogs.agilefaqs.com/2007/08/27/death-of-enterprise-applications/"&gt;Death of Enterprise applications&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I like the post it has a lot in common with the approach taken on for command line UNIX applications. Each command line app has a well defined responsibility, the OS provides a simple set of capabilities that allow these applications to communicate with one another. Using the applications and the 'glue' provided by the OS users can perform far more complex tasks. Adding in the shell means that applications can be developed just using the existing applications and OS communication.&lt;br /&gt;&lt;br /&gt;In the world of web applications &lt;a href="http://www.opensymphony.com/sitemesh/"&gt;Sitemesh&lt;/a&gt; provides the glue roughly equivalent to the OS glue provided by the command shell. By developing applications in the &lt;a href="http://en.wikipedia.org/wiki/Progressive_enhancement"&gt;progressive enhancement&lt;/a&gt; style allows web applications to be glued together to provide a cohesive web experience to the user.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Other benefits&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt; * Each web application is partitioned into its own space. (loose coupling)&lt;br /&gt; * 3rd party applications can be incorporated into the user experience more easily&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-464676626601815130?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/464676626601815130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=464676626601815130' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/464676626601815130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/464676626601815130'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/10/beauty-of-small-applications.html' title='The beauty of small applications'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-1010383717395083824</id><published>2007-10-04T18:22:00.005+01:00</published><updated>2007-10-04T18:22:32.326+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtualisation'/><title type='text'>Virtuosity</title><content type='html'>For some time developers writing applications for managed virtual environments have been enjoying the benefits of being able to interrogate and control the and generate code at runtime. When used appropriately these additional elements have delivered significant advantages - particularly in the tools world. Mocking libraries would not be easy to implement in a non-managed environment.&lt;br /&gt;&lt;br /&gt;In the world of build management we have seen an explosion of tools that make it easier to deliver components and applications into a production environment.&lt;br /&gt;&lt;br /&gt;One element of the picture that we have not seen a lot of progress on is environment control and deployment. Currently there seems little support for automated environment setup or deployment testing.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-1010383717395083824?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/1010383717395083824/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=1010383717395083824' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1010383717395083824'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1010383717395083824'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/10/virtuosity.html' title='Virtuosity'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-4989724391724930191</id><published>2007-10-04T18:22:00.003+01:00</published><updated>2007-10-04T18:22:21.941+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Functional Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Sloth'/><category scheme='http://www.blogger.com/atom/ns#' term='FitNesse'/><title type='text'>Sloth Development</title><content type='html'>Sloth Development Update&lt;br /&gt;========================&lt;br /&gt;&lt;br /&gt;So I have been working on [Sloth](http://sloth.sourceforge.net) for a few weeks now - mostly on the back-end compiler and execution engine. The journey has been quite interesting so far. A model for Functional Integration Tests is evolving in the code base and this is making the testing and Jave code generation easier. Since the test will need to be stored somewhere (initially in the FitNesse wiki format) the engine needs a way of loading and saving the pages. This has been extracted into storage specific repositories that are responsible for mapping to and from the storage system to the model.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-4989724391724930191?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/4989724391724930191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=4989724391724930191' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4989724391724930191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4989724391724930191'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/10/sloth-development.html' title='Sloth Development'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-7244312596878322154</id><published>2007-10-04T18:22:00.001+01:00</published><updated>2007-10-04T18:22:07.493+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MacBook Pro'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><title type='text'>Essential Software for a Cooler Mac</title><content type='html'>I moved over to a Mac early in 2006 and have been impressed. It has done everything I have asked of it and more. It has become an essential part of my life both as a work tool for software development and in my personal life for music and photo management.&lt;br /&gt;&lt;br /&gt;But one irritation is how hot it runs. I know that this is a generally a problem with laptops but I had hoped that my MacBook Pro would have solved this issue.&lt;br /&gt;&lt;br /&gt;So after a couple of years of having a warm lap a colleague of mine put me on to &lt;a href="http://homepage.mac.com/holtmann/eidac/"&gt;smsFanControl&lt;/a&gt; which allows control over the system fan's minimum speed. The default 1000 rpm means that I get a hot lap. Pushing this up to 2500 or 3000 rpm really makes a difference and to my ears does not make that much more noise.&lt;br /&gt;&lt;br /&gt;One very happy chap and would really recommend giving the app a try. &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-7244312596878322154?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/7244312596878322154/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=7244312596878322154' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7244312596878322154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7244312596878322154'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/10/essential-software-for-cooler-mac.html' title='Essential Software for a Cooler Mac'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-4024139093848640194</id><published>2007-09-20T00:35:00.001+01:00</published><updated>2007-09-27T14:30:47.964+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Story Wall'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Keep the story wall clean &amp; tidy!</title><content type='html'>Like so many artefacts produced and consumed during a software project keeping them up to data and simple is vitally important.&lt;br /&gt;&lt;br /&gt;For an agile project where the aim is to keep the number of such artefacts as low as possible this should be straightforward but it is easy to let this sort of project hygiene slip. After all if everything is working well the cards only live for a short time, they collect data during the iteration and perhaps into testing but after that they are of little value. If they live for such a short time why is it important that the cards be written clearly, identify where they came from for traceability etc.&lt;br /&gt;&lt;br /&gt;Keeping the story cards clean helps the team by reducing the number of times related information is sought. For each discrepancy between the card and its context someone needs to work out what the differences are, if they are important and what should happen. By not reflecting this on the card as a simple note edit it is likely that someone else will need to go through the same process.&lt;br /&gt;&lt;br /&gt;It is arguable that if this situation arises that the stories are too big and the cards are spending too long in development. I like to make sure that each story is a coherent vertical slice of functionality with a starting point and user visible result. Sometimes it is not practical with this constraint to slice the work into a story that is both quick to implement and satisfy the requirement to deliver a useful and visible result.&lt;br /&gt;&lt;br /&gt;It does and should not take much to keep the wall clean. If it does then story wall hygiene is probably not your biggest problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-4024139093848640194?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/4024139093848640194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=4024139093848640194' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4024139093848640194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4024139093848640194'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/09/keep-story-wall-clean-and-tidy.html' title='Keep the story wall clean &amp; tidy!'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-5800280766824042438</id><published>2007-07-10T12:54:00.001+01:00</published><updated>2007-07-30T23:16:10.884+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Functional Testing'/><title type='text'>Sloth - The lazy man's path to FitNesse</title><content type='html'>&lt;h1&gt;Sloth Into&lt;/h1&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="http://sloth.sourceforge.net"&gt;Sloth&lt;/a&gt; is a new open source project targeting the Functional Integration Testing space. The basic idea behind Sloth is to provide an extensible development and execution environment for &lt;a href="http://www.fitnesse.org"&gt;FitNesse&lt;/a&gt; wiki pages.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Personally I have always been interested in efficient frameworks and code generation and one of the ideas we came up with was to generate &lt;a href="http://java.sun.com"&gt;Java&lt;/a&gt; code from the test specification in the wiki page which could then be compiled and executed.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This code generation approach has a number of advantages.&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;There are many, many tools for managing compiled Java code&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Bytecode is more compact than wiki source if the tests code needs to be moved around&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-5800280766824042438?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/5800280766824042438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=5800280766824042438' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/5800280766824042438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/5800280766824042438'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/07/sloth-lazy-man-path-to-fitnesse.html' title='Sloth - The lazy man&amp;#39;s path to FitNesse'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-3213245646017202901</id><published>2007-06-18T13:47:00.001+01:00</published><updated>2007-07-12T17:32:19.189+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Virtualisation'/><title type='text'>Virtual Journys #1</title><content type='html'>For some time I have been a great fan of virtual hardware and the now opportunities it brings.&lt;br /&gt;&lt;br /&gt;For most of this year I have been working on a large enterprise scale Java application targeting IBM WebSphere. Currently this configuration is only available on Windows and Linux so my Mac OS-X is out in the cold. During the day I work using windows and in the evening OS X for my own projects.&lt;br /&gt;&lt;br /&gt;With the availability of Parallels and VMWare's virtualisation systems for the Mac new options are available. The most obvious is to create a Windows development envrionment for work running entirely in the guest Windows operating system. I thought I would try a different options. I would keep the source on the host OS X filesystem and perform builds using the virtual machine. Both Parammels and VMWare allow the host filesystem to be accessed as a network server. For windows this means that you can map the host files as a network mapped drive.&lt;br /&gt;&lt;br /&gt;My first experiment used Parallels. The source was located on the host drive and I mapped a drive from the guest Windows system to the host source folder. I use helper batch files to move around the source and do tageted builds (e.g. bvt for ant -f custom-build.xml bvt) which seemed to be a problem for some reason. To run the CMD files I found I had to type bvt.cmd rather than bvt. It appears that the bvt is not sufficient to find and run bvt.cmd - very odd.&lt;br /&gt;&lt;br /&gt;Otherwise things appear to work fine.&lt;br /&gt;&lt;br /&gt;I exported the guest image using the VMWare importer tool to the host filesystem and booted the new VM in VMWare and set up the mapped drive in the same way. This time bvt was sufficient to find the bvt.cmd so there must be a difference in the way the shared filesystems work.&lt;br /&gt;&lt;br /&gt;All the VMS are running on an external USB drive. Having the VMs there is convenient if I want to boot them on another computer and I find that the performance is faster with a second drive. I have used two types of drive. The first is a simple 160GByte laptop style drive which is convenient for travel. The other is a 150GByte 10,000 RPM raptor drive which is really sweet and I think faster indicating to me at least that USB is not the limiting factor for the slower drives.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-3213245646017202901?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/3213245646017202901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=3213245646017202901' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3213245646017202901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3213245646017202901'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/06/virtual-journys-1.html' title='Virtual Journys #1'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-7560186384431697768</id><published>2007-06-16T15:41:00.001+01:00</published><updated>2007-06-16T15:41:40.223+01:00</updated><title type='text'>Terminate SQL Server processes for a database</title><content type='html'>I have come accross the same problem several times now and have had to google for the answer. This one is the best one I have found so far. I take no credit for the script but I have lost the original link so my appologies to the original author. If you read this please let me know so I can supply credit.&lt;br /&gt;&lt;br /&gt;declare @spidstr varchar(8000)&lt;br /&gt;&lt;br /&gt;select @spidstr=coalesce(@spidstr,'')+'kill '+convert(varchar, spid)+ '; ' from master..sysprocesses WHERE dbid=db_id('database name')&lt;br /&gt;&lt;br /&gt;if @spidstr != '' exec (@spidstr)&lt;br /&gt;&lt;br /&gt;The script can actually be put on a single line which makes running it from Ant (etc) very easy.&lt;br /&gt;&lt;br /&gt;Quite often as a developer I need to rebuild my test database. However it is often the case that there are processes still running. It would be nice to track them all down but this is time consuming and it is often easier just to kill the processes in the database server and rebuild then retest.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-7560186384431697768?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/7560186384431697768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=7560186384431697768' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7560186384431697768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7560186384431697768'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/06/terminate-sql-server-processes-for.html' title='Terminate SQL Server processes for a database'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-7435902058871719870</id><published>2007-06-03T22:23:00.005+01:00</published><updated>2007-06-03T22:23:20.098+01:00</updated><title type='text'>Why I bought  Mac</title><content type='html'>Why I bought a Mac&lt;br /&gt;==================&lt;br /&gt;&lt;br /&gt;Just over a year ago I was working in the US on a Java project. My day to day work was was done on a PC and I was looking for something different. An addicted laptop buyer I had been through a number of dells and had a very nice Veio but still I was not satisfied. I had tried customisations of the UI and alternate technologies for software development. In a recent article Martin Fowler talked about boredom when it came to Microsoft and its development tools. Maybe that was it but for whatever reason with the advent of the Intel based macs and virtualization I could run windows if I needed to in a VM but I would use the native OS for my day to day requirements.&lt;br /&gt;&lt;br /&gt;So it is just over a year later was the decision I made a wise one? Hell yes. The day I turned on my mac and saw it boot from cold in 25 seconds was a changing point. A year later it still boots from cold in just over 25 seconds. I have installed and uninstalled lots of software and still it continues to perform. Applications start reliably in the same time that they did when they were first installed. (I had always found that I needed to reimage my windows system once a year to get it back up to speed).&lt;br /&gt;&lt;br /&gt;So I sit as my desk typing this message&lt;br /&gt;&lt;br /&gt;Macs Rock&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-7435902058871719870?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/7435902058871719870/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=7435902058871719870' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7435902058871719870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7435902058871719870'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/06/why-i-bought-mac.html' title='Why I bought  Mac'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-3554080567395389792</id><published>2007-06-03T22:23:00.003+01:00</published><updated>2007-06-03T22:23:07.463+01:00</updated><title type='text'>Maintaining principles, values and culture</title><content type='html'>Maintaining principles, values and culture&lt;br /&gt;==========================================&lt;br /&gt;&lt;br /&gt;I am currently working out of my home country on assignment in Sweden. Anyway, working away tends to means that I quite often get to spend time with my colleagues over dinner and talk about work, technology, people and generally put the world to rights.&lt;br /&gt;&lt;br /&gt;The other evening was just such an event and after talking about work and life in general we started talking about company values and I recounted some things that I had seen during my life as a professional software engineer.&lt;br /&gt;&lt;br /&gt;In the early life of a company the company is a direct reflection of its employers or more typically the mind of the person heading up the company. In this early period especially for software companies it is likely that the company has a very casual attitude to dress and personal expression. The people joining the company at this time are often attracted to the company because of this relaxed approach. Encouraged that hard work and thinking are valued over conforming to corporate stereotypes.&lt;br /&gt;&lt;br /&gt;As companies grow they attract employees with a different view and customers who may expect a different set of values. This difference quite often sets up conflicts or 'growing pains'.&lt;br /&gt;&lt;br /&gt;I believe that these changes in company culture and expectations in most companies go unnoticed or are simply accepted as part of growing up. But should this be the case? If I were to visit the offices of a design company I would expect to be surprised. I would expect a 'different' approach to office layout, dress and a more 'creative' environment. Why? Because I am looking for that type of organisation.&lt;br /&gt;&lt;br /&gt;So why is it that when looking for someone to help with a software development problem I expect to see people in suites? Surly I am looking for creative solutions to my software development issues not someone who will try and apply a formula to my problems. My personal view is that a company should decide what type of company it wants to be rather than just become what everyone else expects it to be.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-3554080567395389792?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/3554080567395389792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=3554080567395389792' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3554080567395389792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3554080567395389792'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/06/maintaining-principles-values-and.html' title='Maintaining principles, values and culture'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-1775504001337797251</id><published>2007-06-03T22:23:00.001+01:00</published><updated>2007-06-03T22:23:00.761+01:00</updated><title type='text'>Keeping Unit Tests Small</title><content type='html'>&lt;p&gt;Unit testing has become one of the mainstays of modern software development. Techniques such as Test Driven Development have delivered significant benefits in ensuring that the developed software is testable.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Designing good tests however seems to be a skill in its own right. I have seem many people struggle to hit the right level. I am not surprised by this - it took me some time to become happy with with my unit tests.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;So I thought I would put some time to documenting what I have learnt about writing good unit tests.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;One test - one feature&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Keep the environment out of the tests.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;One test - one feature&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;It is very tempting to shore up test code with many assertions. I have found that this makes the tests overly brittle. On failure more diagnosis is required to find&lt;br /&gt;the cause of the problem. With more than one assertion you need more than the test name to find the code causing a problem.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Testing a single feature also makes it easier to name the test - name it after the feature! Not after the method name or class. Grouping the tests together for tests referring to a single class is useful for organisational purposes but beware of reflecting the method names into the tests.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-1775504001337797251?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/1775504001337797251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=1775504001337797251' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1775504001337797251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1775504001337797251'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/06/keeping-unit-tests-small.html' title='Keeping Unit Tests Small'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-3289326374650430224</id><published>2007-06-03T22:22:00.001+01:00</published><updated>2007-06-03T22:22:45.312+01:00</updated><title type='text'>A language for test</title><content type='html'>Writing tests is hard&lt;br /&gt;=====================&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Writing unit tests is hard. Often harder than writing the application. Our current choice of languages does not help much. General purpose programming languages were designed to solve application development problems not necessarily help us test the application under development. Virtual machines such as Sun's JVM and Microsoft's .NET runtime provide basic support by exposing the code meta-model so that test frameworks can be developed. To my knowledge 'test frameworks' have not been made high priority aspects of current language design.&lt;br /&gt;&lt;br /&gt;Initiatives like [Behaviour-Driven Development](http://behaviour-driven.org) (BDD) add new dimensions to verifying the behaviour of an application. BDD uses a constrained analysis language to define the intended behaviour for the domain model. This behaviour statement is then used to generate executable code that it then run against the application.&lt;br /&gt;&lt;br /&gt;BDD is an important step but is by its nature a confined to particular types of application (those with a domain model).&lt;br /&gt;&lt;br /&gt;So what could a test language look like?&lt;br /&gt;----------------------------------------&lt;br /&gt;&lt;br /&gt;test-case: test case name&lt;br /&gt;given ::=&lt;br /&gt;  BankAccount (Balance =&gt; 12.50, OverDraftLimit =&gt; 100)&lt;br /&gt;when&lt;br /&gt;&lt;br /&gt;verify that ::=&lt;br /&gt;  BankAccount&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-3289326374650430224?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/3289326374650430224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=3289326374650430224' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3289326374650430224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/3289326374650430224'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/06/language-for-test.html' title='A language for test'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-424872506253411197</id><published>2007-05-28T01:44:00.001+01:00</published><updated>2007-05-28T01:44:57.244+01:00</updated><title type='text'>GPS Units and the Mac</title><content type='html'>&lt;p&gt;Just over a year ago I switched to one of the nice new MacBook Pro's with Intel chips in them. This was a hard decision. I had been a Software Developer on the Windows platform for just over 20 years and felt pretty tied to the platform. But life moves on and I had the good fortune to be working on a Java project and hoped to do more with Ruby so a Mac made sense. I also wanted to immerse myself into a different OS and the Mac seemed ideal.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I still had some reliance on Windows based software so made sure that I got hold of a copy of &lt;a href="http://www.parallels.com"&gt;Paralells&lt;/a&gt; but have needed it less and less. One bone of contention though was the lack of support for GPS software. Initially the USB drivers just did not work in the virtual machines so I had to rely on PCs here and there to transfer my walk information.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I was delighted to read that &lt;a href="http://www.garmin.com"&gt;Garmin&lt;/a&gt; have stated work on supporting Macs! Oh Happy day.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-424872506253411197?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/424872506253411197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=424872506253411197' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/424872506253411197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/424872506253411197'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/05/gps-units-and-mac.html' title='GPS Units and the Mac'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-990502592816886586</id><published>2007-05-28T01:02:00.000+01:00</published><updated>2007-05-28T01:03:21.314+01:00</updated><title type='text'>String Template for code generation</title><content type='html'>I have been a fan of the &lt;a href="http://www.antlr.org"&gt;ANTLR&lt;/a&gt; parser generator by &lt;a href="http://stringtemplate.org/misc/contact"&gt;Terrance Parr&lt;/a&gt; for some years and used it in some of the tools I have developed to make life a little easier.&lt;br /&gt;Recently on a project I was looking at the output stage of a Java code generator for FitNesse fixtures and thought to compare the way the code was being produced (inline strings and print statements) to ANTLR and discovered that version 3 of ANTLR uses the &lt;a href="http://stringtemplate.org"&gt;StringTemplate&lt;/a&gt; library. Further digging revealed a really cool library for text file generation based on a domain model.&lt;br /&gt;Really cool&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-990502592816886586?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/990502592816886586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=990502592816886586' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/990502592816886586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/990502592816886586'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/05/string-template-for-code-generation.html' title='String Template for code generation'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-2367006011406039515</id><published>2007-05-14T22:35:00.001+01:00</published><updated>2007-05-14T22:35:37.593+01:00</updated><title type='text'>FreeMind Retrospectives</title><content type='html'>I was turned on to FreeMind by &lt;a href="http://www.dannorth.net"&gt;Dan North&lt;/a&gt; and I have to say it has been some time since I have been so impressed with a piece of software (commercial or open source). It just works in an intuitive and immediate way. Once installed I was happily brainstorming away on ideas that have been sitting in my mental todo list for quite a while.&lt;br /&gt;On my current project the team is not co-located and this causes problems with team retrospectives. Working on a whiteboard does sort of work as long as the contents is regularly read out to everyone. Web cams might be an option but even over a fast link it is difficult to get sufficient quality for text to be readable. I have strongly resisted using a software tool and desktop sharing during retrospectives because I feel a lot is lost in the process of capturing the teams thoughts.&lt;br /&gt;But I think FreeMind is different - speed of entry is key to capturing information quickly and FreeMind seems to have the right keystrokes for the right commands (Mac and Windows versions). Ok it helps if you are a keyboard junkie rather than a cat chasing mice! Spreadsheets and Word processors would allow similar capture speeds but then you are left with lists and headings and to be honest the results are fairly boring and require time to clean up and format into anything presentable.&lt;br /&gt;Mind Maps are different. They more closely match the organic data collection process of a retrospective. The HTML export option should help those of us using Wikis to manage project documentation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:14pt;"&gt;&lt;strong&gt;First retrospective&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For the first retrospective we used NetMeeting to share a single desktop to the remote teams. One person was designated as the scribe - initially a new team member of the team but someone outside the team would have been better.&lt;br /&gt;The results were impressive. I was able to keep up with the conversation, summarise the discussion and contribute occasionally. The cool part was when it came to adding actions to the items. The actions naturally entered as child nodes on the mind map to the issue and could be flagged with a simple icon.&lt;br /&gt;The really cool part was after a quick export to .jpg file and an upload the results of the retrospective were on the project wiki for all to see.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:14pt;"&gt;&lt;strong&gt;Tools support but do not make a retrospective&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Although I have dwelled a lot on how FreeMind has helped run retrospectives for distributed teams it is important not to let the tool drive the process. For co-located teams I am still a big fan of index cards for rapid collection of raw opinion.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-2367006011406039515?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/2367006011406039515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=2367006011406039515' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2367006011406039515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2367006011406039515'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/05/freemind-retrospectives.html' title='FreeMind Retrospectives'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-1490394631647039470</id><published>2007-05-14T21:53:00.001+01:00</published><updated>2007-05-14T22:23:30.393+01:00</updated><title type='text'>MSDE Setup</title><content type='html'>&lt;strong&gt;Old Entry&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;I have been setting up MSDE a few times recently (same server) to operate as a remote database server. Out of the box the MSDE engine installs for Windows security and no network access. I also needed to use SQL security mode because I could not obtain a trusted connection to the server.&lt;br /&gt;The setup parameters I used are noted here so I don't forget them and incase they are useful to someone else trying to do the same thing.&lt;br /&gt;&lt;pre&gt;setup DISABLENETWORKPROTOCOLS=0 SAPWD=some.strong.password SECURITYMODE=SQL&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-1490394631647039470?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/1490394631647039470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=1490394631647039470' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1490394631647039470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1490394631647039470'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/05/msde-setup.html' title='MSDE Setup'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-2046475322366464380</id><published>2007-04-02T14:10:00.001+01:00</published><updated>2007-04-02T14:11:44.596+01:00</updated><title type='text'>Software Projects as Rock Climbing</title><content type='html'>&lt;br /&gt;   &lt;p&gt;This post &lt;a href="http://www.codinghorror.com/blog/archives/000830.html"&gt;http://www.codinghorror.com/blog/archives/000830.html&lt;/a&gt; on &lt;a href="http://www.codinghorror.com"&gt;CodingHorror&lt;/a&gt; struck a chord with me. I had always thought that my favourite sport was similar to writing software but this really makes the point well.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-2046475322366464380?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/2046475322366464380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=2046475322366464380' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2046475322366464380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2046475322366464380'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/04/software-projects-as-rock-climbing.html' title='Software Projects as Rock Climbing'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-6885099324558299300</id><published>2007-03-01T07:38:00.000Z</published><updated>2007-03-01T07:42:07.116Z</updated><title type='text'>Simple Cruise Control Block Diagram</title><content type='html'>I realized today that I had not seen a simple block diagram of a typical continuous integration system and how it interacts so I thought I would put one together.&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_BP9ytUtoakk/ReaDT1jJnBI/AAAAAAAAAAM/H7gh7T_3vuE/s1600-h/simple_cruise_loop_block_diagram.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_BP9ytUtoakk/ReaDT1jJnBI/AAAAAAAAAAM/H7gh7T_3vuE/s320/simple_cruise_loop_block_diagram.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5036857610075741202" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-6885099324558299300?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/6885099324558299300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=6885099324558299300' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/6885099324558299300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/6885099324558299300'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/02/simple-cruise-control-block-diagram.html' title='Simple Cruise Control Block Diagram'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BP9ytUtoakk/ReaDT1jJnBI/AAAAAAAAAAM/H7gh7T_3vuE/s72-c/simple_cruise_loop_block_diagram.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-828644124335870781</id><published>2007-02-13T16:37:00.000Z</published><updated>2007-02-19T09:02:25.777Z</updated><title type='text'>Software Development Tools</title><content type='html'>&lt;span style="font-size:15pt;"&gt;&lt;strong&gt;Java Development&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Eclipse (Web Development) &lt;a href="http://www.eclipse.org/webtools/"&gt;http://www.eclipse.org/webtools/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Checkstyle Plugin&lt;/li&gt;&lt;li&gt;Format on save plugin&lt;/li&gt;&lt;li&gt;JAD Plugin (Windows)&lt;/li&gt;&lt;li&gt;JUnit &lt;a href="http://www.jnunit.org"&gt;http://www.jnunit.org&lt;/a&gt;&lt;/li&gt;&lt;li&gt;CheckStyle &lt;a href="http://checkstyle.sourceforge.net/"&gt;http://checkstyle.sourceforge.net/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Corbatura&lt;/li&gt;&lt;li&gt;Simian&lt;/li&gt;&lt;li&gt;AspectJ&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:15pt;"&gt;&lt;strong&gt;.NET Development&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Microsoft Visual Studio &lt;a href="http://msdn.microsoft.com"&gt;http://msdn.microsoft.com&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Resharper - essential refactoring support &lt;a href="http://www.jetbrains.com/resharper/"&gt;http://www.jetbrains.com/resharper/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;NUnit &lt;a href="http://www.nunit.org"&gt;http://www.nunit.org&lt;/a&gt;&lt;/li&gt;&lt;li&gt;NAnt &lt;a href="http://nant.sourceforge.net/"&gt;http://nant.sourceforge.net/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;NullSoft Installer &lt;a href="http://nsis.sourceforge.net"&gt;http://nsis.sourceforge.net&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:15pt;"&gt;&lt;strong&gt;Ruby Development&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;RadRails &lt;a href="http://www.radrails.org"&gt;www.radrails.org&lt;/a&gt;&lt;/li&gt;&lt;li&gt;TextMate &lt;a href="http://macromates.com/"&gt;http://macromates.com/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:15pt;"&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Subversion &lt;a href="http://subversion.tigris.org/"&gt;http://subversion.tigris.org/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Trac&lt;/li&gt;&lt;li&gt;ANLTR &lt;a href="http://www.antlr.org"&gt;http://www.antlr.org&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Parallels&lt;/li&gt;&lt;li&gt;Emacs&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-828644124335870781?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/828644124335870781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=828644124335870781' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/828644124335870781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/828644124335870781'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/02/software-development-tools.html' title='Software Development Tools'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-475168151393181750</id><published>2007-02-12T11:15:00.000Z</published><updated>2007-02-08T14:50:19.625Z</updated><title type='text'>How done it looks implies how done it is</title><content type='html'>Kathy Sierra and Dan Russell have an excellent article on prototyping and how the prototype influences the audience&lt;br /&gt;&lt;a href="http://headrush.typepad.com/creating_passionate_users/2006/12/dont_make_the_d.html"&gt;http://headrush.typepad.com/creating_passionate_users/2006/12/dont_make_the_d.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Makes very interesting reading. Have to admit I have fallen into this trap before and spent some time persuading people that the application is not as advanced as the prototype could make them believe. Matching the maturity of the prototype to the maturity of the application makes a lot of sense.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-475168151393181750?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/475168151393181750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=475168151393181750' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/475168151393181750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/475168151393181750'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/02/how-done-it-looks-implies-how-done-it.html' title='How done it looks implies how done it is'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-7061936539847892816</id><published>2007-02-01T11:04:00.000Z</published><updated>2007-02-01T15:40:34.332Z</updated><title type='text'>Courage to do the right thing...</title><content type='html'>Doing the “right thing” is often hard&lt;br /&gt;&lt;br /&gt;Being sure that you know the right thing to do is not that easy either.&lt;br /&gt;&lt;br /&gt;So why do we often need courage to do the right thing? Surely doing the right thing is what we do all the time right?&lt;br /&gt;&lt;br /&gt;We all live in an imperfect world constrained but time, resources and our tools. Often doing the right thing seems too expensive to do and doing some less than perfect updates to the code or environment feels so much more attractive.&lt;br /&gt;&lt;br /&gt;So why do the right thing when doing a less than optimal change delivers a result that works? Surely doing the 'simplest thing' that could possibly work says that making pragmatic decisions is ok?&lt;br /&gt;&lt;br /&gt;Often it is difficult to put into words why doing something is the right thing to do. Often is is just a feeling that something needs to change. The trouble with these sorts of feelings is that the do not go away - and in a way I am glad that they don't because often putting off doing something about them turns out to be a bad idea.&lt;br /&gt;&lt;br /&gt;If at all possible listen to your feelings 'do the right thing' and change the code.&lt;br /&gt;&lt;br /&gt;&lt;!-- technorati tags start --&gt;&lt;p style="text-align:right;font-size:10px;"&gt;Technorati Tags: &lt;a href="http://www.technorati.com/tag/Courage" rel="tag"&gt;Courage&lt;/a&gt;&lt;/p&gt;&lt;!-- technorati tags end --&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-7061936539847892816?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/7061936539847892816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=7061936539847892816' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7061936539847892816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7061936539847892816'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/02/courage-to-do-right-thing.html' title='Courage to do the right thing...'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-1067612912283419844</id><published>2007-01-31T23:06:00.000Z</published><updated>2007-02-01T08:55:53.658Z</updated><title type='text'>On the subject of lists</title><content type='html'>When I am under pressure to deliver and there are a million and one things going on both in and out of my life I start making lists. I know that I should do this all the time because I know it really works but when the number of items on the list is small I always think I can hold the list in my head. It is only when things get interesting that I resort to list making.&lt;br /&gt;&lt;br /&gt;But what should go on these lists. The bottom line is almost everything. I keep at least two lists both in priority order, one for work and the other for the bits I try to do out of work.&lt;br /&gt;&lt;br /&gt;The list for work items helps me maintain balance by keeping the high priority items at the top I know that I just need to work my way down the list. By having a list for personal stuff I can make sure that in the odd moments when I am not actually working I know what I should be doing.&lt;br /&gt;&lt;br /&gt;Having the lists mean that I do not have to keep remembering what to do next.&lt;br /&gt;&lt;br /&gt;Simplify your life - make lists!&lt;br /&gt;There are some excellent descriptions of how lists can be made to work for you over at the &lt;a href="http://www.pragmaticprogrammer.com"&gt;http://www.pragmaticprogrammer.com&lt;/a&gt;. In particular &lt;a href="http://www.pragmaticprogrammer.com/titles/rdbcd/index.html"&gt;http://www.pragmaticprogrammer.com/titles/rdbcd/index.html&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-1067612912283419844?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/1067612912283419844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=1067612912283419844' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1067612912283419844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/1067612912283419844'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/01/on-subject-of-lists.html' title='On the subject of lists'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-4503959182331660687</id><published>2007-01-31T13:17:00.000Z</published><updated>2007-02-01T08:01:48.264Z</updated><title type='text'>Managing your day</title><content type='html'>Working as a coach I sometimes hear the complaint that interruptions and additional tasks cause significant pain to a development team.&lt;br /&gt;&lt;br /&gt;Often people are asked to do things that were unknown at the start of a sprint/iteration but appear to be urgent/important when the sprint is under way. Since these activities are unplanned and unbudgeted taking on these tasks can put the sprint goals in jeopardy. It may be that the requests seem innocuous - an hour here or there, what harm can it cause?&lt;br /&gt;&lt;br /&gt;Individually these additional tasks may not seem significant but these interruptions add up and can start taking over. They also establish a pattern for the future and people get used to asking for more and more of your time.&lt;br /&gt;&lt;br /&gt;Switching tasks and not being able to complete one task before being pulled off onto another one should not be underestimated. It is not easy to pick up some development work even after a break of an hour or two!&lt;br /&gt;&lt;br /&gt;Keep a list of things that you have done during a sprint that can be used to adjust capacity in the next one. Make sure that the Scrum Master or Iteration Manager is aware of these interruptions (they should be consulted anyway). Make sure that these additional tasks really are more important that the current goals!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-4503959182331660687?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/4503959182331660687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=4503959182331660687' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4503959182331660687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/4503959182331660687'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/01/managing-your-day.html' title='Managing your day'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-8264816903218658850</id><published>2007-01-31T13:14:00.000Z</published><updated>2007-01-31T13:27:10.378Z</updated><title type='text'>Pair Programming</title><content type='html'>Not sure if this is just a way of not forgetting a good blog entry or not but Naresh Jain has written a very useful FAQ on pair programming at &lt;a href="http://jroller.com/page/njain?entry=pairing_faqs"&gt;http://jroller.com/page/njain?entry=pairing_faqs&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you are interested in trying out pair programming or have found it does not appear to work for you then I suggest you check it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-8264816903218658850?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/8264816903218658850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=8264816903218658850' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/8264816903218658850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/8264816903218658850'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/01/pair-programming.html' title='Pair Programming'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-2878504540503799827</id><published>2007-01-29T10:29:00.000Z</published><updated>2007-02-01T10:38:10.561Z</updated><title type='text'>Testing Application fail-over using Virtual Hardware</title><content type='html'>Application availability is one of the key features of many designs. e-commerce web applications are a particular example where the application should be available to customers as much as possible. A common model to achieve this is to have a number of servers available. Should one server fail the other servers pick up the request and deliver the result to the customers computer.&lt;br /&gt;&lt;br /&gt;Although this design is simple in concept and with a lot modern server systems straightforward to implement testing the failure scenarios is often a complex and demanding task. Typically this sort of testing is done manually by disconnecting a server from the network or terminating processes on the server.&lt;br /&gt;&lt;br /&gt;Virtual hardware can provide a cost effective alternative and provides capabilities that are not available when using physical servers.&lt;br /&gt;Lets take an example&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The customer clicks on the ‘Add to basket’ for a widget&lt;/li&gt;&lt;li&gt;The request is serviced by server A and returns a page representing the basket containing the selected widget.&lt;/li&gt;&lt;li&gt;The customer clicks the ‘Proceed to checkout’ button&lt;/li&gt;&lt;li&gt;The request is serviced by server A and returns a page requesting payment details for the basket containing the widget.&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;/ol&gt;A fail-over scenario might look something like this&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The customer clicks on the ‘Add to basket’ for a widget&lt;/li&gt;&lt;li&gt;The request is serviced by server A and returns a page representing the basket containing the selected widget.&lt;/li&gt;&lt;li&gt;The customer clicks the ‘Proceed to checkout’ button&lt;/li&gt;&lt;li&gt;Server A has a network fault so the request is serviced by server B and returns a page requesting payment details for the basket containing the widget.&lt;/li&gt;&lt;/ol&gt;In production this might be caused by a rodent chewing through a cable at at critical moment or some other hardware fault. But how do we test this easily.&lt;br /&gt;&lt;br /&gt;Virtual machines typically use a virtual network connection routed through a physical connection or completely virtualized on a single host server. With VMWare Server and Microsoft Virtual server this network connection can be controlled by the host or by an application controlling the host. The last option is the most interesting because it allows the connection to be controlled programatically in the test code.&lt;br /&gt;&lt;br /&gt;A test might then look like (pseudo code)&lt;br /&gt;&lt;pre&gt;result = http.request(“www.test.domain.com/AddToBasket?product=widget”)&lt;br /&gt;AssertWidgetInResult(result)&lt;br /&gt;VirtualHost.ServerA.Network = disabled&lt;br /&gt;result = http.request (“www.test.domain.com/Checkout?orderid=” + result.orderid)&lt;br /&gt;AssertPaymentOptionsDisplayed(result)&lt;br /&gt;&lt;/pre&gt;The ability to automate these tests should not be underestimated. More complex scenarios can be developed and executed easily. The test code can be run frequently perhaps as part of a continuous integration system. Execution time for the tests is now much faster - no manual interventions. Removing the manual steps makes the tests repeatable and less prone to execution error.&lt;br /&gt;&lt;br /&gt;Developers, Quality Analysts and Architects gain a much greater understanding of how resilient their application is to failure which leads to a greater confidence that the application will behave as expected in a production environment.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-2878504540503799827?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/2878504540503799827/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=2878504540503799827' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2878504540503799827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/2878504540503799827'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/01/testing-application-fail-over-using.html' title='Testing Application fail-over using Virtual Hardware'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3215278939917454572.post-7954217945346326696</id><published>2007-01-20T09:55:00.000Z</published><updated>2007-01-20T10:16:48.281Z</updated><title type='text'>So what is this blog all about?</title><content type='html'>To be honest I am not too sure. I have a number of other blogs for family and one syndicated through work so why you ask should I have another one. Well this one is for me to talk to myself and anyone else out there interested in hearing what I have to say about writing software.&lt;br /&gt;&lt;br /&gt;I love working in this industry! I see it as a privilage that I can be paid for doing someting that I love to do. Hopefully there will be some gems of wisdom here that other people will find interesting, hate or perhaps even amusing.&lt;br /&gt;&lt;br /&gt;Only time will tell.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3215278939917454572-7954217945346326696?l=grahambrooks.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://grahambrooks.blogspot.com/feeds/7954217945346326696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3215278939917454572&amp;postID=7954217945346326696' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7954217945346326696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3215278939917454572/posts/default/7954217945346326696'/><link rel='alternate' type='text/html' href='http://grahambrooks.blogspot.com/2007/01/so-what-is-this-blog-all-about.html' title='So what is this blog all about?'/><author><name>Graham Brooks</name><uri>http://www.blogger.com/profile/04938624738598367225</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_BP9ytUtoakk/SOiX_Ap_LOI/AAAAAAAAAEs/HIg7OVuVoOI/S220/GrahamBrooks.jpg'/></author><thr:total>0</thr:total></entry></feed>
