<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.harukizaemon.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">

    <title>My hovercraft is full of eels</title>
    
    <link href="http://www.harukizaemon.com/" />
    <updated>2010-08-05T21:11:27-07:00</updated>
    <id>http://www.harukizaemon.com/</id>
    <author>
        <name>Simon Harris</name>
        <email>haruki.zaemon@gmail.com</email>
    </author>

    
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.harukizaemon.com/MyHovercraftIsFullOfEels" /><feedburner:info uri="myhovercraftisfullofeels" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-sa/3.0/" /><entry>
        <title>How I tell a story</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/XX0ZIsp59GU/how-i-tell-a-story.html" />
        <updated>2010-08-05T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2010/08/how-i-tell-a-story</id>
        <content type="html">&lt;p&gt;As far as I can tell, the most widely accepted format for agile user stories looks like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;As a [role]
I would like to [action]
So that [reason for action]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;#8217;m not entirely certain of the origins. Some have suggested &lt;a href='http://blog.dannorth.net/whats-in-a-story/'&gt;Dan North&lt;/a&gt; and others have have suggested much earlier use. In any event, it&amp;#8217;s use is so common I can&amp;#8217;t recall a single &amp;#8220;agile&amp;#8221; project where that wasn&amp;#8217;t the format but I&amp;#8217;ve also never really been that comfortable with it and I&amp;#8217;ve not really known why until recently.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s an example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;As a domain novice
I want the domain experts names made prominent on a domain listing
So that I know who to turn to for help on a given domain
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Though entirely contrived for the purpose of this discussion, it demonstrates the kind of stories people are inclined to write.&lt;/p&gt;

&lt;p&gt;On the positive side, the format seems quite natural &amp;#8211; people often have an implementation in mind and they can articulate it quite easily but find it much harder to articulate the intent. This seems to be reflected in the format with the primary focus (&amp;#8220;I want&amp;#8221;) expressed as the desired behaviour and the intent (&amp;#8220;So that&amp;#8221;) of conceptually lesser importance. The problem I have is the story centres around how the user will interact with the system and only then describes why. It presupposes an implementation with a cursory nod as to the user&amp;#8217;s intent.&lt;/p&gt;

&lt;p&gt;In my various roles from analyst to developer, I&amp;#8217;ve always wanted to understand why we&amp;#8217;re building a new feature. Experience has taught me that when I understand the why, I am better able to build a solution that satisfies the real need. As a consequence, when running workshops, I&amp;#8217;ve always tried to have the intent stated as the primary desire/need. For example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;As a domain novice
I want to know who to turn to for help on a given domain
So that .... [what the hell goes here?]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When people go to the trouble of putting the intent first, the &amp;#8220;So that&amp;#8221; becomes a bit of a WTF, often resulting in a simple re-statement of the intent just to satisfy the template:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;As a domain novice
I want to know who to turn to for help on a given domain
So that I can learn more about the domain [well d&amp;#39;uh!]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Moreover, we&amp;#8217;ve now lost the implementation detail which, although we&amp;#8217;re more interested in the intent, is still of value by providing context for further discussion/understanding.&lt;/p&gt;

&lt;p&gt;What I&amp;#8217;ve wanted was a way to encourage people to describe their intent and leave the implementation details to be decided closer to the iteration in which the story will be delivered. Yes, training is one way to achieve this but my experience is that the standard format effectively devalues the intent in favour of implementation detail. What I&amp;#8217;d really like is to somehow &lt;a href='http://www.amazon.com/Nudge-Improving-Decisions-Health-Happiness/dp/0300122233'&gt;nudge&lt;/a&gt; people into writing a story where the primary focus is the intent.&lt;/p&gt;

&lt;p&gt;Enter the format I&amp;#8217;ve been using recently and really liking:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;As a [role]
I want to [intent]
[For example] By [action]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It&amp;#8217;s a small but subtle change. To some so subtle that it verges on the trivial. However, my experience is that it&amp;#8217;s similar enough to the original format so as not to seem too radical a change and at the same time different enough to encourage the behaviour I am looking for. By way of example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;As a domain novice
I want to know who to turn to for help on a given domain
e.g by having the domain experts names made prominent on a domain listing
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The intent is now first and clearly specified as a higher order issue. It makes no sense to express the intent as &amp;#8220;For example by wanting to know who to turn to for help on a given domain&amp;#8221; so the only sensible place for it is as &amp;#8220;I want &amp;#8230;&amp;#8221;.&lt;/p&gt;

&lt;p&gt;That the last line begins with &amp;#8220;By&amp;#8221; identifies it as an implementation detail, acknowledging that most people have some idea of how they want it implemented and allowing them to express that without feeling awkward. With the addition of &amp;#8220;For example&amp;#8221; or &amp;#8220;e.g.&amp;#8221;&amp;#8211; as suggested by &lt;a href='http://dogbiscuit.org/mdub/weblog/'&gt;Mike Williams&lt;/a&gt; &amp;#8211; we further clarify that it as up for debate once the story hits an iteration. Finally, by placing it last and making it optional we indicate that it lends less weight than the intent.&lt;/p&gt;

&lt;p&gt;The more I use this format the more it becomes clear when the intent is expressed as implementation, my stories tend to read much more like a plot or a narrative of the software, and I&amp;#8217;m finding it nudges/leads me to write stories that express the intent rather than work backwards from the implementation. I&amp;#8217;ve also noticed I&amp;#8217;m developing some heuristics for &amp;#8220;validation&amp;#8221;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the implementation contains a conjunction (and) it probably indicates the story is an epic.&lt;/li&gt;

&lt;li&gt;When the intent contains a conjunction, it probably indicates more than one story/epic.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/XX0ZIsp59GU" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2010/08/how-i-tell-a-story.html</feedburner:origLink></entry>
    
    <entry>
        <title>Trading Design Pain for Runtime Pain</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/CpuuVm_g67A/trading-design-pain-for-runtime-pain.html" />
        <updated>2010-06-03T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2010/06/trading-design-pain-for-runtime-pain</id>
        <content type="html">&lt;p&gt;So&lt;sup id='fnref:1'&gt;&lt;a href='#fn:1' rel='footnote'&gt;1&lt;/a&gt;&lt;/sup&gt;, since my post on &lt;a href='http://www.harukizaemon.com/2010/03/functional-programming-in-object-oriented-languages.html'&gt;functional programming in object-oriented languages&lt;/a&gt; I&amp;#8217;ve continued to tread the path with a mixture of gratification and despair. This morning the latter became overwhelming, I&amp;#8217;d just had enough. My brain hurt and I just wanted to pump out some code, run it. I threw out the concepts I had been using as my guide and fell back on years of &amp;#8220;old-school&amp;#8221; object-oriented code.&lt;/p&gt;

&lt;p&gt;Unfortunately, I was no more productive. In fact, I&amp;#8217;d argue I was less productive. Things began to fail in weird and unexpected ways. The number of tests I needed to write to catch errors at least doubled. I soon returned to the comfort of my hybrid world.&lt;/p&gt;

&lt;p&gt;In hindsight, I had traded design pain for runtime pain. All the mental gymnastics that went into working out how to build classes that are inter-related and at the same time immutable, etc. was replaced with time spent writing tests for anticipated edge cases as well as debugging the unexpected ones.&lt;/p&gt;

&lt;p&gt;I concluded that the &amp;#8220;pain&amp;#8221; I had been experiencing was largely the result of being forced to deal with the complexity of the underlying problem. Once solved however, the code fell out with few or no bugs. By contrast, when I reverted to my previous approach, the code flowed far more freely but I spent a lot more time working out how to ensure the code didn&amp;#8217;t do nasty things to itself.&lt;/p&gt;

&lt;p&gt;What&amp;#8217;s perhaps as interesting to me is that my designs are resulting in smaller and smaller classes. The more I think about problems in a functional way, the more I&amp;#8217;m am able to design solutions that are essentially pipelines. The irony being that even though we think of imperative code as being step-by-step, it more often than not turns out to be a big, intertwined blob. Functional code on the other hand is almost by definition a series of steps, or transformations applied one after the other on some input.&lt;/p&gt;

&lt;p&gt;These two observations are drawing me ever closer to just &amp;#8220;getting over it&amp;#8221; and using a functional language. The issue for me is the only FP language I know and actually like is Haskell and the only FP language I&amp;#8217;d be likely to get into production is Clojure. Which is all I&amp;#8217;ll say in public as I have no desire to start a flame war :)&lt;/p&gt;
&lt;div class='footnotes'&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li id='fn:1'&gt;
&lt;p&gt;&lt;a href='http://www.nytimes.com/2010/05/22/us/22iht-currents.html'&gt;A Connective Word Takes the Lead&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:1' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/CpuuVm_g67A" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2010/06/trading-design-pain-for-runtime-pain.html</feedburner:origLink></entry>
    
    <entry>
        <title>Functional programming in object oriented languages</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/HUgmILnVatg/functional-programming-in-object-oriented-languages.html" />
        <updated>2010-03-01T00:00:00-08:00</updated>
        <id>http://www.harukizaemon.com/2010/03/functional-programming-in-object-oriented-languages</id>
        <content type="html">&lt;p&gt;In my current job, I spend about 40% of my time with my underpants on the outside, digging around in production code, generally making stuff better. The other 60% of the time is R&amp;amp;D. The R&amp;amp;D part has some very concrete objectives but there is certainly leeway to explore different ways of developing software.&lt;/p&gt;

&lt;p&gt;Like many programmers, my first formal introduction to OO was all about classes and inheritance. What mattered most was getting the &amp;#8220;structure&amp;#8221; right. Next, I came to understand the importance of encapsulation, and after that polymorphism.&lt;/p&gt;

&lt;p&gt;Over the past 6-12 months or so I&amp;#8217;ve become more and more interested in functional programming concepts if not functional programming languages. I&amp;#8217;ve always been a big fan of declarative programming, business rules, etc. and yet I&amp;#8217;ve also always been a big fan of OO. Even when I was an assembler programmer I tended to structure my code and data as if it were object-oriented, even if the &lt;code&gt;self&lt;/code&gt; pointer was explicit.&lt;/p&gt;

&lt;p&gt;Mor recently I re-read &lt;a href='http://mitpress.mit.edu/sicp/'&gt;SICP&lt;/a&gt;, learned &lt;a href='http://www.haskell.org/'&gt;Haskell&lt;/a&gt; which I unashamedly love, played with &lt;a href='http://clojure.org/'&gt;Clojure&lt;/a&gt; on and off, and briefly looked at &lt;a href='http://www.scala-lang.org/'&gt;Scala&lt;/a&gt;. Co-incidentally, I also read &lt;a href='http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215'&gt;Domain Driven Design&lt;/a&gt;, and &lt;a href='http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882'&gt;Clean Code&lt;/a&gt; along with a number of other very interesting articles on functional programming, immutability in general and recursion in object-oriented languages.&lt;sup id='fnref:1'&gt;&lt;a href='#fn:1' rel='footnote'&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;sup id='fnref:2'&gt;&lt;a href='#fn:2' rel='footnote'&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;sup id='fnref:3'&gt;&lt;a href='#fn:3' rel='footnote'&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;sup id='fnref:4'&gt;&lt;a href='#fn:4' rel='footnote'&gt;4&lt;/a&gt;&lt;/sup&gt; All of which got me thinking, once again, that perhaps I&amp;#8217;d been doing this OO thing all wrong.&lt;/p&gt;

&lt;p&gt;Here I&amp;#8217;d like to present a few observations from my exploration into functional programming in an object-oriented world.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Immutable objects good; Mutable objects bad&lt;/li&gt;

&lt;li&gt;An object is a collection of partially applied functions&lt;/li&gt;

&lt;li&gt;An object&amp;#8217;s API provides a clear separation between Commands and Queries&lt;/li&gt;

&lt;li&gt;An object is a snapshot of state and possible outcomes&lt;/li&gt;

&lt;li&gt;An object is a persistent data structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clear as mud hey?&lt;/p&gt;

&lt;h2 id='immutable_objects_good_mutable_objects_bad'&gt;Immutable objects good; Mutable objects bad&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;Classes should be immutable unless there&amp;#8217;s a very good reason to make them mutable&amp;#8230;.If a class cannot be made immutable, limit its mutability as much as possible.&amp;#8221; &amp;#8211; Joshua Bloch, Effective Java&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I won&amp;#8217;t go into a lot of detail as to why I believe this to be true. There are plenty of arguments to be found both for and against. Suffice it to say, the direction I&amp;#8217;m taking and the conclusions I draw from my experiences are predicated on this belief. What I will say however, is that the effect it has on my designs quite often gives me the same sense of satisfaction as when practising Test Driven Design.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s not as though immutability in object-oriented programming is anything new. Many years ago I wrote code where all my value objects were immutable as was the occasional service class, etc. The difference in my current approach is that everything is immutable except for a tiny layer at the fringes where I need to save data for later retrieval, consume HTTP requests, etc. Yes, even my &amp;#8220;entities&amp;#8221; are immutable.&lt;/p&gt;

&lt;h2 id='an_object_is_a_collection_of_partially_applied_functions'&gt;An object is a collection of partially applied functions&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;The ideal number of arguments for a function is zero &amp;#8230; More than three requires very special justification &amp;#8211; and then shouldn’t be used anyway.&amp;#8221; &amp;#8211; Bob Martin, Clean Code&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In functional languages, partial application of a function allows us to define a new function by &amp;#8220;pre-populating&amp;#8221; some of the arguments. For example, we can take a very simple Haskell function that calculates the amount of applicable sales tax:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;applicableSalesTax&lt;/span&gt; &lt;span class='n'&gt;percentage&lt;/span&gt; &lt;span class='n'&gt;amount&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;percentage&lt;/span&gt; &lt;span class='o'&gt;/&lt;/span&gt; &lt;span class='mi'&gt;100&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='n'&gt;amount&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;and then partially apply it to create another function that has a fixed sales tax:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;applicableGST&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;applicableSalesTax&lt;/span&gt; &lt;span class='mi'&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The function &lt;code&gt;applicableGST&lt;/code&gt; partially applies &lt;code&gt;applicableSalesTax&lt;/code&gt; with the value 10. Anytime we call &lt;code&gt;applicableGST&lt;/code&gt; it will invoke &lt;code&gt;applicableSalesTax&lt;/code&gt; with a rate of 10% and whatever amount we pass to it.&lt;/p&gt;

&lt;p&gt;Now consider an object-oriented approach (in Ruby). Imagine a very simple &lt;code&gt;SalesTax&lt;/code&gt; class that holds the rate:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;SalesTax&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;percentage&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@rate&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;percentage&lt;/span&gt; &lt;span class='o'&gt;/&lt;/span&gt; &lt;span class='mi'&gt;100&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;applicable_for&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;amount&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;amount&lt;/span&gt; &lt;span class='o'&gt;*&lt;/span&gt; &lt;span class='vi'&gt;@rate&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;included_in&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;amount&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;amount&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt; &lt;span class='n'&gt;excluded_from&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;amount&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;excluded_from&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;amount&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;amount&lt;/span&gt; &lt;span class='o'&gt;/&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='vi'&gt;@rate&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Here, the constructor sets up the context within which each of the methods then operates, just the way we always read good OO code should be.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve starting to think of constructor arguments as the mechanism for partially applying all the methods on an object. Considering an object as a partial application of a set of methods is really quite interesting to me. It almost dictates that methods MUST operate, in some way, on the state of the object &amp;#8211; just as we always read good OO code should &amp;#8211; only there&amp;#8217;s a nice explanation as to why: If they didn&amp;#8217;t operate on the object&amp;#8217;s state, they wouldn&amp;#8217;t be partially applied.&lt;/p&gt;

&lt;p&gt;When I apply this principle in my designs I find I have smaller, more cohesive classes &amp;#8211; ie the methods are all related more closely to the shared state. I also find I have far fewer private methods and more often than not, none at all. (This coincidentally fits in nicely with my relatively long held belief that &lt;a href='http://www.harukizaemon.com/2004/02/dont-touch-my-privates.html'&gt;private methods are a smell&lt;/a&gt; though this is a perhaps a topic for another discussion.) I also find that the constructor then becomes a meaningful, nay critical, part of my API.&lt;/p&gt;

&lt;h2 id='an_objects_api_provides_a_clear_separation_between_commands_and_queries'&gt;An object&amp;#8217;s API provides a clear separation between Commands and Queries&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;Methods should return a value only if they are referentially transparent and hence possess no side effects.&amp;#8221; &amp;#8211; Bertrand Meyer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Interestingly, when we deal with immutable objects we really have little choice but to do just this.&lt;/p&gt;

&lt;p&gt;If we want an object to &amp;#8220;answer something&amp;#8221; (a query) no modification is expected and we simply return a (potentially calculated) value:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;full_name&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@first_name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;, &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='vi'&gt;@last_name&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If we want an object to &amp;#8220;do something&amp;#8221; (a command) we&amp;#8217;ll be expecting some kind of representation of the new state as the result:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;set_first&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;new_last_name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='no'&gt;Person&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@first_name&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;new_last_name&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If we assume we only want to return one thing from a method, and that a change in state necessitates returning a handle to the new state, then a method can only ever be either a query or command but not both.&lt;/p&gt;

&lt;p&gt;After discussing this with a colleague, they suggested that in a sense commands are now queries, eg. that ask the question: &amp;#8220;what would a system look like if I asked you to do something?&amp;#8221; Given &lt;a href='http://martinfowler.com/bliki/CommandQuerySeparation.html'&gt;this definition of Commands and Queries&lt;/a&gt; I can certainly see it from that perspective.&lt;/p&gt;

&lt;p&gt;In the example just given we merely returned a newly created object but it could just as easily have inserted a record into a database. So, I still like to think of commands in the original sense except they now return a handle to the new state. Much like an HTTP PUT/POST/DELETE request does when following the principles of &lt;a href='http://en.wikipedia.org/wiki/Representational_State_Transfer'&gt;REST&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;(As an aside, one consequence of this approach is that objects are &lt;a href='http://en.wikipedia.org/wiki/Closure_%28mathematics%29'&gt;closed under modification&lt;/a&gt;. That is, whenever we modify an object, we receive the result in the form of a new object of the same type.)&lt;/p&gt;

&lt;h2 id='an_object_is_a_snapshot_of_state_and_possible_outcomes'&gt;An object is a snapshot of state and possible outcomes&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;Domain Events represent the state of entities at a given time when an important event occurred and decouple subsystems with event streams. Domain Events give us clearer, more expressive models in those cases.&amp;#8221; &amp;#8211; Eric Evans&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I presume it would be largely uncontroversial to describe immutable objects as a snapshot of some state. When I also consider an object as a collection of partially applied functions, I begin to think of an object &amp;#8211; and therefore the system as a whole &amp;#8211; as a snapshot not only of state but also possible outcomes.&lt;/p&gt;

&lt;p&gt;I suspect thinking about the difference between a system that undergoes state changes in situ and one that in effect represents every possible outcome simultaneously without needing to materialise them all in advance leads to a very different way of modelling a problem.&lt;/p&gt;

&lt;p&gt;While pondering this, I recalled that as a kid I loved &lt;a href='http://en.wikipedia.org/wiki/Choose_Your_Own_Adventure'&gt;Choose Your Own Adventure books&lt;/a&gt;? At the end of each page (or few pages) you are presented with a set of choices: Do you turn left? Do we Open the door? Do you run away? Depending on the choice we make, the story takes a different course. Objects seem a bit like pages in a Choose Your Own Adventure Book, frozen in time. The methods are like the choices we make &amp;#8211; each one takes us to a different page, itself frozen in time. I used to bookmark pages with my thumb, like a save-point. If I didn&amp;#8217;t like the way the story was headed I simply turned back to the last known &amp;#8220;good&amp;#8221; point in the book.&lt;/p&gt;

&lt;h2 id='an_object_is_a_persistent_data_structure'&gt;An object is a persistent data structure&lt;/h2&gt;

&lt;p&gt;A &lt;a href='http://en.wikipedia.org/wiki/Persistent_data_structure'&gt;persistent data structure&lt;/a&gt; is one that efficiently preserves the previous version of itself when it is modified. One of the simplest persistent data structures is the singly-linked (cons) list but almost any tree structure can be adapted to be persistent.&lt;/p&gt;

&lt;p&gt;If we&amp;#8217;re creating snapshots in order to preserve the initial state we&amp;#8217;ll need to make a copy that can be modified. It&amp;#8217;s reasonable to assume that all these redundant copies will take precious memory and computing cycles and in doing so create quite a bit of garbage. Assuming a naive copying strategy that makes deep, nested copies, this will certainly be the case. Thankfully, there are some pretty neat optimisations we can make by because every object is immutable.&lt;/p&gt;

&lt;p&gt;When thought of as a tree with the references to other objects as the children, an object can be treated just like a persistent data structure. If we need to make a copy and modify something, all we need do is create a shallow copy and change the necessary fields. In this way, each copy is like a delta from the previous, sharing as much state as possible and reducing not only the time to copy but also the amount of memory needed.&lt;/p&gt;

&lt;p&gt;When I first started down this path, I used constructors for this purpose. For example, if I wanted to create a new &lt;code&gt;Money&lt;/code&gt; object, I&amp;#8217;d create a new version using regular object construction:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Money&lt;/span&gt;

  &lt;span class='kp'&gt;attr_reader&lt;/span&gt; &lt;span class='ss'&gt;:currency&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;amount&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;currency&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;amount&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='vi'&gt;@currency&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;currency&lt;/span&gt;
    &lt;span class='vi'&gt;@amount&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;amount&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;other&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='no'&gt;Money&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@currency&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='vi'&gt;@amount&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='vi'&gt;@currency&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;convert&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;other&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;currency&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;other&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;money&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I found this approach worked fine for small, value-object sized, classes however for objects that reference more than two or three values, constructing new instances became cumbersome. Moreover, if an object had internal state that was hidden but necessary when copying, the constructor API would become polluted. Even in languages such as Java that provide method overloading, or Ruby with first-class associative arrays, it still felt overly complicated to construct a new instance just to change a single value.&lt;/p&gt;

&lt;p&gt;Instead I&amp;#8217;ve started using an approach that involves cloning. Whenever I need to make a change, I perform a shallow copy, update the appropriate fields and return the result. In a language such as Ruby, this is quite simple to implement and make safe. Instead of using object construction, anytime I wish to make a change I do something like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;other&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='n'&gt;transform&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='vi'&gt;@amount&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@amount&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;currency&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;convert&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;other&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;currency&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;other&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;money&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;add&lt;/code&gt; method now looks similar to a method you&amp;#8217;d write if you were able to modify state; we assign a new amount based on some calculation. The &lt;code&gt;transform&lt;/code&gt; method&lt;sup id='fnref:5'&gt;&lt;a href='#fn:5' rel='footnote'&gt;5&lt;/a&gt;&lt;/sup&gt; is the key here by making a shallow copy of the object, running the block within the context of the copy, then freezing the result to prevent modification before returning it to the caller. I&amp;#8217;m finding this approach to have a number of advantages.&lt;/p&gt;

&lt;p&gt;My constructor API isn&amp;#8217;t &amp;#8220;polluted&amp;#8221; with internal implementation concerns. The constructor remains a part of the public API.&lt;/p&gt;

&lt;p&gt;The construction of the modified copy isn&amp;#8217;t leaking into the implementation of the method itself. Instead, the method can focus on the job at hand.&lt;/p&gt;

&lt;p&gt;Because the method only ever needs to concern itself with the data upon which it operates, the rest of the class can vary relatively independently. When we were explicitly constructing a new object, the &lt;code&gt;add&lt;/code&gt; method had to concern itself with also copying the currency. When using &lt;code&gt;transform&lt;/code&gt; that problem goes away. No matter how many other fields need to be copied, the &lt;code&gt;add&lt;/code&gt; method remains unchanged.&lt;/p&gt;

&lt;p&gt;In a sense each method describes the delta between the current state and the new state. Just like a persistent data structure. It reminds me of branching in a Version Control System.&lt;/p&gt;

&lt;h2 id='more_to_explore'&gt;More to explore&lt;/h2&gt;

&lt;p&gt;As I mentioned very early on, I&amp;#8217;m working with designs that are almost completely immutable, even at the entity level. This approach results in some really positive benefits but also presents some interesting implementation challenges as well as challenging some of my long held beliefs.&lt;/p&gt;

&lt;p&gt;Immutable designs &lt;em&gt;feel&lt;/em&gt; easier to reason about. I have no empirical evidence for this just a gut feel. When I&amp;#8217;m trying to work out why something isn&amp;#8217;t working as expected, more often than not I can just read through the code and work out what happened. I&amp;#8217;m not trying to keep a mental mode of all the side effects.&lt;/p&gt;

&lt;p&gt;When dealing with any kind of RDBMS, immutable objects lend themselves to a model where changes to the database are written as events rather than updates to individual records. Unlike a traditional ORM, I don&amp;#8217;t have the &amp;#8220;luxury&amp;#8221; of modifying an object to assign an ID. This hasn&amp;#8217;t presented much of a problem as yet though I suspect it might become more interesting as the object model increases in complexity.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve been contemplating trying out an OODB such as &lt;a href='http://github.com/MagLev/maglev'&gt;MagLev&lt;/a&gt; to see how that might fit in. I suspect it should be no more difficult than with mutable objects and perhaps even simpler.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m also working on a project at the moment that uses an immutable RDF store wrapped in an object model to make it actually useable. So far it&amp;#8217;s fit really nicely.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m weary of my code turning into a collection of function objects. Ie. objects that effectively have a single &lt;code&gt;doIt&lt;/code&gt; method. It doesn&amp;#8217;t happen too often to be a concern but it certainly does happen and I&amp;#8217;m still not certain how I feel about it.&lt;/p&gt;

&lt;p&gt;I sometimes find myself exposing state I wouldn&amp;#8217;t otherwise have needed when I used mutable objects. It feels a tad icky but thus far I haven&amp;#8217;t found it to be much of an issue.&lt;/p&gt;

&lt;p&gt;Testing has also been interesting. I find I&amp;#8217;m doing far less mocking and much more state-based testing. I find the tests I&amp;#8217;m writing to be far more declarative than when I do interaction based testing. Define the initial state of the system, run the code, and compare against the expected state. Even (especially?) at the unit level this has been very effective. Again, I&amp;#8217;m not sure how I feel about this but so far, it&amp;#8217;s worked out well.&lt;/p&gt;

&lt;p&gt;Of course not everything is immutable. The database isn&amp;#8217;t nor is the file system though in both cases I try my best to treat them as if they were by only ever writing new records/files. The system runtime isn&amp;#8217;t immutable either &amp;#8211; the act of creating a new object proves that.&lt;/p&gt;

&lt;p&gt;Perhaps it really is a natural progression from here to the use of more functional languages as some of my colleagues tell me I should. However there does seem to be a general lack of distinction between the benefits of functional programming concepts and functional programming languages. I&amp;#8217;m thoroughly enjoying incorporating functional programming concepts into object-oriented languages.&lt;/p&gt;
&lt;div class='footnotes'&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li id='fn:1'&gt;
&lt;p&gt;&lt;a href='http://www.cs.chalmers.se/~rjmh/Papers/whyfp.pdf'&gt;Why Functional Programming Matters&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:1' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;li id='fn:2'&gt;
&lt;p&gt;&lt;a href='http://weblog.raganwald.com/2007/03/why-why-functional-programming-matters.html'&gt;Why Why Functional Programming Matters Matters&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:2' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;li id='fn:3'&gt;
&lt;p&gt;&lt;a href='http://www.ccs.neu.edu/home/matthias/Presentations/ecoop2004.pdf'&gt;Functional Objects&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:3' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;li id='fn:4'&gt;
&lt;p&gt;&lt;a href='http://lambda-the-ultimate.org/node/3702'&gt;Why Object Oriented Languages Need Tail Calls&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:4' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;li id='fn:5'&gt;
&lt;p&gt;&lt;a href='http://github.com/harukizaemon/hamster/'&gt;Hamster - Efficient, Immutable, Thread-Safe Collection classes for Ruby&lt;/a&gt;&lt;/p&gt;
&lt;a href='#fnref:5' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/HUgmILnVatg" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2010/03/functional-programming-in-object-oriented-languages.html</feedburner:origLink></entry>
    
    <entry>
        <title>Tests as documentation</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/1bcS09xumsw/tests-as-documentation.html" />
        <updated>2010-02-11T00:00:00-08:00</updated>
        <id>http://www.harukizaemon.com/2010/02/tests-as-documentation</id>
        <content type="html">&lt;p&gt;Whilst I&amp;#8217;ve been playing around with &lt;a href='http://github.com/harukizaemon/hamster'&gt;immutable collection classes in Ruby&lt;/a&gt;, I&amp;#8217;ve also been working on ways to document behaviour without writing loads of RDOC that goes stale really quickly.&lt;/p&gt;

&lt;p&gt;Tests have always been touted as a form of documentation but I&amp;#8217;ve rarely &amp;#8211; if ever come to think of it &amp;#8211; seen that work in practice. &lt;a href='http://cukes.info/'&gt;Cucumber&lt;/a&gt; comes very close but I wanted something a little closer to the metal, something that allowed me to write unit tests with something like &lt;a href='http://rspec.info/'&gt;RSpec&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For sometime now, I&amp;#8217;d been structuring my specs with this in mind and I thought I was doing a reasonably good approximation. Then today I finally had cause to test my work. As part of a feature I was implementing in another project, I wanted to use a list method I thought provided just what I required but I couldn&amp;#8217;t remember exactly how it behaved or what the interface was so, naturally, I consulted the documentation. D&amp;#8217;oh! But wait, I thought smugly, I&amp;#8217;ve been writing these specs and as we all know, specs are documentation. Moreover, I&amp;#8217;ve been putting in quite a bit of effort to make them read as such so why not go read the specs?&lt;/p&gt;

&lt;p&gt;Suffice to say, they didn&amp;#8217;t live up to my expectations. After running &lt;code&gt;spec -f nested spec/hamster/list/span_spec.rb&lt;/code&gt; the result wasn&amp;#8217;t bad but wasn&amp;#8217;t great either:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;Hamster::List
  #span
    is lazy
    on []
      with a block
        preserves the original
        returns a tuple with two items
        correctly identifies the prefix
        correctly identifies the remainder
      without a block
        returns a tuple with two items
        returns self as the prefix
        leaves the remainder empty
    on [1]
      with a block
        preserves the original
        returns a tuple with two items
        correctly identifies the prefix
        correctly identifies the remainder
      without a block
        returns a tuple with two items
        returns self as the prefix
        leaves the remainder empty
    on [1, 2, 3, 4]
      with a block
        preserves the original
        returns a tuple with two items
        correctly identifies the prefix
        correctly identifies the remainder
      without a block
        returns a tuple with two items
        returns self as the prefix
        leaves the remainder empty
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;For a start, there was no narrative, nothing telling me what the desired outcome was; why do I want to use this method? Secondly, whilst the individual assertions seemed to make sense when reading the spec code, once they were in this purely textual form they were somewhat useless in helping me understand what to expect. And lastly, a purely aesthetic complaint, I didn&amp;#8217;t really like the indentation so much. Right when all that hard work should have paid off, it failed me. But not completely. I was still convinced there was some merit in what I wanted and perhaps a little more tweaking could get me closer to my ideal.&lt;/p&gt;

&lt;p&gt;After a few iterations of modifying the code, running the specs, and reading the output, I finally hit upon something I think is pretty close to what I&amp;#8217;ve been after:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='text'&gt;Hamster.list#span
  is lazy
  given a predicate (in the form of a block), splits the list into two lists
  (returned as a tuple) such that elements in the first list (the prefix) are
  taken from the head of the list while the predicate is satisfied, and elements
  in the second list (the remainder) are the remaining elements from the list
  once the predicate is not satisfied. For example:
    given the list []
      and a predicate that returns true for values &amp;lt;= 2
        preserves the original
        returns the prefix as []
        returns the remainder as []
      without a predicate
        returns a tuple
        returns self as the prefix
        returns an empty list as the remainder
    given the list [1]
      and a predicate that returns true for values &amp;lt;= 2
        preserves the original
        returns the prefix as [1]
        returns the remainder as []
      without a predicate
        returns a tuple
        returns self as the prefix
        returns an empty list as the remainder
    given the list [1, 2, 3, 4]
      and a predicate that returns true for values &amp;lt;= 2
        preserves the original
        returns the prefix as [1, 2]
        returns the remainder as [3, 4]
      without a predicate
        returns a tuple
        returns self as the prefix
        returns an empty list as the remainder
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This time there&amp;#8217;s a narrative describing what the method does, followed by a series of examples not only describing the behaviour but also providing concrete values. Now the output reads more like documentation only rather than duplicated as RDOC that rapidly becomes disconnected from reality, it&amp;#8217;s generated from the tests and automatically stays up-to-date.&lt;/p&gt;

&lt;p&gt;The underlying spec is not perfect by any stretch &amp;#8211; there is certainly a modicum of duplication between the test code and the descriptive text &amp;#8211; but I think it strikes a reasonable balance between tests that are readable as code as well as plain text documentation. I&amp;#8217;d certainly love to know what, if anything, others have done.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;expand_path&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;../../../spec_helper&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='bp'&gt;__FILE__&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;hamster/list&amp;#39;&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Hamster.list#span&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;

  &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;is lazy&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='nb'&gt;lambda&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='no'&gt;Hamster&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stream&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;item&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='nb'&gt;fail&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;span&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='kp'&gt;true&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_not&lt;/span&gt; &lt;span class='n'&gt;raise_error&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class='no'&gt;DESC&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
&lt;span class='sh'&gt;given a predicate (in the form of a block), splits the list into two lists&lt;/span&gt;
&lt;span class='sh'&gt;  (returned as a tuple) such that elements in the first list (the prefix) are&lt;/span&gt;
&lt;span class='sh'&gt;  taken from the head of the list while the predicate is satisfied, and elements&lt;/span&gt;
&lt;span class='sh'&gt;  in the second list (the remainder) are the remaining elements from the list&lt;/span&gt;
&lt;span class='sh'&gt;  once the predicate is not satisfied. For example:&lt;/span&gt;
&lt;span class='no'&gt;DESC&lt;/span&gt;

    &lt;span class='o'&gt;[&lt;/span&gt;
      &lt;span class='o'&gt;[[]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[]]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='o'&gt;[[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[]]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='o'&gt;[[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[]]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='o'&gt;[[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='o'&gt;]]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='o'&gt;[[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='o'&gt;]]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='o'&gt;[[&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='o'&gt;]]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='o'&gt;[[&lt;/span&gt;&lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;3&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='o'&gt;]]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
      &lt;span class='o'&gt;[[&lt;/span&gt;&lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;4&lt;/span&gt;&lt;span class='o'&gt;]]&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;each&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;values&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;expected_prefix&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;expected_remainder&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;

      &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;given the list &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;values&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;inspect&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;

        &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='vi'&gt;@original&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Hamster&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;values&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;and a predicate that returns true for values &amp;lt;= 2&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;

          &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='vi'&gt;@result&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@original&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;span&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;item&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;item&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;=&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
            &lt;span class='vi'&gt;@prefix&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@result&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;
            &lt;span class='vi'&gt;@remainder&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@result&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;last&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

          &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;preserves the original&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='vi'&gt;@original&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='no'&gt;Hamster&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;values&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

          &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;returns the prefix as &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;expected_prefix&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;inspect&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='vi'&gt;@prefix&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='no'&gt;Hamster&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;expected_prefix&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

          &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;returns the remainder as &lt;/span&gt;&lt;span class='si'&gt;#{&lt;/span&gt;&lt;span class='n'&gt;expected_remainder&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;inspect&lt;/span&gt;&lt;span class='si'&gt;}&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='vi'&gt;@remainder&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='no'&gt;Hamster&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;expected_remainder&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;without a predicate&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;

          &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='vi'&gt;@result&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@original&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;span&lt;/span&gt;
            &lt;span class='vi'&gt;@prefix&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@result&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;
            &lt;span class='vi'&gt;@remainder&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@result&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;last&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

          &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;returns a tuple&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='vi'&gt;@result&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;is_a?&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;Hamster&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Tuple&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='kp'&gt;true&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

          &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;returns self as the prefix&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='vi'&gt;@prefix&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;equal&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@original&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

          &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;returns an empty list as the remainder&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='vi'&gt;@remainder&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;be_empty&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='k'&gt;end&lt;/span&gt;

      &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/1bcS09xumsw" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2010/02/tests-as-documentation.html</feedburner:origLink></entry>
    
    <entry>
        <title>Lazy spec task creation</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/LjMZ6-UMA-I/lazy-spec-task-creation.html" />
        <updated>2010-01-21T00:00:00-08:00</updated>
        <id>http://www.harukizaemon.com/2010/01/lazy-spec-task-creation</id>
        <content type="html">&lt;p&gt;I converted a Ruby project over to use &lt;a href='http://github.com/wycats/bundler'&gt;Bundler&lt;/a&gt; for gem dependency management today. For the most part it worked flawlessly except, that is, when the CI build ran for the first time after the conversion:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;LoadError: no such file to load -- vendor/gems/environment&lt;/span&gt;

&lt;span class='go'&gt;Stacktrace:&lt;/span&gt;
&lt;span class='go'&gt;tasks/spec.rb:8:in `require&amp;#39;&lt;/span&gt;
&lt;span class='go'&gt;tasks/spec.rb:8:in `&amp;lt;top (required)&amp;gt;&amp;#39;&lt;/span&gt;
&lt;span class='go'&gt;...&lt;/span&gt;
&lt;span class='go'&gt;Rake aborted!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The short story: The spec task definition needed the RSpec gem to be loaded but it wasn&amp;#8217;t until &lt;em&gt;after&lt;/em&gt; all tasks had been defined.&lt;/p&gt;

&lt;p&gt;Now, I could single out the spec task definition and ensure it was loaded last but that would mean adding a bunch of code to my otherwise trivial &lt;code&gt;Rakefile&lt;/code&gt;. The other option was to somehow defer the creation of the spec task until actually needed. After a bit of searching I couldn&amp;#8217;t find anything particularly useful so I rolled my own:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;namespace&lt;/span&gt; &lt;span class='ss'&gt;:spec&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;

  &lt;span class='n'&gt;desc&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Run specifications&amp;quot;&lt;/span&gt;
  &lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='ss'&gt;:run&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='ss'&gt;:define&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='no'&gt;Rake&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Task&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:_run&lt;/span&gt;&lt;span class='o'&gt;].&lt;/span&gt;&lt;span class='n'&gt;invoke&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;task&lt;/span&gt; &lt;span class='ss'&gt;:define&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;

    &lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;spec/rake/spectask&amp;#39;&lt;/span&gt;

    &lt;span class='no'&gt;Spec&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Rake&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;SpecTask&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:_run&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;t&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
      &lt;span class='n'&gt;t&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;spec_opts&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;--options&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;spec/spec.opts&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;exists?&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;spec/spec.opts&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;spec:run&lt;/code&gt; task depends on the &lt;code&gt;spec:define&lt;/code&gt; task to create a &amp;#8220;hidden&amp;#8221; &lt;code&gt;spec:_run&lt;/code&gt; task to actually do the work.&lt;/p&gt;

&lt;p&gt;The nice thing about this all the ickiness is hidden &amp;#8211; remove the &lt;code&gt;tasks/spec.rb&lt;/code&gt; file and nothing else really cares &amp;#8211; and means I can treat the spec task like any other when creating my task dependencies.&lt;/p&gt;

&lt;p&gt;As always, YMMV.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/LjMZ6-UMA-I" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2010/01/lazy-spec-task-creation.html</feedburner:origLink></entry>
    
    <entry>
        <title>Why Object-Oriented Languages Need Tail Calls</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/OAISsk5Yi-w/why-object-oriented-language-need-tail-calls.html" />
        <updated>2009-12-24T00:00:00-08:00</updated>
        <id>http://www.harukizaemon.com/2009/12/why-object-oriented-languages-need-tail-calls</id>
        <content type="html">&lt;p&gt;&lt;strong&gt;Update 2009/12/30&lt;/strong&gt;: MacRuby supports a limited form of TCO as well. I received similar results as for YARV (see below) the differences being you&amp;#8217;re not limited to the call being the &lt;em&gt;last&lt;/em&gt; statement in the method and there&amp;#8217;s a bug where you receive a segmentation fault rather than a stack overflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update 2009/12/27&lt;/strong&gt;: According to &lt;a href='http://redmine.ruby-lang.org/issues/show/1256'&gt;this redmine ticket&lt;/a&gt;, YARV has some limited TCO support which is disabled by default. I performed the necessary incantations to enable it, only to discover the true meaning of &amp;#8220;limited&amp;#8221;: optimise calls to the same method in the same instance &lt;em&gt;iff&lt;/em&gt; the call is the last statement in the method.&lt;/p&gt;

&lt;p&gt;Disclaimer: I unashamedly stole the title after reading &lt;a href='http://projectfortress.sun.com/Projects/Community/blog/ObjectOrientedTailRecursion'&gt;another article&lt;/a&gt; on the same topic.&lt;/p&gt;

&lt;p&gt;Some of you may know of a &lt;a href='http://github.com/harukizaemon/hamster'&gt;little project&lt;/a&gt; I&amp;#8217;ve been working on in my, albeit very limited, spare time. Hamster started out as an implementation of &lt;a href='http://lamp.epfl.ch/papers/idealhashtrees.pdf'&gt;Hash Array Mapped Trees&lt;/a&gt; (HAMT) for Ruby and has since expanded to include implementations of other &lt;a href='http://en.wikipedia.org/wiki/Persistent_data_structure'&gt;Persistent Data Structures&lt;/a&gt; such as Sets, Lists, Stacks, etc.&lt;/p&gt;

&lt;p&gt;For those that aren&amp;#8217;t up with HAMTs or persistent data structures in general, they have a really neat property: very efficient copy-on-write operations. This allows us to create immutable data-structures that only need copying when something changes, making them a very effective when writing multi-threaded code.&lt;/p&gt;

&lt;p&gt;Hamster also contains an implementation of &lt;a href='http://en.wikipedia.org/wiki/Cons'&gt;Cons Lists&lt;/a&gt; with all the usual methods you&amp;#8217;d expect from a Ruby collection such as &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;reject&lt;/code&gt;, etc. thrown in for good measure.&lt;/p&gt;

&lt;p&gt;One of the things I really wanted to investigate was laziness. So, for example, when evaluating:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;Hamster&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;interval&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1000000&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;filter&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='ss'&gt;:odd?&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;take&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;10&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Rather than generate a list with a million values, evaluate them all against the filter, and then select the first ten, Hamster lazily generates the list, the evaluation of &lt;code&gt;filter&lt;/code&gt;, and even &lt;code&gt;take&lt;/code&gt;. In fact, as it stands, the example code wont&amp;#8217; &lt;em&gt;actually&lt;/em&gt; do anything; you would need to call &lt;code&gt;head&lt;/code&gt; to kick-start anything happening at all. This behaviour extends, to the extent possible, to all other collection methods.&lt;/p&gt;

&lt;p&gt;Hamster also supports infinite lists. For example, the following code produces an infinite list of integers:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;integers&lt;/span&gt;
  &lt;span class='n'&gt;value&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;
  &lt;span class='no'&gt;Hamster&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stream&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;value&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now we can easily generate a list of odd numbers:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;integers&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;filter&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='ss'&gt;:odd?&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Again, rather than generate every possible integer and filter those into odd numbers, the list is generated as necessary.&lt;/p&gt;

&lt;p&gt;OK, so enough with the apparent shameless self-promotion. Let&amp;#8217;s get to the point.&lt;/p&gt;

&lt;p&gt;My first implementation of lists used recursion for collection methods. The code was succinct, and, IMHO elegant. It conveyed the essence of what I was trying to achieve. It was easier to understand and thus, I would surmise, easier to maintain. The problem was that for any reasonably large list, stack overflows were common place. The lack of Tail-Call-Optimisation (TCO) meant that the recursive code would eventually blow whatever arbitrary stack limits were in place. The solution: convert the recursive code to an equivalent iterative form.&lt;/p&gt;

&lt;p&gt;Once all methods had been re-implemented using iteration, the code ran just fine on large lists; no more stack overflow errors. The downside was, the code had almost doubled in size&amp;#8211;1~2 lines of code became 2~4 or in some cases even more. The code was now harder to read and far less intention revealing. In short, the lack of Tail-Call-Optimisation lead to less maintainable and I&amp;#8217;d hazard a guess, more error prone code.&lt;/p&gt;

&lt;p&gt;The story however, doesn&amp;#8217;t end there. Take another (albeit contrived) example that partitions integers into odds and evens:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;partitions&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;integers&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;partition&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='ss'&gt;:odd?&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;odds&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;partitions&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;car&lt;/span&gt;
&lt;span class='n'&gt;evens&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;partitions&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;cadr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You would expect &lt;code&gt;odds&lt;/code&gt; to contain &lt;code&gt;[1, 3, 5, 7, 9, ...]&lt;/code&gt;, and &lt;code&gt;evens&lt;/code&gt; to contain &lt;code&gt;[2, 4, 6, 8, 10, ...]&lt;/code&gt;. But the way I initially implemented the code it didn&amp;#8217;t. Here&amp;#8217;s an example to show what happened:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;odds&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;take&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;    &lt;span class='c1'&gt;# =&amp;gt; [1, 3, 5, 7, 9]&lt;/span&gt;
&lt;span class='n'&gt;evens&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;take&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;5&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;   &lt;span class='c1'&gt;# =&amp;gt; [2, 12, 14, 16, 18]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Confused? So was I until it dawned on me that I had broken a fundamental principle: immutability. The underlying block that generates the list of integers has state! Enumerating the odd values first produces the expected results but once we get around to enumerating the even values, the state of the block is such that it no longer starts at 1&amp;#8211;reversing the order of enumeration produces a corresponding reversal of the error. Pure functional Languages such as Haskell have mechanisms for dealing with this but in Ruby, the only construct I really have available to me is explicit caching of generated values.&lt;/p&gt;

&lt;p&gt;Once I had cached the values all was well, or so I thought. I started to write some examples that used files as lists:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;open&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;my_100_mb_file.txt&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;io&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
  &lt;span class='n'&gt;io&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;to_list&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='ss'&gt;:chomp&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;&amp;amp;&lt;/span&gt;&lt;span class='ss'&gt;:downcase&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;each&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;line&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='nb'&gt;puts&lt;/span&gt; &lt;span class='n'&gt;line&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Running the code above took forever to run, much slower than the non-list equivalent. I expected a little slow down sure, but nothing like that which I was seeing.&lt;/p&gt;

&lt;p&gt;At first I suspected garbage collection&amp;#8211;perhaps the virtual machine was being crushed by the sheer number of discarded objects; I could find no evidence for this. Next, I suspected synchronisation&amp;#8211;anything with state needs synchronisation. Again, I found no evidence for this either. A bit more fiddling and a few dozen print statements later&amp;#8211;Ruby has no real profiling tools that I&amp;#8217;m aware of, something that frustrates me no end at times&amp;#8211;I realised what the problem was.&lt;/p&gt;

&lt;p&gt;When I failed to find any evidence of garbage collection as the culprit, it had seemed a bit odd but I wasn&amp;#8217;t sure why I felt that way and thus moved on. Had I stopped and thought about it for a while I may have realised that in fact that was &lt;em&gt;exactly&lt;/em&gt; the problem: there was NO evidence of garbage collection at all. How could that be? Processing hundreds of thousands of lines in a 100MB text file using a linked list was sure to generate lots of garbage. Once a line had been processed, the corresponding list element should no longer have been referenced and thus made available for garbage collection, unless&amp;#8230; unless for some mysterious reason each element was still being referenced.&lt;/p&gt;

&lt;p&gt;My caching implementation worked like this: As each value is generated, it&amp;#8217;s stored in an element and linked to from the previous element: &lt;code&gt;[A] -&amp;gt; [B] -&amp;gt; [C]&lt;/code&gt;. At face value this works well&amp;#8211;if you never hold a references to &amp;#8220;A&amp;#8221; or &amp;#8220;B&amp;#8221;, they will become available for garbage collection. So what could possibly have been going wrong? Each line was being processed and then discarded. Surely, that meant each corresponding element should have become available for garbage collection?&lt;/p&gt;

&lt;p&gt;Now recall that I had converted the recursive code to an iterative equivalent. This had now come back to bite me, hard!&amp;#8211;though to be fair the recursive code would have suffered in a similar and perhaps more obvious way. The call to &lt;code&gt;map&lt;/code&gt; runs in the context of the very first line which, because of the caching, directly and indirectly references every other line that is processed! The lack of Tail-Call-Optimisation in Ruby means that whether I use recursion or iteration, if I process all elements from the head of a stream, the garbage collector can never reclaim anything because the head element is always referenced until the end of the process!&lt;/p&gt;

&lt;p&gt;Some of my colleagues have suggested that I just get over it and use a &amp;#8220;real&amp;#8221; language like &lt;a href='http://clojure.org/'&gt;Clojure&lt;/a&gt;. Whilst I understand the sentiment, the point of Hamster is not necessarily to implement a functional language in Ruby. Rather, it is to see what can be done in object-oriented languages and, in this case, Ruby.&lt;/p&gt;

&lt;p&gt;Hamster has allowed me to demonstrate that functional language idioms can, for the most part, translate quite well into object-oriented equivalents. However, the lack of Tail-Call-Optimisation severely limits what is possible.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/OAISsk5Yi-w" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/12/why-object-oriented-language-need-tail-calls.html</feedburner:origLink></entry>
    
    <entry>
        <title>Responsibility Traps</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/Of0eHWZX4pA/responsibility-traps.html" />
        <updated>2009-10-31T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2009/10/responsibility-traps</id>
        <content type="html">&lt;p&gt;I recently watched a wonderfully insightful presentation by Eric Evans on &lt;a href='http://www.infoq.com/presentations/design-strategic-eric-evans'&gt;Responsibility Traps&lt;/a&gt;. In it he describes a number of traps into which otherwise well meaning and capable developers fall. Among others these include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building a platform to make other (lesser) programmers more productive&lt;/li&gt;

&lt;li&gt;Cleaning up other people&amp;#8217;s mess; being a janitor&lt;/li&gt;

&lt;li&gt;Making hackers (pejorative) look even better&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;He concludes that the responsible developer often focuses her energy on solving the wrong problem, incorrectly believing it to be in the best interests of the project/company/etc. as a whole.&lt;/p&gt;

&lt;p&gt;Since then I have subconsciously been on the lookout for other areas of life where this anti-pattern arises and to my delight (or perhaps horror), I see it everywhere.&lt;/p&gt;

&lt;p&gt;I thought about the number of relationships that I had dragged on for much longer than was probably good for either party, where, as a result of my desire to avoid hurting anyone, both parties suffered needlessly.&lt;/p&gt;

&lt;p&gt;I spoke with a colleague who told me how, in a recent attempt to both fulfil his unspoken promise to help a project out of trouble and preserve the reputation of his sponsors, he continued to engage with the client well beyond his own reasonable belief of success. A near stress-related break down followed shortly thereafter leading to strained relationships all &amp;#8216;round.&lt;/p&gt;

&lt;p&gt;I can&amp;#8217;t count the number of times I&amp;#8217;ve tried to &amp;#8220;rescue&amp;#8221; a project I thought was doomed to failure, implement an unnecessarily complex story, &amp;#8220;protect&amp;#8221; a friend/relative/colleague/client from some bad news. In almost all cases the outcome was as bad as, if not worse than, it might have been had I confronted the reality at the outset.&lt;/p&gt;

&lt;p&gt;Why do I fall into these traps when I believe I&amp;#8217;m primarily motivated by of a sense of duty and responsibility? Partly I think it&amp;#8217;s about taking a path of least resistance &amp;#8211; It seems easier to try and press ahead to &amp;#8220;fix&amp;#8221; the symptom than to address the underlying cause; partly it&amp;#8217;s about self-esteem &amp;#8211; I&amp;#8217;m a failure unless I can solve the problem; there&amp;#8217;s an aspect of self-importance &amp;#8211; few others can see what I see, so it&amp;#8217;s up to me to do something about it. And then there&amp;#8217;s just a plain old misguided sense of responsibility.&lt;/p&gt;

&lt;p&gt;Many years ago, someone handed me a copy of a Garfield cartoon &amp;#8211; ironically it was probably a technically illegal copy. The cartoon showed Garfield in bed on a Monday morning with Jon telling him to &amp;#8220;Get out of bed Garfield!&amp;#8221; Garfield wonders to himself &amp;#8220;What&amp;#8217;s my motivation?&amp;#8221; Taken literally that doesn&amp;#8217;t really say much but the message it has left with me is to be honest with myself about what really drives my decisions.&lt;/p&gt;

&lt;p&gt;As a professional software developer, I believe I have a duty of care to act in the best interests of my employer even if that means delivering the news nobody wants to hear&amp;#8211; &amp;#8220;I think we&amp;#8217;d be better off killing this project than sinking anymore money into it.&amp;#8221; &amp;#8211; and that doing so is ultimately better for me as well.&lt;/p&gt;

&lt;p&gt;More often than not, the way a message is received has far more to do with the way in which it is delivered than with the substance of the message itself. Telling someone they&amp;#8217;re screwed unless they do what you say probably won&amp;#8217;t get you anywhere; suggesting humbly that they are spending double what they could be paying if all they are after is someone who&amp;#8217;ll unquestioningly implement whatever whacky ideas they present, has historically worked out much better for me.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve come to the conclusion that, more important than acting responsibly is to act ethically &amp;#8211; fairly and honestly. If you act ethically you will necessarily end up acting responsibly but not necessarily the other way &amp;#8216;round. Acting ethically takes courage, determination and optimism and that&amp;#8217;s bloody hard work&amp;#8482;. I encourage you to be brave, take a risk, act ethically and do the right thing.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/Of0eHWZX4pA" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/10/responsibility-traps.html</feedburner:origLink></entry>
    
    <entry>
        <title>Plugins: Grab 'em while they're stale</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/zhdyLl88okE/plugins-grab-em-while-theyre-stale.html" />
        <updated>2009-09-19T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2009/09/plugins-grab-em-while-theyre-stale</id>
        <content type="html">&lt;p&gt;I don&amp;#8217;t like leaving unused code lying around, unused applications installed, unused clothes in the wardrobe, etc. As a consequence I&amp;#8217;m often referred to as &amp;#8216;Mr. Detritus&amp;#8217;.&lt;/p&gt;

&lt;p&gt;As you probably know, I&amp;#8217;ve created a number of Ruby on Rails plugins over the years. Most of them when I first started out with Rails and for that matter, Ruby. Most of them had poor (if any) test coverage and the code looked generally like a dog&amp;#8217;s breakfast but they satisfied a need &amp;#8211; scratched an itch if you like &amp;#8211; I had at the time.&lt;/p&gt;

&lt;p&gt;Time marches on and although I will continue to use Ruby as a language, I no longer have any desire to use Rails. Some of my plugins ended up in Rails core, I&amp;#8217;ve continued to use others on recent projects but most of them have been left to rot &amp;#8211; some of them I wouldn&amp;#8217;t use even if I did another Rails project having long since considered them failed experiments.&lt;/p&gt;

&lt;p&gt;And so it is that I will very shortly (within the next month) delete most of the plugins from my &lt;a href='http://github.com/harukizaemon'&gt;GitHub account&lt;/a&gt;. If you wish to continue using them, feel free to fork and keep a copy for yourself. Republish them under your own name if you wish for they will no doubt be better cared for by you than me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; By popular demand, a &lt;a href='http://github.com/harukizaemon/redhillonrails'&gt;Once off never to be repeated copy of the UNSUPPORTED Rails plugins&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/zhdyLl88okE" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/09/plugins-grab-em-while-theyre-stale.html</feedburner:origLink></entry>
    
    <entry>
        <title>Random thoughts on our current Agile process</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/a5PqwUV-yY0/random-thoughts-on-our-current-agile.html" />
        <updated>2009-08-31T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2009/08/random-thoughts-on-our-current-agile</id>
        <content type="html">&lt;p&gt;It&amp;#8217;s late and I don&amp;#8217;t seem to be able to sleep so for something to do I thought I&amp;#8217;d jot down (ok copy from an email I sent out earlier in the week) some thoughts about our development process as it has evolved over the last few months or so.&lt;/p&gt;

&lt;p&gt;As always, I can only speak from personal experience (one data point doesn&amp;#8217;t really count for much) so here&amp;#8217;s my totally subjective perspective, YMMV:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Full-time pairing when possible/practical&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;No more than one card per pair in dev at any time&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;No more than one card per pair in ready-for-dev at any time&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Nothing to be blocked; If it&amp;#8217;s blocked we work to remove the blockage&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;New cards are demand pulled into read-for-dev as cards are moved from dev to ready-for-test&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We have big picture story card sessions as required&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We have planning meetings at the start of each iteration where we discuss what&amp;#8217;s &amp;#8220;planned&amp;#8221;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We give everything t-shirt sizes (S, M, L)&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;No technical stories; everything must be done because it delivers business value&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We don&amp;#8217;t measure velocity&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We aggressively split cards&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;I repeat, we aggressively split cards&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Daily stand-ups&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Parking lot for post-stand up discussions&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;2-week iterations with retro followed by a kick-off to discuss the stories&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We try to focus on doing things as simply as possible&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We try to focus on building things correctly rather than as fast as possible&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We fight to have a REAL user available to better understand their needs&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We rally against the usual cries of &amp;#8220;but I know we&amp;#8217;ll need it&amp;#8221;; We trust that by building things simply we can always add on the extra functionality later&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Trying to deliver everything to everyone leads to delivering nothing at all to anyone&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;T-shirt sizes help the business prioritise not estimate delivery dates; Business value is a function of, among other things, time/cost to build&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Rolling technical stories into stories that deliver business value force us to change course slowly and justify changes&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We usually have parallel implementations of some things as a consequence&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Minimal changes are allowed on &amp;#8220;old&amp;#8221; implementations; anything substantial requires a migration to the &amp;#8220;new&amp;#8221; implementation&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;If we can deliver &lt;em&gt;some&lt;/em&gt; business value early by splitting the cards we do so as soon as possible; Eg. business can view existing data in the new form but editing is a new card because they can still use the old mechanism for that.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;It&amp;#8217;s critical that the whole team is taken on the &amp;#8220;journey&amp;#8221; so they understand &lt;em&gt;why&lt;/em&gt; things are being built. Doing so brings the team into alignment and also allows the team to make informed decisions such as re-structuring work to enable splitting cards for aggressively.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Bringing the team along for the journey can be painful, never gets easier, and is always worth the effort.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Just-in-time stories really does enable the business to leave the decision as to what&amp;#8217;s important to the last possible moment&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Implementing the smallest amount of code possible for each story is critical to enabling just-in-time development; less code == greater flexibility; E.g. don&amp;#8217;t use a database when the data comes from a spreadsheet and presently only ever changes in a spreadsheet.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We do as much forward thinking as possible/practical; We think of as many likely scenarios as we can and keep reducing the scope of the implementation so as not to preclude implementing them later on&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Almost nothing ends up looking as we thought it would when first envisaged.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;More important than writing the code is working out how to structure the implementation so that we get the job done without precluding possible future work; sometimes this means at least thinking through a strategy for migrating from one implementation to another later on if necessary.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;It&amp;#8217;s amazing how splitting stories reveals just how little the business value certain aspects of stories&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We almost never get through everything that was &amp;#8220;planned&amp;#8221;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We almost always end up doing stories that weren&amp;#8217;t &amp;#8220;planned&amp;#8221;&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We are as close as we can get (due to the bureaucratic nature of the client&amp;#8217;s operations group) to on-demand deployment into production. Ideally we&amp;#8217;d like it to be automated but that&amp;#8217;s just not going to happen anytime soon&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We&amp;#8217;re motivated by getting things done; call that velocity if you will but we really haven&amp;#8217;t found a need to measure velocity. Delivering a constant stream of small but valuable stuff into production every week is VERY motivating.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We value delivering something over delivering nothing&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We actively plan for change Caveats:&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We have a highly competent team&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We have a fixed budget&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We have internal and external users&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We have UI and data-only users&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;We have an existing implementation we are evolving away from It&amp;#8217;s far from perfect and is constantly evolving but as &lt;a href='http://www.prozacblues.com/'&gt;Travis&lt;/a&gt; observed, it kinda represents a snapshot of what being Agile means to me right now.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/a5PqwUV-yY0" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/08/random-thoughts-on-our-current-agile.html</feedburner:origLink></entry>
    
    <entry>
        <title>We're Recruiting</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/rNPiF3dX7Zg/were-recruiting.html" />
        <updated>2009-08-01T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2009/08/were-recruiting</id>
        <content type="html">&lt;p&gt;If you haven&amp;#8217;t heard already, &lt;a href='http://www.cogentconsulting.com.au/'&gt;Cogent Consulting&lt;/a&gt; are recruiting.&lt;/p&gt;

&lt;p&gt;Cogent Consulting prides itself on the depth of its experience with agile software development, and its ability to leverage this experience to benefit Cogent clients. We are an open-book company, with comprehensive employee participation in decision-making.&lt;/p&gt;

&lt;p&gt;What do we do? We’re a three part story. We go out on site as consultants to help our clients get better at producing good software, by both coaching them in agile techniques and working as integral part of their development teams. We produce high-quality websites for clients from our own premises. Finally, we build our own (mostly web-based) products, using the range of great talents that make up our team.&lt;/p&gt;

&lt;p&gt;Right now we’re looking for people who can perform hands-on web application development both in our offices and on client sites, predominantly in Ruby on Rails.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re also looking for people who can provide hands-on support to clients undertaking agile transformations at both the small and large scale, as well as help out with internal product development&lt;/p&gt;

&lt;p&gt;In either case You’ll need to show us that you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;understand the principles of agile software development and have experience working on agile projects&lt;/li&gt;

&lt;li&gt;are collaborative, but willing to be a benevolent dictator when required&lt;/li&gt;

&lt;li&gt;can represent us on a client site in a way that makes us proud&lt;/li&gt;

&lt;li&gt;have a passion for software development and you continue your professional development outside of work hours&lt;/li&gt;

&lt;li&gt;have experience with Ruby on Rails, or you are able to learn it very quickly. Extra points if you’re a Smalltalk or Haskell expert&lt;/li&gt;

&lt;li&gt;understand that “done” means the software is in production&lt;/li&gt;

&lt;li&gt;have a demonstrated track record of successful delivery&lt;/li&gt;

&lt;li&gt;have a passion for software development and you continue your professional development outside of work hours&lt;/li&gt;

&lt;li&gt;think that the time after five o’clock belongs to your family (yes, that’s contradictory - we want to know how you deal with that contradiction)&lt;/li&gt;

&lt;li&gt;understand that software and process should be opinionated, but not bigoted&lt;/li&gt;

&lt;li&gt;can read, you choose to read, and you understand what you read&lt;/li&gt;

&lt;li&gt;are intellectually omnivorous&lt;/li&gt;

&lt;li&gt;consider communication (written and verbal) to be amongst your strongest skills&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In return, we’ll provide you with a collegial environment that rewards inquisitiveness rather than being an ongoing inquisition. We’ll treat you as part of the Cogent family, and give you a share of the profit and/or the products that we develop. We’ll provide an environment where you can work with your peers, be challenged, and be the best that you can be.&lt;/p&gt;

&lt;p&gt;If this sounds like your thing, you can visit our &lt;a href='http://www.cogentconsulting.com.au/'&gt;website&lt;/a&gt; for more information about Cogent, or email us directly: &lt;a href='mailto:info@cogentconsulting.com.au'&gt;info@cogentconsulting.com.au&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/rNPiF3dX7Zg" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/08/were-recruiting.html</feedburner:origLink></entry>
    
    <entry>
        <title>Less delicious, yet more satisfying</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/Mm3XXLQCiKY/less-delicious-yet-more-satisfying.html" />
        <updated>2009-07-14T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2009/07/less-delicious-yet-more-satisfying</id>
        <content type="html">&lt;p&gt;These days, I spread my research and reading between &lt;a href='http://www.instapaper.com/'&gt;Instapaper&lt;/a&gt; and &lt;a href='http://evernote.com/'&gt;Evernote&lt;/a&gt;. IMHO, &lt;a href='http://delicious.com/'&gt;delicious&lt;/a&gt; is essentially a big old shed with crap in it and no way to actually use any of it other than marvel at how much stuff I&amp;#8217;ve collected.&lt;/p&gt;

&lt;p&gt;On the other hand, both Instapaper and Evernote add value to the stuff I&amp;#8217;ve collected: Instapaper allows me to read blogs and websites on my phone, and Evernote allows me to collect and organise information according to project, tags, etc.&lt;/p&gt;

&lt;p&gt;As &lt;a href='http://www.prozacblues.com/'&gt;Travis&lt;/a&gt; pointed out, this makes it difficult (nay impossible) for others to see what I&amp;#8217;m reading and is largely the reason I send out almost daily emails to colleagues on stuff I think is more generally interesting.&lt;/p&gt;

&lt;p&gt;This morning I noticed that Instapaper helpfully provide a read-only feed of my list. So, for anyone interested, here is the link: &lt;a href='http://www.instapaper.com/rss/175381/1rDOvQp1xwBTeMIoml2TuzPjlmM'&gt;http://www.instapaper.com/rss/175381/1rDOvQp1xwBTeMIoml2TuzPjlmM&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;If you&amp;#8217;d rather not wade through everything I read to find the good bits, I&amp;#8217;ve started &amp;#8220;starring&amp;#8221; items I found insightful and/or think are of more general interest. Here&amp;#8217;s the feed: &lt;a href='http://www.instapaper.com/starred/rss/175381/ttNEuQvOmmM5sX94f0HCO7ns'&gt;http://www.instapaper.com/starred/rss/175381/ttNEuQvOmmM5sX94f0HCO7ns&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/Mm3XXLQCiKY" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/07/less-delicious-yet-more-satisfying.html</feedburner:origLink></entry>
    
    <entry>
        <title>Problem Solving</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/v_eBQX-Zcjw/problem-solving.html" />
        <updated>2009-06-25T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2009/06/problem-solving</id>
        <content type="html">&lt;p&gt;It occurred to me recently that I have this notion of programming as a process that involves breaking a problem down into a sets of smaller and smaller problems until I have something I know how to solve. (I mentioned this to &lt;a href='http://iridescenturchin.blogspot.com/'&gt;Steve&lt;/a&gt; yesterday which reminded him of a &lt;a href='http://www.electronics.dit.ie/staff/sofearghail/mathematicians.htm'&gt;joke about an engineer and a mathematician&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;I have previously just assumed that I therefore follow this process when I&amp;#8217;m actually problem solving however, on reflection, I&amp;#8217;n not so sure. More specifically, I&amp;#8217;m either not doing it at all or, at the very least, I&amp;#8217;m doing it intuitively.&lt;/p&gt;

&lt;p&gt;I wonder how many people do (or have done) this as an explicit part of their own problem solving and if so, what effects they&amp;#8217;ve noticed as a consequence.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/v_eBQX-Zcjw" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/06/problem-solving.html</feedburner:origLink></entry>
    
    <entry>
        <title>Collaboration</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/vP7xRbgaSQA/collaboration.html" />
        <updated>2009-06-25T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2009/06/collaboration</id>
        <content type="html">&lt;p&gt;I&amp;#8217;ve heard the phrase &amp;#8220;Excuse my poor code&amp;#8221; (or words to that effect) a number of times recently. I&amp;#8217;ve said it to myself about my own code (if not to others), I&amp;#8217;ve heard two of my work colleagues say it, and I&amp;#8217;ve had a customer&amp;#8217;s sole developer apologise ad nauseum about his code.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m not here to make any determination as to the veracity of these claims but the thing that I find interesting is that in all cases, the majority of the code in question was written by a single person.&lt;/p&gt;

&lt;p&gt;Now this may be difficult for some to believe but I inherently don&amp;#8217;t trust my own opinion. I do tend to confidently put ideas forward as bold assertions to be shot down when I&amp;#8217;m wrong. The confidence comes from knowing I&amp;#8217;ll defend my ideas to the hilt and not take it personally when my argument is proven flawed.&lt;/p&gt;

&lt;p&gt;I hate working alone because I don&amp;#8217;t trust decisions that weren&amp;#8217;t arrived at through furious debate. I don&amp;#8217;t like developers working alone no matter how good they are (or think they are) because I don&amp;#8217;t trust they can be objective enough by themselves. In fact I don&amp;#8217;t care if they&amp;#8217;re working in pairs of developers or not, I just want their decisions to be scrutinised by smart people as early as possible.&lt;/p&gt;

&lt;p&gt;The idea that the majority of a developer&amp;#8217;s work involves going off to think on their own is totally nonsensical to me. It feels like a lot of hocus pocus going on behind closed doors and then &lt;em&gt;poof&lt;/em&gt; a few days later something is divined. Not only is the process opaque, but the possibility for smart people to scrutinise is left as late as possible. Sure, I like to sit and ponder without the hullabaloo of every man and his dog trying to give me their 2c worth as much as the next but the lack of transparency and scrutiny in this as a process is something I find very difficult to accept.&lt;/p&gt;

&lt;p&gt;Smart people working alone is even worse. They&amp;#8217;re often implicitly promoted to the position of grand wizard, the seer and knower of all things. They go away, think about a problem and come back with much fanfare (trumpets playing, drums beating) to bestow upon the people their creation who will wonder in amazement at the design, so simple and yet, so complex, that only they can truly grasp the significance of what they have achieved.&lt;/p&gt;

&lt;p&gt;When I write code on my own, I feel personally, individually, responsible. When I write code on my own, the pressures I feel are, mostly, self imposed. They make me lie awake at night. They make me code into the wee hours of the morning, on the train home. I worry that I&amp;#8217;ve missed something. I start to believe my own hype. That I&amp;#8217;m good enough to do this on my own. That because I did most of it on my own, I should fix it on my own lest someone else realise how crap my code is. In a vacuum my ideas have no predators. As importantly (if not more so), my priorities have no predators. I race towards a goal without stopping to re-think that goal because I&amp;#8217;m stuck in a vicious cycle of self doubt and self confidence. Moreover, when I work alone, the production of code becomes the focus and not, as I believe it should be, thinking!&lt;/p&gt;

&lt;p&gt;When we write code together we have shared code ownership. I feel like someone has my back. That even if we got the decision &amp;#8220;wrong&amp;#8221;, we decided together and if two smart people can&amp;#8217;t get it right then maybe it&amp;#8217;s good enough, maybe there are diminishing returns for adding more people to solving the problem. When I go home at night, sure I might tinker but I know there&amp;#8217;s not much point to spending a lot of effort because I&amp;#8217;ll just be re-doing it tomorrow anyway. And if there is something we missed, someone has my back if need be.&lt;/p&gt;

&lt;p&gt;I speak as one who has been, done and experienced others doing all of the above and decided once and for all that it&amp;#8217;s just not worth working alone. Having more than one person working on something WILL cost more but I assert that the result will be better and will be achieved more quickly and with less churn. Anyone who thinks they&amp;#8217;re smart enough to do otherwise needs to learn to &lt;a href='http://teddziuba.com/2009/06/startups-keep-it-in-your-pants.html'&gt;keep it in their pants&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I have this mental model of software development that is akin to the way I&amp;#8217;ve heard Abraham Lincoln&amp;#8217;s cabinet described. Apparently he got a whole bunch of really smart people together, even those from opposite sides of politics, and let them argue it out. His (Lincoln&amp;#8217;s) role was to decide when to stop the debate and which idea(s) to act on.&lt;/p&gt;

&lt;p&gt;I think that&amp;#8217;s what collaborative development should be.&lt;/p&gt;

&lt;p&gt;YMMV :)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/vP7xRbgaSQA" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/06/collaboration.html</feedburner:origLink></entry>
    
    <entry>
        <title>No, Sleep, Till Bedtime</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/w2uNu3ZwOSg/no-sleep-till-bedtime.html" />
        <updated>2009-06-14T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2009/06/no-sleep-till-bedtime</id>
        <content type="html">&lt;p&gt;Or at least until all those &lt;a href='http://twitter.com/'&gt;Twitter&lt;/a&gt; client developers have fixed their &lt;a href='http://www.twitpocalypse.com/'&gt;Twitpocalypse&lt;/a&gt; bugs. In case you didn&amp;#8217;t know, a few days ago the ID range used for Twitter&amp;#8217;s messages exceeded 2^31 (approximately 2 billion) causing any apps that stored them as 32-bit integers to think they were really small negative numbers.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s usual &amp;#8211; and I say usual because I don&amp;#8217;t always adhere to it &amp;#8211; policy for storing external identifiers is to treat them as text, even when I know they are numbers. Why? Essentially because I consider it a coincidence that they&amp;#8217;re numbers. That identifier, number though it may be, has no special significance to me over and above being an opaque handle to some entity in another system. As such, I like to treat them as text.&lt;/p&gt;

&lt;p&gt;Discussing this with a good friend and colleague of mine, the question of column width came up. Ie. if you&amp;#8217;re going to make it text, how long should the column be? If you&amp;#8217;re lucky enough to be using a database such as PostgreSQL, then the answer is: it doesn&amp;#8217;t matter &amp;#8211; there&amp;#8217;s no performance benefit to artificially limiting the size of the column. For other databases, the common practice is to use something like &lt;code&gt;VARCHAR(255)&lt;/code&gt;. Think about it, even if it is a number that&amp;#8217;s 10^255!&lt;/p&gt;

&lt;p&gt;Twitter claims that its &lt;a href='http://apiwiki.twitter.com/Twitter-API-Documentation'&gt;API&lt;/a&gt; is RESTful. And if to you, REST means nice, predictable URLs with some semantic path possibly followed by a numeric id and returning numeric ids in search results, then yes, it&amp;#8217;s RESTful. Want to see the most recent messages for a user? There&amp;#8217;s a simple HTTP request you can make to a nice, semantic (if you speak English) URL that returns a list of them and their identifiers. And, as expected, our Twitter clients have been dutifully squirrelling these ids away in integer fields (probably because that&amp;#8217;s the default) and all has well until 2 days ago.&lt;/p&gt;

&lt;p&gt;Now, without going into too much of an ideological rant, I happen subscribe to the principle that RESTful URLs should be opaque. That is, a URL is a URL is a URL. No slicing, no dicing, no assembling, no joining. If I have a URL to a resource then that&amp;#8217;s what I use. Period. End of story. (You can find plenty of discussion on this by Roy Fielding using Google.)&lt;/p&gt;

&lt;p&gt;So, back to our column widths. Assuming we have a text field in our database large enough to accommodate a URL, we could go one step further. Rather than treat the identifier as text and storing that, why not go the whole hog and store the URL instead?&lt;/p&gt;

&lt;p&gt;As far as I can tell, the only reason is that Twitter&amp;#8217;s API, RESTful though they may claim, sends back numeric identifiers rather than URLs which in turn leads developers to incorrectly assume that they should be storing them as numbers.&lt;/p&gt;

&lt;p&gt;On their own, identifiers are meaningless and in fact, useless. To utilise an identifier requires us to know the system in which it is stored and the collection in which it belongs. If instead each piece of information was identified by a URL we get all that context for free and the power to share information grows phenomenally.&lt;/p&gt;

&lt;p&gt;To me, the beauty and power of the internet is the ability to link together disparate systems in ways no one had previously imagined. More specifically, in ways the publishers of the information never considered.&lt;/p&gt;

&lt;p&gt;Opaque URLs combined with idiomatic use of HTTP verbs can help reduce the coupling between producers and consumers by giving back control to producers in how and where they store information and at the same time increasing the freedom for others to share and use that information.&lt;/p&gt;

&lt;p&gt;(That last paragraph reads like an &lt;a href='http://www.amnesty.org/'&gt;Amnesty International&lt;/a&gt; commercial!)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/w2uNu3ZwOSg" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/06/no-sleep-till-bedtime.html</feedburner:origLink></entry>
    
    <entry>
        <title>Shameless Self Promotion</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/QxvJs_Tr3mA/shameless-self-promotion.html" />
        <updated>2009-05-15T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2009/05/shameless-self-promotion</id>
        <content type="html">&lt;p&gt;So the past couple of months, I&amp;#8217;ve finally had the luxury of starting to realise my (and &lt;a href='http://www.cogentconsulting.com.au'&gt;Cogent&amp;#8217;s&lt;/a&gt;) dream of doing product development.&lt;/p&gt;

&lt;p&gt;We just recently launched what we hope is a very simple, easy to use and somewhat opinionated web application for &lt;a href='http://www.runwayapp.com/'&gt;Getting Things Done&amp;#8482; (GTD)&lt;/a&gt;. It&amp;#8217;s a crowded market to be sure but we really believe we understand GTD well enough to deliver a system that is &lt;strong&gt;more than just a to-do list with GTD inspired keywords&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Runway is still in the early stages of feature development. For those that know anything about GTD, you&amp;#8217;ll be happy to hear that we&amp;#8217;re working on delivering Projects, Artifacts, Agendas and of course an Inbox, to name but a few, in the very near future.&lt;/p&gt;

&lt;p&gt;What you see now is, and will always be, free. at some point we&amp;#8217;ll be adding pay-for features but we&amp;#8217;ll also be doing the right thing by all our early adopters. So, if you have 5 or so minutes, we&amp;#8217;d love for you to &lt;a href='http://www.runwayapp.com/signup'&gt;sign up&lt;/a&gt;, have a play, and of course, tell us what you think.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/QxvJs_Tr3mA" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/05/shameless-self-promotion.html</feedburner:origLink></entry>
    
    <entry>
        <title>Web standards and all I got was this lousy website</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/UJ_0weTzNjU/web-standards-and-all-i-got-was-this.html" />
        <updated>2009-04-17T00:00:00-07:00</updated>
        <id>http://www.harukizaemon.com/2009/04/web-standards-and-all-i-got-was-this</id>
        <content type="html">&lt;p&gt;Over the Easter long weekend, I had a great break from work and a great opportunity to think about and reflect on my career, my job, and my profession as a whole. It&amp;#8217;s safe to say I become a bit disheartened and disillusioned. The one striking conclusion I kept arriving at is that we are so technology focused that we spend too much time, money and effort building things that the customer is &amp;#8220;happy&amp;#8221; with but not blown away by. That we artificially constrain the end user experience based on our notions of &amp;#8220;correctness&amp;#8221;. In particular, &lt;strong&gt;web application development is largely a bunch of dick-pulling technical masturbation&lt;/strong&gt;, forever re-inventing the wheel at a ridiculously low level of abstraction shoving our technological solutions down user&amp;#8217;s throats in the name of &amp;#8220;software engineering&amp;#8221;. &lt;strong&gt;What&amp;#8217;s worse is that I&amp;#8217;ve been complicit.&lt;/strong&gt; Not only by buying the hype but often by trying to do &amp;#8220;the right thing&amp;#8221; even when I felt as though I was bashing my head against a brick wall.&lt;/p&gt;

&lt;p&gt;Rewind the clock to somewhere between 1996 and 1999. During those years I, along with a good friend and colleague built a desktop application that was delivered to thousands of users across Australia using nothing more than good old-fashioned client-server SQL written in, of all things, PowerBuilder &amp;#8211; kinda like VisualBasic. &lt;strong&gt;More than 10 years ago, the user experience was compelling and sophisticated, it performed exceptionally well over 2400 baud dialup modems, and we built the initial release with only 2 people over 3 months from scratch.&lt;/strong&gt; As shameful as it is, especially coming from one so vocal about automated testing as I, we had nothing but manual testing but we also had few bugs and when users did find a problem, we fixed and redeployed within 24 hours &amp;#8211; mostly because we didn&amp;#8217;t want to interrupt users as they worked and so waited until after hours. Over the next 12 months, we were able to adapt to the user&amp;#8217;s needs immediately. Rarely did we add the features as request but we always managed to produce a solution they actually needed. Fast forward a decade and &lt;strong&gt;I feel like I suck&lt;/strong&gt; because I honestly don&amp;#8217;t believe I could do the same thing again today. In fact, &lt;strong&gt;I challenge any of us to build the same user experience with our existing technology stack&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To those that know me well, I will no doubt sound like a broken record but I can&amp;#8217;t help feel we&amp;#8217;ve been trying to coerce HTML &amp;amp; CSS into something they just aren&amp;#8217;t and doing so for a decade now.&lt;/p&gt;

&lt;p&gt;Think about it, HTML: HyperText Markup Language. Does that sound like it has anything to do with layout and design? In fact do you know any designers, even those that call themselves web designers, that do any of their design work in HTML/CSS? No &amp;#8211; well none that I&amp;#8217;ve ever heard of. The closest I can think of is a colleague who does his wireframes in OmniGraffle and then generates HTML/CSS. Why? I put it to you it&amp;#8217;s because &lt;strong&gt;we don&amp;#8217;t think in HTML/CSS&lt;/strong&gt;. You CAN&amp;#8217;T effectively think in HTML/CSS and if a guy who&amp;#8217;s expertise lies in designing user interfaces can&amp;#8217;t think in terms of HTML/CSS why the hell do we think we should?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML was designed for linking documents&lt;/strong&gt; with a modicum of layout and has served that purpose admirably. As a result, the web browser largely won the battle for desktop supremacy and almost everyone has a web browser and regularly uses a number of web sites. Similarly, pretty much everyone has a computer running an 80x86 based CPU and run dozens of applications built specifically for it. &lt;strong&gt;HTML/CSS are the machine language of the web&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For those of us lucky enough to have done any assembler programming, we&amp;#8217;ve also been lucky enough not to have had to do any for a very long time. Instead, we chose to move away from assembler to other languages. C, C++, Java, Smalltalk, Python, Perl, Ruby, literally &lt;strong&gt;dozens of other programming languages that have systematically improved the level of abstraction.&lt;/strong&gt; Many of these languages now run on top of the JVM, LLVM, CLR, etc. themselves abstractions on top of the underlying CPU.&lt;/p&gt;

&lt;p&gt;Did we move because the runtime was faster? Hardly. In fact in almost all cases outrageous claims were made early on that poor performance would be the undoing of these languages and in almost all cases these claims ultimately proved unfounded. No, &lt;strong&gt;we moved to these languages because we hoped they would give us a better level of abstraction.&lt;/strong&gt; That we could code more closely to the way we think. That we would one day realise the dream of literally thinking in code.&lt;/p&gt;

&lt;p&gt;Even within languages we constantly strive to improve the level of abstraction. In many cases we&amp;#8217;ve created Domain-Specific-Languages in order that we are better able to think IN the language most appropriate to the task at hand rather than needing to perform some contorted mapping process. This is the reason the Ruby community has slowly moved from Test::Unit to RSpec/Shoulda: Test::Unit does the job just fine but it&amp;#8217;s verbose and &amp;#8220;too close to the metal&amp;#8221;. Just like assembler. &lt;strong&gt;When I&amp;#8217;m the most productive I&amp;#8217;m literally thinking in code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We&amp;#8217;ve largely sorted the back-end problems&lt;/strong&gt;: Database access layers, routing, data format conversion, validation, you name it it&amp;#8217;s all been largely worked out in whatever framework and language combination you can imagine. &lt;strong&gt;The same cannot be said of the front-end WHERE IT ACTUALLY MATTERS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Granted, HTML/CSS has undergone change but to what extent and to what end? We have JSP, ASP, ERB, HAML, SASS, Liquid, blueprint, jQuery, Prototype, MooTools, Dojo, YUI, etc. but none of them appreciably raises the level of abstraction. &lt;strong&gt;Most advances in the world of HTML/CSS are lipstick.&lt;/strong&gt; They&amp;#8217;re all constrained by the fallacy that HTML/CSS is the holy grail of web design. No, the whole problem with web development is that &lt;strong&gt;we haven&amp;#8217;t abstracted away the underlying technology&lt;/strong&gt;, instead we&amp;#8217;ve been conned by a bunch of HTML/CSS gurus and boffins who think that designing the perfect machine code is all the world needs. &lt;strong&gt;There is nothing more primitive than HTML+CSS when it comes to the web.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HTML &amp;amp; CSS try to be all things to all people and by doing so, much like J2EE, we ended up with a set of primitive tools that are repetitive, verbose, hard to test, maintain and refactor and ultimately provide a user experience that can best be described as &lt;strong&gt;a tarted up, 24-bit 3270 terminal.&lt;/strong&gt; Don&amp;#8217;t believe me? Point me at a website where the user experience feels liquid and natural. Where it literally gets out of your way so that you never even realise you&amp;#8217;re using it? For the most part you can&amp;#8217;t. The poster children of the Rails world provide at best a rudimentary user experience. I suspect people use them because there is no alternative, not because it&amp;#8217;s actually a great UX. Why? IMHO because the technology choices are just plain awful. If you can find a website with a rich user experience that just melts away, you&amp;#8217;ll likely find a bunch of developers who either had nervous breakdowns or spent many years building some superduper framework, or both!&lt;/p&gt;

&lt;p&gt;To be fair I&amp;#8217;m no doubt coming across as though HTML/CSS is to blame for all the world&amp;#8217;s problems. Not at all. We suffer from similar problems across the board in software development. It just so happens that I&amp;#8217;ve been in the world of web development for a long time now and feeling the effects.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m not advocating the use of any particular technology &amp;#8211; that would kinda defeat the purpose of my argument. What I am saying is that I believe we&amp;#8217;re stuck in a mindset that only allows us to think inside the incredibly narrow bounds of something we&amp;#8217;re used to, IMHO, only because it&amp;#8217;s all we&amp;#8217;re used to.&lt;/p&gt;

&lt;p&gt;Rather than embracing the &amp;#8220;web paradigm&amp;#8221; how about we &lt;strong&gt;embrace the user and their experience and decide what technology would best enable us to deliver that.&lt;/strong&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/UJ_0weTzNjU" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/04/web-standards-and-all-i-got-was-this.html</feedburner:origLink></entry>
    
    <entry>
        <title>A Title Case Gem for Ruby</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/mxQ82w5Gl9o/title-case-gem-for-ruby.html" />
        <updated>2009-02-02T00:00:00-08:00</updated>
        <id>http://www.harukizaemon.com/2009/02/title-case-gem-for-ruby</id>
        <content type="html">&lt;p&gt;A project I&amp;#8217;m working on called for some &amp;#8220;smart&amp;#8221; capitalisation of page titles. Essentially I wanted to take a URL &lt;a href='http://en.wikipedia.org/wiki/Slug_(production'&gt;slug&lt;/a&gt;) and generate a page title.&lt;/p&gt;

&lt;p&gt;Rails comes with a built-in &lt;code&gt;String#titleize&lt;/code&gt; method that capitalises every word but that looked a little odd when the title was something like: &lt;em&gt;&amp;#8220;My Hovercraft Is Full Of Eels&amp;#8221;&lt;/em&gt;. So I went on a hunt for something &amp;#8220;smarter&amp;#8221;.&lt;/p&gt;

&lt;p&gt;After a little search I stumbled upon Marshall Elfstrand&amp;#8217;s &lt;a href='http://vengefulcow.com/titlecase/'&gt;JavaScript, Ruby, and Objective-C ports&lt;/a&gt; of &lt;a href='http://daringfireball.net/'&gt;John Gruber&amp;#8217;s&lt;/a&gt; &amp;#8220;Title Case&amp;#8221; algorithm and decided to turn it into a &lt;a href='http://github.com/harukizaemon/titleizer'&gt;Gem&lt;/a&gt; that adds &lt;code&gt;String#titleize&lt;/code&gt; and &lt;code&gt;String#titleize!&lt;/code&gt; (aliased as &lt;code&gt;#titlecase&lt;/code&gt;, and &lt;code&gt;#titlecase!&lt;/code&gt; respectively). When used in a Rails environment, this effectively replaces the Rails versions.&lt;/p&gt;

&lt;p&gt;Now my page titles look a little more human-like: &amp;#8220;My Hovercraft is Full of Eels&amp;#8221;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/mxQ82w5Gl9o" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/02/title-case-gem-for-ruby.html</feedburner:origLink></entry>
    
    <entry>
        <title>Plugins move</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/7b_xlOw5rMM/plugins-move.html" />
        <updated>2009-01-18T00:00:00-08:00</updated>
        <id>http://www.harukizaemon.com/2009/01/plugins-move</id>
        <content type="html">&lt;p&gt;Following hot on the heels of my &lt;a href='http://www.harukizaemon.com/2009/01/blog-move.html'&gt;blog move&lt;/a&gt;, I&amp;#8217;ve finally moved all my rails plugins off the venerable RubyForge and onto GitHub.&lt;/p&gt;

&lt;p&gt;Since I started working at &lt;a href='http://www.cogentconsulting.com.au'&gt;CogentConsulting&lt;/a&gt; &amp;#8211; no we&amp;#8217;re not &amp;#8220;The Company of ex-ThoughtWorkers&amp;#8221; unless you count all 3 of us as somehow statistically significant &amp;#8211; I&amp;#8217;ve had less and less time and less and less inclination to spend any appreciable effort on &lt;a href='http://www.redhillconsulting.com.au/'&gt;RedHill&lt;/a&gt; related stuff to the point where the company really exists just to support and market &lt;a href='http://www.redhillconsulting.com.au/simian'&gt;Simian&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a consequence, I&amp;#8217;ve also dropped the RedhillOnRails moniker in favour of publishing the plugins under &lt;a href='http://github.com/harukizaemon/'&gt;my personal account&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/7b_xlOw5rMM" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/01/plugins-move.html</feedburner:origLink></entry>
    
    <entry>
        <title>Blog move</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/PP27sLBkOR4/blog-move.html" />
        <updated>2009-01-17T00:00:00-08:00</updated>
        <id>http://www.harukizaemon.com/2009/01/blog-move</id>
        <content type="html">&lt;p&gt;If you&amp;#8217;re reading this then the move of my blog was successful and thank-you for putting up with a screwy RSS feed during the transition. No doubt you received double or possibly even triple posts.&lt;/p&gt;

&lt;p&gt;Why the move? Well, even though &lt;a href='http://www.geekisp.com/'&gt;GeekISP&lt;/a&gt; have been a fantastic hosting provider over the years and MovableType has been pretty reliable as a blogging platform, in my never ending quest to Do Less Stuff, I figured it was time to move the pain somewhere else.&lt;/p&gt;

&lt;p&gt;From a technical perspective, the move was fairly easy though not without some pain. There is no direct way to import from MT to Blogger however I did find &lt;a href='http://movabletype2blogger.appspot.com/'&gt;a tool that helped&lt;/a&gt; convert the MT export file into something Blogger could import.&lt;/p&gt;

&lt;p&gt;I also wrote a quick script to replace all internal references with new links as well as generating a new .htaccess file for any links from the outside world. This step was pretty easy although it took some trial and error to work out what how Blogger converts titles into URLs &amp;#8211; as near as I can tell it truncates to a maximum of 40 characters with a bias towards word boundaries. The duplicate posts appearing in the RSS feed were as a direct result of me re-creating the entire blog several times fixing little things here and there.&lt;/p&gt;

&lt;p&gt;And so it is that my blog comes to be here on Blogger. The next step is to move all my domain hosting to Google Sites but that&amp;#8217;s for another day. Hopefully this will be the last move for some time and, with someone else maintaining my blogging software, hopefully less stuffing around on my part.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/PP27sLBkOR4" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/01/blog-move.html</feedburner:origLink></entry>
    
    <entry>
        <title>Rails, meet Drupal.</title>
        <link href="http://feeds.harukizaemon.com/~r/MyHovercraftIsFullOfEels/~3/oM2dRSLJdWY/rails-meet-drupal.html" />
        <updated>2009-01-12T00:00:00-08:00</updated>
        <id>http://www.harukizaemon.com/2009/01/rails-meet-drupal</id>
        <content type="html">&lt;p&gt;If you&amp;#8217;ve been considering integrating (or replacing) your Drupal application with a Rails application, then &lt;a href='http://github.com/harukizaemon/drupal_fu'&gt;Drupal Fu&lt;/a&gt; may come in handy.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s pretty rough-and-ready &amp;#8211; I essentially just ripped the code out of an existing application and cobbled it together &amp;#8211; with, as yet, no plugin infrastructure, Rakefile, or anything else that might give you a degree of confidence in the quality of the code :)&lt;/p&gt;

&lt;p&gt;That said, the code has been working in a production application for a while and we figured it might help out some others going through the same pain.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MyHovercraftIsFullOfEels/~4/oM2dRSLJdWY" height="1" width="1"/&gt;</content>
    <feedburner:origLink>http://www.harukizaemon.com/2009/01/rails-meet-drupal.html</feedburner:origLink></entry>
    

</feed>
