Steve Tookehttp://tooky.co.uk/2015-12-01T00:00:00+00:00The mob rules, ok?http://tooky.co.uk/the-mob-rules-ok/2015-12-01T00:00:00+00:002015-12-01T12:55:28+00:00Steve Tooke<p>During the last 6 weeks or so, I’ve had the pleasure to be working on <a href="https://cucumber.io/pro">Cucumber
Pro</a> with the team at <a href="https://cucumber.io/">Cucumber
Limited</a>. One of the key thing making this such a good
experience has been the way we’ve been working. Mob Programming.</p>
<h2>What is Mob Programming?</h2>
<blockquote>
<p>All the brilliant people working on the same thing, at the same time, in the
same space, and on the same computer — <a href="https://twitter.com/woodyzuill">@woodyzuill</a></p>
</blockquote>
<p>Mob Programming is a term coined by Woody Zuill. It describes a practice that he
and his team “discovered” while he was coaching at Hunter Industries. It’s a way
of working where the whole team gather around a single computer and work on
a single problem together. The team take turns to “drive” the computer, while
the other members of the team help to think through the problem and find
solutions.</p>
<h2>A Remote Mob</h2>
<p>The Cucumber Pro team works remotely. We are geographically distributed
(although we are usually in similar timezones). Obviously this makes sharing
a computer more of a challenge, but we’ve found a couple of solutions that are
working well for us.</p>
<p>The first thing is that the person driving always works on their computer. This
allows everyone to use the tools they are most comfortable with and saves them
from them having to deal with lag or other connection problems on input.</p>
<p>To share the driver’s computer with the rest of the team we have mostly used
<a href="https://screenhero.com/">Screenhero</a>. Screenhero allows us to share a single
computer with several other participants (I think we’ve had up to 5 or 6).
Unlike other screensharing technology it also gives each user a mouse pointer.
This is <em>especially</em> useful when trying to point out where that misspelt
variable is hiding. Screenhero also allows the navigators to type, which helps
from time to time.</p>
<p>While Screenhero does provide a voice channel, we generally prefer to use
<a href="https://hangouts.google.com/">Google Hangouts</a> for voice and video. Partly
because the sound is better, but really because being able to see each other is
great!</p>
<p>We haven’t found a really good solution for a shared whiteboard yet. Most of the
drawing we’ve done has been on paper and shared with photographs. We’ve also
experimented with an <a href="http://www.ipevo.com/prods/Point-2-View-USB-Camera">iPEVO
camera</a>. This lets you share
a drawing live as it happens. We’ve used it point to paper on the desktop, and
with a whiteboard. This is a bit more of an interactive experience, but it still
only allows one person to draw.</p>
<h2>Mornings only</h2>
<p>We decided that the Cucumber Pro mob would only convene in the mornings. This
gives us 3.5 focussed hours where we all work together. These morning mob
sessions are where we take design decisions. We discuss the work that’s to be
done. Talk through the business, and find examples that we can use to
illustrate them in our Cucumber features. Its also in these sessions that we
write most of the code.</p>
<p>Afternoons are more free-form. For a start everyone in the team has other
responsibilities. So this leaves space for this work. Dealing with email,
running a business, open-source, etc.</p>
<p>But… it also leaves space for people to think, to read, to experiment, to fix
little niggles, to automate tiresome tasks. This space is <em>invaluable</em>. We
liberally use TODOs while we are mobbing. We use them in the same way we might
note something we want to address later on an index card. Fixing TODOs in the
afternoon has been quite common. Sometimes this is just tidying up and getting
work out of the way, so the mob can focus on bigger tasks. Sometimes this is
a spike to try out some idea before presenting it back to the mob.</p>
<h2>Pull requests</h2>
<p>We use <a href="https://github.com">Github’s</a> <a href="https://help.github.com/articles/using-pull-requests/">pull
requests</a> in a couple of
different ways. Firstly, any work that people undertake outside of the mob (in
the afternoon), is almost always done on a pull-request. This allows us to use
GitHub as the communication channel about the code, and it means that work that
is done indivdually is seen by someone else before its merged.</p>
<p>We have also been using pull requests for work-in-progress. Not everyone on the
Cucumber Pro team is available everyday. There’s often someone away delivering
training or consulting, or at a conference. Again pull requests let us use
Github’s great tooling for seeing changes to the code over time, and having
asynchronous discussions with those who weren’t able to join the mob.</p>
<h2>Daily retrospective</h2>
<p>We end every mob session with a short retrospective. We ask ourselves two
questions:</p>
<ul>
<li>What have we learnt?</li>
<li>What puzzles us?</li>
</ul>
<p>We use this as a chance to reflect on the work we have done, and how things
went. We try to recognise things that have gone well so we can do more of them,
and recognise problems early so that we can head them off.</p>
<p>We also spend a few minutes thinking about the next steps, where the mob’s focus
should go next.</p>
<p>We write all of this up in a file at the root of the project and commit it to
the repository. This is helpful for the team members that weren’t in the mob
session. It helps to share what we’ve learnt and our questions with them. It
also marks where the mob finished that day.</p>
<p>We’re currently adding each retrospective at the top of a single file, and
maintaining a history. I’m confident that it will be useful to reflect back on
how our thoughts and feelings about the project change over time.</p>
<h2>Joy</h2>
<p>Mob programming is a great way to build a team. I feel that we get a real sense
that we’re working together towards a common goal. We solve problems together.
We learn together and we teach each other. By reflecting on each session, we
learn more about how each of us likes to work, and how we can all help each
other.</p>
<p>The remote working lets us all be comfortable in our surroundings. We’ve had
<a href="https://twitter.com/mattwynne">Matt</a> join for a few hours while he’s been in
<a href="https://cucumber.io/events/cukeup-australia-2015">Australia</a>. The last couple
of days <a href="https://twitter.com/aslak_hellesoy">Aslak</a> has been in the mob, with
his new baby nestled in a sling — there is something really calming about
hearing contented baby gurgles while your working.</p>
<p>Remote collaboration is quite an intense way to work. I’ve done quite a lot of
remote pair programming and it can be quite draining. Keeping the afternoons
free really helps to combat this.</p>
<p>Working in the mob everyday is fantastic. I look forward to them because
they’re
fun, and I feel like we’re growing as a team every day — but the afternoon
space is just as important.</p>
Hands-on With the Cucumber Events APIhttp://tooky.co.uk/hands-on-with-cucumber-events-api/2015-09-14T01:00:00+01:002015-09-14T17:18:37+01:00Steve Tooke<p><a href="https://cucumber.io/blog/2015/09/11/cucumber-2.1">Cucumber Ruby 2.1</a> introduces the new <a href="http://www.rubydoc.info/gems/cucumber/Cucumber/Events">Events API</a> — a simple way to find out what’s happening while Cucumber runs your features. Events are read-only and simplify the process of writing formatters, and other output tools.</p>
<p>I’ll illustate how to use the API with a worked example that streams Cucumber test results to a browser in real-time.</p>
<h2>Can you give me an example?</h2>
<p>As much as we love our console applications, we can get a much richer experience in a web browser. How could we get Cucumber to push information into a nice web UI, without losing the rich information available with the built-in formatters?</p>
<p>Let’s build a super-simple example using the Events API that uses a websocket to update a web page while cucumber is running.</p>
<p>There’s lots of ways to run a websocket server – a favourite of mine is to use <a href="https://github.com/joewalnes/websocketd"><code>websocketd</code></a> because it’s <em>super</em> simple. Give it an executable that reads <code>STDIN</code> and write <code>STDOUT</code> and you’re done!</p>
<p>For our very simple websocket reporter we are going to use a UNIX <a href="https://en.wikipedia.org/wiki/Named_pipe">named pipe</a> to push information out of our cucumber process. To get these events out onto a websocket we need a shell command that reads from a named pipe and echos back onto <code>STDOUT</code>.</p>
<p><code>subscriber.sh</code></p>
<pre><code class="highlight shell"><span class="c">#!/bin/bash</span>
<span class="nv">fifo_name</span><span class="o">=</span><span class="s2">"events"</span>;
<span class="o">[</span> -p <span class="nv">$fifo_name</span> <span class="o">]</span> <span class="o">||</span> mkfifo <span class="nv">$fifo_name</span>;
<span class="k">while </span><span class="nb">true
</span><span class="k">do
if </span><span class="nb">read </span>line <<span class="nv">$fifo_name</span>; <span class="k">then
</span><span class="nb">echo</span> <span class="nv">$line</span>
<span class="k">fi
done</span>
</code></pre>
<p>Make sure the script is executable with <code>chmod +x subscriber.sh</code>.</p>
<p>When you run it, it will create an <code>events</code> named pipe if one doesn’t exist already, then wait until there is data on the pipe for it to read. We can see it in action by putting some data on to the pipe: <code>echo "hello, world" > events</code>.</p>
<h3>Writing Cucumber Events to the pipe</h3>
<p>Let’s start by asking cucumber to write messages to the pipe. Add the following to <code>features/support/env.rb</code></p>
<pre><code class="highlight ruby"><span class="no">EVENT_PIPE</span> <span class="o">=</span> <span class="s2">"events"</span>
<span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">exist?</span><span class="p">(</span><span class="no">EVENT_PIPE</span><span class="p">)</span>
<span class="sb">`mkfifo </span><span class="si">#{</span><span class="no">EVENT_PIPE</span><span class="si">}</span><span class="sb">`</span>
<span class="k">end</span>
<span class="n">publisher</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="no">EVENT_PIPE</span><span class="p">,</span> <span class="s2">"w+"</span><span class="p">)</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">sync</span> <span class="o">=</span> <span class="kp">true</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">puts</span> <span class="s2">"started"</span>
<span class="nb">at_exit</span> <span class="p">{</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">puts</span> <span class="s2">"done"</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">close</span>
<span class="p">}</span>
</code></pre>
<p>This doesn’t use the Events API yet, but we’ve got the plumbing in place now to write to the same named pipe as <code>subscriber.sh</code> will read from. With <code>subscriber.sh</code> up and running, you should be able to run cucumber and see <code>started</code> and <code>done</code> output to the terminal by <code>subscriber.sh</code>.</p>
<p>For our simple web-browser cucumber reporter we want to show each step that cucumber runs, and its result. We want cucumber to tell us when it starts to execute, when it starts to run each step, when it finishes a step (and what the result was) and when it’s finished executing.</p>
<p>We’ll send some formatted JSON that give us some information about the events:</p>
<pre><code class="highlight javascript"><span class="p">{</span>
<span class="s2">"event"</span><span class="err">:</span> <span class="s2">"event_name"</span><span class="p">,</span>
<span class="s2">"data"</span><span class="err">:</span> <span class="p">{}</span> <span class="c1">//information about the event</span>
<span class="p">}</span>
</code></pre>
<p>We can modify <code>features/support/env.rb</code> to give us the start and end events:</p>
<pre><code class="highlight ruby"><span class="nb">require</span> <span class="s1">'json'</span>
<span class="no">EVENT_PIPE</span> <span class="o">=</span> <span class="s2">"events"</span>
<span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">exist?</span><span class="p">(</span><span class="no">EVENT_PIPE</span><span class="p">)</span>
<span class="sb">`mkfifo </span><span class="si">#{</span><span class="no">EVENT_PIPE</span><span class="si">}</span><span class="sb">`</span>
<span class="k">end</span>
<span class="n">publisher</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="no">EVENT_PIPE</span><span class="p">,</span> <span class="s2">"w+"</span><span class="p">)</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">sync</span> <span class="o">=</span> <span class="kp">true</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">puts</span><span class="p">({</span><span class="ss">event: </span><span class="s2">"started"</span><span class="p">,</span> <span class="ss">data: </span><span class="p">{}}.</span><span class="nf">to_json</span><span class="p">)</span>
<span class="nb">at_exit</span> <span class="p">{</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">puts</span><span class="p">({</span><span class="ss">event: </span><span class="s2">"done"</span><span class="p">,</span> <span class="ss">data: </span><span class="p">{}}.</span><span class="nf">to_json</span><span class="p">)</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">close</span>
<span class="p">}</span>
</code></pre>
<p>The Cucumber Events API gives us access to what’s going on inside Cucumber while it’s running our features. We want to know when a step is going to be run, and what happened when it finished. Cucumber provides us the <a href="http://www.rubydoc.info/gems/cucumber/Cucumber/Events/BeforeTestStep"><code>BeforeTestStep</code></a> and <a href="http://www.rubydoc.info/gems/cucumber/Cucumber/Events/AfterTestStep"><code>AfterTestStep</code></a> events. To hear about these events we can use the cucumber <code>AfterConfiguration</code> hook to get access to the current config, and add handlers for specific events with the <code>on_event</code> method:</p>
<pre><code class="highlight ruby"><span class="no">AfterConfiguration</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
<span class="n">config</span><span class="p">.</span><span class="nf">on_event</span> <span class="ss">:before_test_step</span> <span class="k">do</span> <span class="o">|</span><span class="n">event</span><span class="o">|</span>
<span class="k">end</span>
<span class="n">config</span><span class="p">.</span><span class="nf">on_event</span> <span class="ss">:after_test_step</span> <span class="k">do</span> <span class="o">|</span><span class="n">event</span><span class="o">|</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Putting this all together we can modify <code>features/support/env.rb</code> to push these events out onto our named pipe too:</p>
<pre><code class="highlight ruby"><span class="nb">require</span> <span class="s1">'json'</span>
<span class="no">EVENT_PIPE</span> <span class="o">=</span> <span class="s2">"events"</span>
<span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">exist?</span><span class="p">(</span><span class="no">EVENT_PIPE</span><span class="p">)</span>
<span class="sb">`mkfifo </span><span class="si">#{</span><span class="no">EVENT_PIPE</span><span class="si">}</span><span class="sb">`</span>
<span class="k">end</span>
<span class="n">publisher</span> <span class="o">=</span> <span class="no">File</span><span class="p">.</span><span class="nf">open</span><span class="p">(</span><span class="no">EVENT_PIPE</span><span class="p">,</span> <span class="s2">"w+"</span><span class="p">)</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">sync</span> <span class="o">=</span> <span class="kp">true</span>
<span class="no">AfterConfiguration</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">puts</span><span class="p">({</span><span class="ss">event: </span><span class="s2">"started"</span><span class="p">,</span> <span class="ss">data: </span><span class="p">{}}.</span><span class="nf">to_json</span><span class="p">)</span>
<span class="n">config</span><span class="p">.</span><span class="nf">on_event</span> <span class="ss">:before_test_step</span> <span class="k">do</span> <span class="o">|</span><span class="n">event</span><span class="o">|</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">puts</span><span class="p">(</span>
<span class="p">{</span>
<span class="ss">event: </span><span class="s2">"before_test_step"</span><span class="p">,</span>
<span class="ss">data: </span><span class="p">{}</span>
<span class="p">}.</span><span class="nf">to_json</span>
<span class="p">)</span>
<span class="k">end</span>
<span class="n">config</span><span class="p">.</span><span class="nf">on_event</span> <span class="ss">:after_test_step</span> <span class="k">do</span> <span class="o">|</span><span class="n">event</span><span class="o">|</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">puts</span><span class="p">(</span>
<span class="p">{</span>
<span class="ss">event: </span><span class="s2">"after_test_step"</span><span class="p">,</span>
<span class="ss">data: </span><span class="p">{</span> <span class="ss">result: </span><span class="n">event</span><span class="p">.</span><span class="nf">result</span><span class="p">.</span><span class="nf">to_s</span> <span class="p">}</span>
<span class="p">}.</span><span class="nf">to_json</span>
<span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="nb">at_exit</span> <span class="p">{</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">puts</span><span class="p">({</span><span class="ss">event: </span><span class="s2">"done"</span><span class="p">,</span> <span class="ss">data: </span><span class="p">{}}.</span><span class="nf">to_json</span><span class="p">)</span>
<span class="n">publisher</span><span class="p">.</span><span class="nf">close</span>
<span class="p">}</span>
</code></pre>
<p>Now if you run Cucumber, with <code>subscriber.sh</code> up and running you should see something like:</p>
<pre><code class="highlight plaintext">$ ./subscriber.sh
{"event":"started","data":{}}
{"event":"before_test_step","data":{}}
{"event":"after_test_step","data":{"result":"✓"}}
{"event":"before_test_step","data":{}}
{"event":"after_test_step","data":{"result":"✓"}}
{"event":"before_test_step","data":{}}
{"event":"after_test_step","data":{"result":"✓"}}
{"event":"before_test_step","data":{}}
{"event":"after_test_step","data":{"result":"✗"}}
{"event":"before_test_step","data":{}}
{"event":"after_test_step","data":{"result":"-"}}
{"event":"done","data":{}}
</code></pre>
<h3>Hooking up a WebSocket</h3>
<p>Great! We’ve got Cucumber sending our events. We now want to get these events pushed into a web-page using a websocket.</p>
<p><code>websocketd</code> lets us hook our <code>subscriber.sh</code> command up to a websocket. Let’s have a look at what happens using <code>websocketd</code>’s <code>devconsole</code> mode:</p>
<pre><code class="highlight plaintext">$ websocketd --port=8080 --devconsole ./subscriber.sh
</code></pre>
<p>Then point your browser to [http://localhost:8080] and you should see:</p>
<p><img src="/images/websocketd-devconsole.png" /></p>
<p>Clicking the little “✔” in the top left will connect the <code>websocketd</code>’s dev console to the running socket. Now if you <code>echo</code> some text on to the named pipe, you will see it appear in the console on the web browser. Now running Cucumber again, you should see something like this in the web browser:</p>
<p><img src="/images/websocketd-devconsole-cuke.png" /></p>
<h3>WebSocket Cucumber</h3>
<p>Finishing everything up, lets create a simple web-page that uses the websocket to get information from Cucumber as it’s running. Save this as <code>index.html</code>:</p>
<pre><code class="highlight html"><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html></span>
<span class="nt"><head></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><h1></span>Cucumber Runner<span class="nt"></h1></span>
<span class="nt"><p</span> <span class="na">id=</span><span class="s">"status"</span><span class="nt">></span>disconnected<span class="nt"></p></span>
<span class="nt"><div</span> <span class="na">id=</span><span class="s">"runner"</span><span class="nt">></div></span>
<span class="nt"><script></span>
<span class="c1">// helper function: log message to screen</span>
<span class="kd">function</span> <span class="nx">stepStarted</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">runner</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"runner"</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">resultNode</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s2">"span"</span><span class="p">);</span>
<span class="nx">resultNode</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">"*"</span><span class="p">;</span>
<span class="nx">runner</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">resultNode</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">stepResult</span><span class="p">(</span><span class="nx">result</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">resultNode</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">"runner"</span><span class="p">).</span><span class="nx">lastElementChild</span><span class="p">;</span>
<span class="nx">resultNode</span><span class="p">.</span><span class="nx">textContent</span> <span class="o">=</span> <span class="nx">result</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">clearRunner</span><span class="p">()</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'runner'</span><span class="p">).</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="s2">""</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">statusWaiting</span><span class="p">()</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'status'</span><span class="p">).</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">"waiting"</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">statusRunning</span><span class="p">()</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'status'</span><span class="p">).</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">"running"</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">statusDisconnected</span><span class="p">()</span> <span class="p">{</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'status'</span><span class="p">).</span><span class="nx">textContent</span> <span class="o">=</span> <span class="s2">"disconnected"</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">done</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">statusWaiting</span><span class="p">();</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">CucumberSocket</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">ws</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">WebSocket</span><span class="p">(</span><span class="s1">'ws://localhost:8080/'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">callbacks</span> <span class="o">=</span> <span class="p">{};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">on</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">event_name</span><span class="p">,</span> <span class="nx">callback</span><span class="p">){</span>
<span class="nx">callbacks</span><span class="p">[</span><span class="nx">event_name</span><span class="p">]</span> <span class="o">=</span> <span class="nx">callback</span><span class="p">;</span>
<span class="k">return</span> <span class="k">this</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">dispatch</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">event_name</span><span class="p">,</span> <span class="nx">message</span><span class="p">){</span>
<span class="kd">var</span> <span class="nx">callback</span> <span class="o">=</span> <span class="nx">callbacks</span><span class="p">[</span><span class="nx">event_name</span><span class="p">];</span>
<span class="k">if</span><span class="p">(</span><span class="k">typeof</span> <span class="nx">callback</span> <span class="o">==</span> <span class="s1">'undefined'</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="nx">callback</span><span class="p">(</span><span class="nx">message</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">ws</span><span class="p">.</span><span class="nx">onmessage</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">event</span><span class="p">){</span>
<span class="kd">var</span> <span class="nx">json</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span>
<span class="nx">dispatch</span><span class="p">(</span><span class="nx">json</span><span class="p">.</span><span class="nx">event</span><span class="p">,</span> <span class="nx">json</span><span class="p">.</span><span class="nx">data</span><span class="p">)</span>
<span class="p">}</span>
<span class="nx">ws</span><span class="p">.</span><span class="nx">onclose</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span><span class="nx">dispatch</span><span class="p">(</span><span class="s1">'close'</span><span class="p">,</span><span class="kc">null</span><span class="p">)}</span>
<span class="nx">ws</span><span class="p">.</span><span class="nx">onopen</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span><span class="nx">dispatch</span><span class="p">(</span><span class="s1">'open'</span><span class="p">,</span><span class="kc">null</span><span class="p">)}</span>
<span class="p">};</span>
<span class="kd">var</span> <span class="nx">cucumber</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">CucumberSocket</span><span class="p">();</span>
<span class="nx">cucumber</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'open'</span><span class="p">,</span> <span class="nx">statusWaiting</span><span class="p">);</span>
<span class="nx">cucumber</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'close'</span><span class="p">,</span> <span class="nx">statusDisconnected</span><span class="p">);</span>
<span class="nx">cucumber</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'started'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">statusRunning</span><span class="p">();</span>
<span class="nx">clearRunner</span><span class="p">();</span>
<span class="p">});</span>
<span class="nx">cucumber</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'before_test_step'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">stepStarted</span><span class="p">();</span>
<span class="p">});</span>
<span class="nx">cucumber</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'after_test_step'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">stepResult</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">result</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">cucumber</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'done'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">statusWaiting</span><span class="p">();</span>
<span class="p">})</span>
<span class="nt"></script></span>
<span class="nt"></body></span>
<span class="nt"></html></span>
</code></pre>
<p>Using <code>websocketd</code>’s static site server we can get our little web page up and running: <code>websocketd --port=8080 --staticdir=. ./subscriber.sh</code> and open <a href="http://localhost:8080">http://localhost:8080</a>. Now running Cucumber should show you progress in the web page!</p>
<p><a href="https://www.youtube.com/watch?v=-pI5WzHfvjw"><img alt="Cucumber Websocket" src="/images/CucumberWebsocket.gif" /></a></p>
<h2>What events are available?</h2>
<p>Cucumber 2 introduced a new model for executing a set of features. Each scenario is now compiled into a suite of Test Cases, each made up of Test Steps. Test Steps include Before and After hooks. Cucumber fires the following 5 events based on that model.</p>
<ul>
<li><a href="http://www.rubydoc.info/gems/cucumber/Cucumber/Events/BeforeTestCase"><code>BeforeTestCase</code></a> – fired before a test case is executed</li>
<li><a href="http://www.rubydoc.info/gems/cucumber/Cucumber/Events/BeforeTestStep"><code>BeforeTestStep</code></a> – fired before a test step is executed</li>
<li><a href="http://www.rubydoc.info/gems/cucumber/Cucumber/Events/StepMatch"><code>StepMatch</code></a> – fired when a step is matched to a definition</li>
<li><a href="http://www.rubydoc.info/gems/cucumber/Cucumber/Events/AfterTestStep"><code>AfterTestStep</code></a> – fired after each test step has been executed</li>
<li><a href="http://www.rubydoc.info/gems/cucumber/Cucumber/Events/AfterTestCase"><code>AfterTestCase</code></a> – fired after a test case has finished executing</li>
</ul>
<h2>What can I use it for?</h2>
<p>The Events API is there for getting information out of Cucumber. It’s going to be the best way to write new formatters in future — the old formatter API will be removed in Cucumber 3.0. If you’re looking for a way to contribute to Cucumber then <a href="https://github.com/cucumber/cucumber-ruby/issues/839">rewriting some of the old formatters</a> to use the new events API would be a tremendous help.</p>
<p>Any questions please come and join us on our <a href="https://gitter.im/cucumber/chat">gitter channel</a> or the <a href="https://groups.google.com/forum/#!forum/cukes">mailing list</a>. All the code for this blog post is <a href="https://github.com/tooky/cucumber-events">available here</a>.</p>
Your tests want you to change your designhttp://tooky.co.uk/your-tests-want-you-to-change-your-design/2014-12-19T00:00:00+00:002014-12-19T11:59:48+00:00Steve Tooke<p>I came across an interesting post by <a href="https://twitter.com/brandonhilkert">Brandon Hilkert</a> looking at <a href="http://brandonhilkert.com/blog/a-ruby-refactor-exploring-dependency-injection-options/">the
differences between constructor and setter dependency injection</a>. It’s
a great introduction to the differences between the two, and his example
illustrates them well. Please go and read it first.</p>
<p>Brandon’s example gets started when he realises that the tests he wants to write
are difficult:</p>
<blockquote>
<p>[A] thing that bothered me was the difficulty simulating different pricing
tiers and customer usage…What if I wanted to change the ceiling of that
tier next month? I’d have to come in here and adjust the stats being created
until it totalled something above the adjustment. It just felt weird..</p>
</blockquote>
<p>He uses this as an example of how we can use dependency injection to use
different collaborators in tests so we get more control over the context our
objects are running in.</p>
<p>The solution he settles on is to use setter injection:</p>
<pre><code class="highlight ruby"><span class="k">module</span> <span class="nn">StripeEvent</span>
<span class="k">class</span> <span class="nc">InvoiceCreated</span>
<span class="kp">attr_writer</span> <span class="ss">:usage_service</span>
<span class="kp">attr_reader</span> <span class="ss">:payload</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="vi">@payload</span> <span class="o">=</span> <span class="n">payload</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">perform</span>
<span class="k">if</span> <span class="n">user</span><span class="p">.</span><span class="nf">created_at</span> <span class="o"><</span> <span class="mi">14</span><span class="p">.</span><span class="nf">days</span><span class="p">.</span><span class="nf">ago</span>
<span class="no">Stripe</span><span class="o">::</span><span class="no">InvoiceItem</span><span class="p">.</span><span class="nf">create</span><span class="p">(</span>
<span class="ss">customer: </span><span class="n">user</span><span class="p">.</span><span class="nf">stripe_id</span><span class="p">,</span>
<span class="ss">amount: </span><span class="n">additional_charges_in_cents</span><span class="p">,</span>
<span class="ss">currency: </span><span class="s2">"usd"</span><span class="p">,</span>
<span class="ss">description: </span><span class="s2">"Usage charges"</span>
<span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">additional_charges_in_cents</span>
<span class="no">Billing</span><span class="o">::</span><span class="no">Tier</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">usage</span><span class="p">).</span><span class="nf">additional_charges_in_cents</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">usage</span>
<span class="n">usage_service</span><span class="p">.</span><span class="nf">last_30_days</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">usage_service</span>
<span class="vi">@usage_service</span> <span class="o">||=</span> <span class="no">Billing</span><span class="o">::</span><span class="no">Usage</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">user</span>
<span class="vi">@user</span> <span class="o">||=</span> <span class="no">User</span><span class="p">.</span><span class="nf">find_by</span><span class="p">(</span><span class="ss">stripe_id: </span><span class="n">payload</span><span class="p">[</span><span class="s2">"data"</span><span class="p">][</span><span class="s2">"object"</span><span class="p">][</span><span class="s2">"customer"</span><span class="p">])</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>He’s now able to take an initialized object and using the <code>attr_writer
:usage_service</code> he can swap in a stub implementation of the usage service and
tightly control what is returned. It allows him to ignor the <em>incidental detail</em>
of creating a <code>Stat</code>.</p>
<p>When tests are difficult to write they are a great indicator that there’s
something about our design that we should take another look at. I’m not sure
that adding the setter method really changes the design, it just hides a little
complexity when writing our tests.</p>
<p>Here’s the sequence diagram for the original code:</p>
<p><img alt="original sequence" src="https://dl.dropboxusercontent.com/u/41915/tooky-images/listening_to_tests_1.png" /></p>
<p>Using the setter to inject a usage service shortcuts creating the usage service,
but is <em>only</em> relevant in the tests — in normal usage the design is
<em>exactly</em> the same.</p>
<p><img alt="setter sequence" src="https://dl.dropboxusercontent.com/u/41915/tooky-images/listening_to_tests_2.png" /></p>
<p>The tests were hinting that we had too many responsibilities, but this sequence
diagram really highlights this:</p>
<ul>
<li>Retrieve a user</li>
<li>Get the users usage for the last 30 days</li>
<li>Get the billing tier for that usage</li>
<li>Create an invoice item for the billing tier amount</li>
</ul>
<p>The last one is the most important. We want to create an additional invoice item
for the user, based on their usage in the last 30 days., and
sequence diagram looked something like:</p>
<p><img alt="extracted dependencies sequence" src="https://dl.dropboxusercontent.com/u/41915/tooky-images/listening_to_tests_3.png" /></p>
<p>Based on this idea I changed the tests to focus the object on the responsibility
we care about:</p>
<pre><code class="highlight ruby"><span class="n">describe</span> <span class="s2">"creating an invoice"</span> <span class="k">do</span>
<span class="n">before</span> <span class="k">do</span>
<span class="vi">@payload</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">"data"</span> <span class="o">=></span> <span class="p">{</span>
<span class="s2">"object"</span> <span class="o">=></span> <span class="p">{</span>
<span class="s2">"customer"</span> <span class="o">=></span> <span class="s2">"stripe_brandon"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">end</span>
<span class="n">let</span><span class="p">(</span><span class="ss">:billing_tier_service</span><span class="p">)</span> <span class="p">{</span> <span class="n">double</span><span class="p">(</span><span class="ss">:billing_tier_service</span><span class="p">)</span> <span class="p">}</span>
<span class="n">let</span><span class="p">(</span><span class="ss">:level1</span><span class="p">)</span> <span class="p">{</span> <span class="n">double</span><span class="p">(</span><span class="ss">:tier</span><span class="p">,</span> <span class="ss">:additional_charges_in_cents</span> <span class="o">=></span> <span class="mi">1900</span><span class="p">)</span> <span class="p">}</span>
<span class="n">let</span><span class="p">(</span><span class="ss">:level2</span><span class="p">)</span> <span class="p">{</span> <span class="n">double</span><span class="p">(</span><span class="ss">:tier</span><span class="p">,</span> <span class="ss">:additional_charges_in_cents</span> <span class="o">=></span> <span class="mi">4900</span><span class="p">)</span> <span class="p">}</span>
<span class="n">it</span> <span class="s1">'adds invoice item based on usage'</span> <span class="k">do</span>
<span class="n">allow</span><span class="p">(</span><span class="n">billing_tier_service</span><span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:last_30_days_for_stripe_id</span><span class="p">).</span>
<span class="nf">with</span><span class="p">(</span><span class="s2">"stripe_brandon"</span><span class="p">).</span><span class="nf">and_return</span><span class="p">(</span><span class="n">level1</span><span class="p">)</span>
<span class="n">expect</span><span class="p">(</span> <span class="no">Stripe</span><span class="o">::</span><span class="no">InvoiceItem</span> <span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:create</span><span class="p">).</span><span class="nf">with</span><span class="p">(</span>
<span class="ss">customer: </span><span class="s2">"stripe_brandon"</span><span class="p">,</span>
<span class="ss">amount: </span><span class="mi">1900</span><span class="p">,</span>
<span class="ss">currency: </span><span class="s2">"usd"</span><span class="p">,</span>
<span class="ss">description: </span><span class="s2">"Usage charges"</span>
<span class="p">)</span>
<span class="no">StripeEvent</span><span class="o">::</span><span class="no">InvoiceCreated</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="vi">@payload</span><span class="p">,</span> <span class="n">billing_tier_service</span><span class="p">).</span><span class="nf">perform</span>
<span class="k">end</span>
<span class="n">it</span> <span class="s1">'adds next level charge for usage'</span> <span class="k">do</span>
<span class="n">allow</span><span class="p">(</span><span class="n">billing_tier_service</span><span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:last_30_days_for_stripe_id</span><span class="p">)</span>
<span class="p">.</span><span class="nf">with</span><span class="p">(</span><span class="s2">"stripe_brandon"</span><span class="p">).</span><span class="nf">and_return</span><span class="p">(</span><span class="n">level2</span><span class="p">)</span>
<span class="n">expect</span><span class="p">(</span> <span class="no">Stripe</span><span class="o">::</span><span class="no">InvoiceItem</span> <span class="p">).</span><span class="nf">to</span> <span class="n">receive</span><span class="p">(</span><span class="ss">:create</span><span class="p">).</span><span class="nf">with</span><span class="p">(</span>
<span class="ss">customer: </span><span class="s2">"stripe_brandon"</span><span class="p">,</span>
<span class="ss">amount: </span><span class="mi">4900</span><span class="p">,</span>
<span class="ss">currency: </span><span class="s2">"usd"</span><span class="p">,</span>
<span class="ss">description: </span><span class="s2">"Usage charges"</span>
<span class="p">)</span>
<span class="no">StripeEvent</span><span class="o">::</span><span class="no">InvoiceCreated</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="vi">@payload</span><span class="p">,</span> <span class="n">billing_tier_service</span><span class="p">).</span><span class="nf">perform</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>We are injecting a new dependency, a <code>billing_tier_service</code>. We’re imagining
that this dependency will take on the responsibility of giving us back the
correct billing tier for the customer that stripe has asked us for. Our tests
will just check we creating the InvoiceItem correctly, and the resulting code
is little simpler.</p>
<pre><code class="highlight ruby"><span class="k">module</span> <span class="nn">StripeEvent</span>
<span class="k">class</span> <span class="nc">InvoiceCreated</span>
<span class="kp">attr_reader</span> <span class="ss">:payload</span>
<span class="kp">attr_reader</span> <span class="ss">:billing_tier_service</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">billing_tier_service</span> <span class="o">=</span> <span class="ss">:some_sensible_default</span><span class="p">)</span>
<span class="vi">@payload</span> <span class="o">=</span> <span class="n">payload</span>
<span class="vi">@billing_tier_service</span> <span class="o">=</span> <span class="n">billing_tier_service</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">perform</span>
<span class="no">Stripe</span><span class="o">::</span><span class="no">InvoiceItem</span><span class="p">.</span><span class="nf">create</span><span class="p">(</span>
<span class="ss">customer: </span><span class="n">stripe_id</span><span class="p">,</span>
<span class="ss">amount: </span><span class="n">additional_charges_in_cents</span><span class="p">,</span>
<span class="ss">currency: </span><span class="s2">"usd"</span><span class="p">,</span>
<span class="ss">description: </span><span class="s2">"Usage charges"</span>
<span class="p">)</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">additional_charges_in_cents</span>
<span class="n">tier</span> <span class="o">=</span> <span class="n">billing_tier_service</span><span class="p">.</span><span class="nf">last_30_days_for_stripe_id</span><span class="p">(</span><span class="n">stripe_id</span><span class="p">)</span>
<span class="n">tier</span><span class="p">.</span><span class="nf">additional_charges_in_cents</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">stripe_id</span>
<span class="n">payload</span><span class="p">[</span><span class="s2">"data"</span><span class="p">][</span><span class="s2">"object"</span><span class="p">][</span><span class="s2">"customer"</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Obviously this leaves us with more work to do. We will still need to build the
<code>billing_tier_service</code>, to return the current tier for the customer. But this
should be simpler, and focus purely on which level is returned based on usage.</p>
<p>The trade-off is that we now have to deal with more objects in our system, but
each responsibility is in a single place, and our tests are isolated from
incidental changes in other parts of the system, e.g. changing the tier pricing.</p>
<p>Test driven development is about listening to your tests. When something is hard
to test it’s usually a good indicator that you should change something in your
design. Use it as an opportunity to reevaluate design — and don’t be
afraid of breaking out some boxes and arrows on the whiteboard.</p>
Test first diamondshttp://tooky.co.uk/test-first-diamonds/2014-12-06T00:00:00+00:002014-12-06T21:55:05+00:00Steve Tooke<p><a href="https://twitter.com/sebrose">Seb</a>’s recent post <a href="http://claysnow.co.uk/recycling-tests-in-tdd/">Recycling tests in TDD</a> introduced the
“Print Diamond” kata. This has provoked a flurry of interesting posts looking at
different approaches to solving it.</p>
<pre><code class="highlight plaintext">Given a letter, print a diamond starting with 'A' with the supplied letter at the widest point.
For example: print-diamond 'C' prints
A
B B
C C
B B
A
</code></pre>
<p><em>Thinking</em> has been the theme that has dominated the posts others have published
while trying out this kata. <a href="http://alistair.cockburn.us/Thinking+before+programming">Alistair Cockburn</a> began by suggesting
that this kind of problem is ideal for thinking about the properties of the
problem, and then deriving the code as an exercise - although his approach is to
use tests to get him there. <a href="http://ronjeffries.com/articles/diamond/diamond.html">Ron Jeffries</a> and <a href="http://blog.gdinwiddie.com/2014/11/30/another-approach-to-the-diamond-kata/">George Dinwiddie</a>
both take an incremental TDD approach, although both are different.</p>
<p>Luckily I’d had a go at this kata before reading any of the other posts. I say
lucky because I think having read all of the other posts I’d probably have done
something else. </p>
<p>Ron and George both talk about thinking during their approach. I stepped through
printing ‘A’, then 'B’ and 'C’ without really thinking about the algorithm at
all. My first test looked like:</p>
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">TestPrintDiamond</span> <span class="o"><</span> <span class="no">MiniTest</span><span class="o">::</span><span class="no">Unit</span><span class="o">::</span><span class="no">TestCase</span>
<span class="kp">include</span> <span class="no">PrintDiamond</span>
<span class="k">def</span> <span class="nf">test_print_a</span>
<span class="n">assert_equal</span> <span class="s1">'A'</span><span class="p">,</span> <span class="n">print_diamond</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I just took the easy way to make it pass:</p>
<pre><code class="highlight ruby"><span class="k">module</span> <span class="nn">PrintDiamond</span>
<span class="k">def</span> <span class="nf">print_diamond</span>
<span class="s1">'A'</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I’m not sure why I decided the interface would be a module that I mixed in, but
I think that’s incidental.</p>
<p>My second and third tests followed a similar pattern, I’m going to put them both
here because there’s nothing interesting about them.</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">test_print_b</span>
<span class="n">expected</span> <span class="o">=</span> <span class="p">[</span>
<span class="s1">' A '</span><span class="p">,</span>
<span class="s1">'B B'</span><span class="p">,</span>
<span class="s1">' A '</span><span class="p">,</span>
<span class="p">].</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="n">assert_equal</span> <span class="n">expected</span><span class="p">,</span> <span class="n">print_diamond</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">test_print_c</span>
<span class="n">expected</span> <span class="o">=</span> <span class="p">[</span>
<span class="s1">' A '</span><span class="p">,</span>
<span class="s1">' B B '</span><span class="p">,</span>
<span class="s1">'C C'</span><span class="p">,</span>
<span class="s1">' B B '</span><span class="p">,</span>
<span class="s1">' A '</span><span class="p">,</span>
<span class="p">].</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="n">assert_equal</span> <span class="n">expected</span><span class="p">,</span> <span class="n">print_diamond</span><span class="p">(</span><span class="s1">'C'</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>I kept going with hard coding the answers, so the implementation for this was
pretty simple too.</p>
<pre><code class="highlight ruby"><span class="k">module</span> <span class="nn">PrintDiamond</span>
<span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span> <span class="s1">'A'</span> <span class="p">]</span>
<span class="k">elsif</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'B'</span>
<span class="p">[</span> <span class="s1">' A '</span><span class="p">,</span> <span class="s1">'B B'</span><span class="p">,</span> <span class="s1">' A '</span> <span class="p">]</span>
<span class="k">else</span>
<span class="p">[</span> <span class="s1">' A '</span><span class="p">,</span> <span class="s1">' B B '</span><span class="p">,</span> <span class="s1">'C C'</span><span class="p">,</span> <span class="s1">' B B '</span><span class="p">,</span> <span class="s1">' A '</span> <span class="p">]</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>So now I had tests that passed, but an implementation that wasn’t going to
scale. This is the point that Seb mentions in his post that we can see the code
is screaming for us to refactor. Seb points out that this is difficult, because
there is so much going on at this point that it’s hard to know where to start.</p>
<p>Thanks to <a href="https://twitter.com/sandimetz">Sandi Metz</a> I’ve been trying recently to make lots of very
small refactorings. This is a great example of code that doesn’t quite look the
same, but definitely has a pattern. Rather than going straight for trying to fix
the problem, I wanted to expose the pattern. I want to extract the differences
so I can more clearly see where the lines are the same.</p>
<p>I decided I wanted to focus on the “middle” of each row - the letters and the
spacing between them.</p>
<p>I wrote a method that I thought would give me what I wanted:</p>
<pre><code class="highlight ruby"><span class="no">ALPHABET</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="s1">'Z'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">print_line</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="n">letter</span>
<span class="k">else</span>
<span class="p">[</span><span class="n">letter</span><span class="p">,</span> <span class="s1">' '</span> <span class="o">*</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">letter</span><span class="p">),</span> <span class="n">letter</span><span class="p">].</span><span class="nf">join</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I had a hunch that the spacing between the letters was the equivalent to the
index of that letter in the alphabet. There’s a special case for 'A’ as it’s the
only character that’s printed once, but I figured I would leave that for later.</p>
<p>I then tried using this method in a single place:</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span><span class="n">print_line</span><span class="p">(</span><span class="n">letter</span><span class="p">)]</span>
<span class="k">elsif</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'B'</span>
<span class="p">[</span><span class="s1">' A '</span><span class="p">,</span> <span class="s1">'B B'</span><span class="p">,</span> <span class="s1">' A '</span><span class="p">]</span>
<span class="k">else</span>
<span class="p">[</span><span class="s1">' A '</span><span class="p">,</span> <span class="s1">' B B '</span><span class="p">,</span> <span class="s1">'C C'</span><span class="p">,</span> <span class="s1">' B B '</span><span class="p">,</span> <span class="s1">' A '</span><span class="p">]</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>So I extended using it for each of the central rows - the rows that had no extra
spaces on the ends.</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span><span class="n">print_line</span><span class="p">(</span><span class="n">letter</span><span class="p">)]</span>
<span class="k">elsif</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'B'</span>
<span class="p">[</span><span class="s1">' A '</span><span class="p">,</span> <span class="n">print_line</span><span class="p">(</span><span class="n">letter</span><span class="p">),</span> <span class="s1">' A '</span><span class="p">]</span>
<span class="k">else</span>
<span class="p">[</span><span class="s1">' A '</span><span class="p">,</span> <span class="s1">' B B '</span><span class="p">,</span> <span class="n">print_line</span><span class="p">(</span><span class="n">letter</span><span class="p">),</span> <span class="s1">' B B '</span><span class="p">,</span> <span class="s1">' A '</span><span class="p">]</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>Oh a test failed! My hunch was wrong about the internal padding, or I’d
miss-counted. 'C’ has 3 spaces between it, and yes the pattern is that the
internal padding is always an odd number.</p>
<pre><code class="highlight ruby"> <span class="k">def</span> <span class="nf">print_line</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="n">letter</span>
<span class="k">else</span>
<span class="n">internal_padding</span> <span class="o">=</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">-</span> <span class="mi">1</span>
<span class="p">[</span><span class="n">letter</span><span class="p">,</span> <span class="s1">' '</span> <span class="o">*</span> <span class="n">internal_padding</span><span class="p">,</span> <span class="n">letter</span><span class="p">].</span><span class="nf">join</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Back to green. Now I was confident that this would work for all the other cases,
so I pushed on and used it throughout, and renamed the method to pad_inside.</p>
<pre><code class="highlight ruby"><span class="k">module</span> <span class="nn">PrintDiamond</span>
<span class="no">ALPHABET</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="s1">'Z'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span><span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">)]</span>
<span class="k">elsif</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'B'</span>
<span class="p">[</span><span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">,</span>
<span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">),</span>
<span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">]</span>
<span class="k">else</span>
<span class="p">[</span><span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">,</span>
<span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">,</span>
<span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">),</span>
<span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">,</span>
<span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">]</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="n">letter</span>
<span class="k">else</span>
<span class="n">internal_padding</span> <span class="o">=</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">-</span> <span class="mi">1</span>
<span class="p">[</span><span class="n">letter</span><span class="p">,</span> <span class="s1">' '</span> <span class="o">*</span> <span class="n">internal_padding</span><span class="p">,</span> <span class="n">letter</span><span class="p">].</span><span class="nf">join</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>The next thing to tackle is the external padding. Again I started by writing the
code I thought might handle it:</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">pad_out</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">mid_letter</span><span class="p">,</span> <span class="n">thing</span><span class="p">)</span>
<span class="n">padding</span> <span class="o">=</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">mid_letter</span><span class="p">)</span> <span class="o">-</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="p">[</span><span class="s1">' '</span> <span class="o">*</span> <span class="n">padding</span><span class="p">,</span> <span class="n">thing</span><span class="p">,</span> <span class="s1">' '</span> <span class="o">*</span> <span class="n">padding</span><span class="p">]</span>
<span class="k">end</span>
</code></pre>
<p>Another hunch. The central row was never padded, and each other row the padding
increased by one. My simple finger-counting maths seemed to think this would
work. Let’s try it in one place and see how it goes:</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span><span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">)]</span>
<span class="k">elsif</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'B'</span>
<span class="p">[</span><span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">,</span>
<span class="n">pad_out</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">)),</span>
<span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">]</span>
<span class="k">else</span>
<span class="p">[</span><span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">,</span>
<span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">,</span>
<span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">),</span>
<span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">,</span>
<span class="s2">" </span><span class="si">#{</span><span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)</span><span class="si">}</span><span class="s2"> "</span><span class="p">]</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>Ok - something failed there… Ahh, I’m returning an array, not the string
I need.</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">pad_out</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">mid_letter</span><span class="p">,</span> <span class="n">thing</span><span class="p">)</span>
<span class="n">padding</span> <span class="o">=</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">mid_letter</span><span class="p">)</span> <span class="o">-</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="p">[</span><span class="s1">' '</span> <span class="o">*</span> <span class="n">padding</span><span class="p">,</span> <span class="n">thing</span><span class="p">,</span> <span class="s1">' '</span> <span class="o">*</span> <span class="n">padding</span><span class="p">]</span>
<span class="k">end</span>
</code></pre>
<p>I can now work through using this method throughout:</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span><span class="n">pad_out</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">))]</span>
<span class="k">elsif</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'B'</span>
<span class="p">[</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="p">]</span>
<span class="k">else</span>
<span class="p">[</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'B'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'B'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="p">]</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>Great - that works. I want to make a small refactoring to make all of the lines
look the same. The central line that uses <code>letter</code> on each conditional is
perhaps masking the pattern a bit.</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span><span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">))]</span>
<span class="k">elsif</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'B'</span>
<span class="p">[</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'B'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="p">]</span>
<span class="k">else</span>
<span class="p">[</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'B'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'C'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'C'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'B'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="p">]</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>So, now I want to remove the duplication inside one of the legs. I need some way
of stepping through from <code>A</code> to the target letter, and then back to <code>A</code>.</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span><span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">))]</span>
<span class="k">elsif</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'B'</span>
<span class="n">rows</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="n">letter</span><span class="p">)</span> <span class="o">+</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="p">.</span><span class="nf">letter</span><span class="p">).</span><span class="nf">reverse</span>
<span class="n">rows</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">row_letter</span><span class="o">|</span> <span class="n">pad_out</span><span class="p">(</span><span class="n">row_letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">row_letter</span><span class="p">))</span> <span class="p">}</span>
<span class="p">[</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'B'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="p">]</span>
<span class="k">else</span>
<span class="p">[</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'B'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'C'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'C'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'B'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="p">]</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>There’s another hunch! It’s a bit tricky because it uses the difference between
the ruby <code>..</code> range operator, and the <code>...</code> operator — using <code>..</code> means up
to and including, and <code>...</code> means up to but not including. Let’s see if it works
— I’ll just remove the old code for <code>B</code>.</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span><span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">))]</span>
<span class="k">elsif</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'B'</span>
<span class="n">rows</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="n">letter</span><span class="p">)</span> <span class="o">+</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="p">.</span><span class="nf">letter</span><span class="p">).</span><span class="nf">reverse</span>
<span class="n">rows</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">row_letter</span><span class="o">|</span> <span class="n">pad_out</span><span class="p">(</span><span class="n">row_letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">row_letter</span><span class="p">))</span> <span class="p">}</span>
<span class="k">else</span>
<span class="p">[</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'B'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'C'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'C'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'B'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'B'</span><span class="p">)),</span>
<span class="n">pad_out</span><span class="p">(</span><span class="s1">'A'</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="s1">'A'</span><span class="p">)),</span>
<span class="p">]</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>Great, so I can try the same for the <code>C</code> branch.</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span><span class="n">pad_out</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">))]</span>
<span class="k">elsif</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'B'</span>
<span class="n">rows</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="n">letter</span><span class="p">)</span> <span class="o">+</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="p">.</span><span class="nf">letter</span><span class="p">).</span><span class="nf">reverse</span>
<span class="n">rows</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">row_letter</span><span class="o">|</span> <span class="n">pad_out</span><span class="p">(</span><span class="n">row_letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">row_letter</span><span class="p">))</span> <span class="p">}</span>
<span class="k">else</span>
<span class="n">rows</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="n">letter</span><span class="p">)</span> <span class="o">+</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="p">.</span><span class="nf">letter</span><span class="p">).</span><span class="nf">reverse</span>
<span class="n">rows</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">row_letter</span><span class="o">|</span> <span class="n">pad_out</span><span class="p">(</span><span class="n">row_letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">row_letter</span><span class="p">))</span> <span class="p">}</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>Success! Time to remove the duplication and lose the <code>B</code> branch.</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="p">[</span><span class="n">pad_out</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">))]</span>
<span class="k">else</span>
<span class="n">rows</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="n">letter</span><span class="p">)</span> <span class="o">+</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="p">.</span><span class="nf">letter</span><span class="p">).</span><span class="nf">reverse</span>
<span class="n">rows</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">row_letter</span><span class="o">|</span> <span class="n">pad_out</span><span class="p">(</span><span class="n">row_letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">row_letter</span><span class="p">))</span> <span class="p">}</span>
<span class="k">end</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>Still works - so I’m confident it will work for the <code>A</code> branch too, so I’ll
remove the conditional altogether.</p>
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="n">rows</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="n">letter</span><span class="p">)</span> <span class="o">+</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="p">.</span><span class="nf">letter</span><span class="p">).</span><span class="nf">reverse</span>
<span class="n">rows</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">row_letter</span><span class="o">|</span> <span class="n">pad_out</span><span class="p">(</span><span class="n">row_letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">row_letter</span><span class="p">))</span> <span class="p">}.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>I think this is a good point to talk about how this approach has differed from
the others. Like some of the other solutions I didn’t do very up front thinking,
but I didn’t really break the problem down. I just started to write code —
I think Sandi Metz would call it <a href="http://pawelduda.blogspot.co.uk/2014/06/practical-object-oriented-design-in.html">shameless</a> — and then looked
for patterns.</p>
<p>One of Sandi’s key points from her OOD training is that it helps to look for
simliar code, and extract the differences. This lets you make code that is
nearly the same, actually be the same, and then you can tackle the duplication.</p>
<p>By this point I’d pretty much sketched out the algorithm. Its still not
particularly nice, but it works and there’s something to work with.</p>
<pre><code class="highlight ruby"><span class="k">module</span> <span class="nn">PrintDiamond</span>
<span class="no">ALPHABET</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="s1">'Z'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="n">rows</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="n">letter</span><span class="p">)</span> <span class="o">+</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="p">.</span><span class="nf">letter</span><span class="p">).</span><span class="nf">reverse</span>
<span class="n">rows</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">row_letter</span><span class="o">|</span> <span class="n">pad_out</span><span class="p">(</span><span class="n">row_letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">,</span> <span class="n">pad_inside</span><span class="p">(</span><span class="n">row_letter</span><span class="p">))</span> <span class="p">}.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">pad_inside</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">if</span> <span class="n">letter</span> <span class="o">==</span> <span class="s1">'A'</span>
<span class="n">letter</span>
<span class="k">else</span>
<span class="n">internal_padding</span> <span class="o">=</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">-</span> <span class="mi">1</span>
<span class="p">[</span><span class="n">letter</span><span class="p">,</span> <span class="s1">' '</span> <span class="o">*</span> <span class="n">internal_padding</span><span class="p">,</span> <span class="n">letter</span><span class="p">].</span><span class="nf">join</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">pad_out</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">mid_letter</span><span class="p">,</span> <span class="n">thing</span><span class="p">)</span>
<span class="n">padding</span> <span class="o">=</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">mid_letter</span><span class="p">)</span> <span class="o">-</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="p">[</span><span class="s1">' '</span> <span class="o">*</span> <span class="n">padding</span><span class="p">,</span> <span class="n">thing</span><span class="p">,</span> <span class="s1">' '</span> <span class="o">*</span> <span class="n">padding</span><span class="p">].</span><span class="nf">join</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I’m concerned about that <code>if letter == 'A'</code>, and I definitely sense there’s an
object or two waiting to leap out! I won’t bore you with the step-by-step
<a href="https://github.com/tooky/print-diamond/tree/refactoring">refactorings</a>, as this post is already pretty long. This was where
I stopped though:</p>
<pre><code class="highlight ruby"><span class="k">module</span> <span class="nn">PrintDiamond</span>
<span class="no">ALPHABET</span> <span class="o">=</span> <span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="s1">'Z'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">print_diamond</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="no">Diamond</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">letter</span><span class="p">).</span><span class="nf">to_s</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Diamond</span>
<span class="kp">attr_reader</span> <span class="ss">:letter</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="vi">@letter</span> <span class="o">=</span> <span class="n">letter</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">to_s</span>
<span class="n">rows</span><span class="p">.</span><span class="nf">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">row_letter</span><span class="o">|</span> <span class="no">PaddedRow</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">row_letter</span><span class="p">,</span> <span class="n">letter</span><span class="p">)</span> <span class="p">}.</span><span class="nf">join</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">rows</span>
<span class="n">top</span> <span class="o">+</span> <span class="n">bottom</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">top</span>
<span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="n">letter</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">bottom</span>
<span class="no">Array</span><span class="p">(</span><span class="s1">'A'</span><span class="p">.</span><span class="nf">.</span><span class="p">.</span><span class="nf">letter</span><span class="p">).</span><span class="nf">reverse</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Row</span>
<span class="kp">attr_reader</span> <span class="ss">:letter</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="vi">@letter</span> <span class="o">=</span> <span class="n">letter</span>
<span class="n">create_chars</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">to_s</span>
<span class="vi">@chars</span><span class="p">.</span><span class="nf">join</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">row_size</span>
<span class="c1"># 0 -> 1, 1 -> 3, 3 -> 7, ...</span>
<span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">create_chars</span>
<span class="vi">@chars</span> <span class="o">=</span> <span class="no">Array</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">row_size</span><span class="p">)</span> <span class="p">{</span> <span class="s1">' '</span> <span class="p">}</span>
<span class="vi">@chars</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">letter</span>
<span class="vi">@chars</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">letter</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">PaddedRow</span>
<span class="kp">attr_reader</span> <span class="ss">:diamond_letter</span><span class="p">,</span> <span class="ss">:row</span><span class="p">,</span> <span class="ss">:letter</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">letter</span><span class="p">,</span> <span class="n">diamond_letter</span><span class="p">)</span>
<span class="vi">@row</span> <span class="o">=</span> <span class="no">Row</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="vi">@letter</span> <span class="o">=</span> <span class="n">letter</span>
<span class="vi">@diamond_letter</span> <span class="o">=</span> <span class="n">diamond_letter</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">to_s</span>
<span class="p">[</span><span class="n">padding</span><span class="p">,</span> <span class="n">row</span><span class="p">,</span> <span class="n">padding</span><span class="p">].</span><span class="nf">join</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">padding</span>
<span class="s1">' '</span> <span class="o">*</span> <span class="n">padding_size</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">padding_size</span>
<span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">diamond_letter</span><span class="p">)</span> <span class="o">-</span> <span class="no">ALPHABET</span><span class="p">.</span><span class="nf">index</span><span class="p">(</span><span class="n">letter</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>I won’t claim this as an example of TDD. I think this is what <a href="http://www.jbrains.ca/permalink/how-test-driven-development-works-and-more">J. B.
Rainsberger</a> would call test-first development. The tests were written
first, but they didn’t influence the design particularly. I think it is an
example of evolutionary design, and how having tests enables the refactoring
that allows a design to emerge.</p>
Connascence and Inverting Dependencieshttp://tooky.co.uk/connascence-and-inverting-dependencies/2014-11-07T00:00:00+00:002014-11-07T07:52:18+00:00Steve Tooke<p>Recently <a href="http://twitter.com/abernardes">Andre Bernardes</a> <a href="http://abernardes.github.io/2014/11/04/inverting-dependencies.html">wrote about inverting
dependencies</a> and a refactoring that he made in the <a href="http://rom-rb.org">Ruby Object
Mapper</a> codebase.</p>
<p>It’s a great article and if you haven’t read it yet it won’t take you long.
Go on, I can wait.</p>
<p>The original code, however, doesn’t simply provide a great example of code that
violates the <a href="http://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion Principle</a>. Let’s take a closer look and
see what else we can find.</p>
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">Adapter</span>
<span class="p">.</span><span class="nf">.</span><span class="p">.</span>
<span class="nf">def</span> <span class="nb">self</span><span class="p">.</span><span class="nf">setup</span><span class="p">(</span><span class="n">uri_string</span><span class="p">)</span>
<span class="n">uri</span> <span class="o">=</span> <span class="no">Addressable</span><span class="o">::</span><span class="no">URI</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">uri_string</span><span class="p">)</span>
<span class="n">adapter</span> <span class="o">=</span>
<span class="k">case</span> <span class="n">uri</span><span class="p">.</span><span class="nf">scheme</span>
<span class="k">when</span> <span class="s1">'sqlite'</span><span class="p">,</span> <span class="s1">'jdbc'</span> <span class="k">then</span> <span class="no">Adapter</span><span class="o">::</span><span class="no">Sequel</span>
<span class="k">when</span> <span class="s1">'memory'</span> <span class="k">then</span> <span class="no">Adapter</span><span class="o">::</span><span class="no">Memory</span>
<span class="k">when</span> <span class="s1">'mongo'</span> <span class="k">then</span> <span class="no">Adapter</span><span class="o">::</span><span class="no">Mongo</span>
<span class="k">else</span>
<span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">,</span> <span class="s2">"</span><span class="si">#{</span><span class="n">uri_string</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2"> uri is not supported"</span>
<span class="k">end</span>
<span class="n">adapter</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
<span class="k">end</span>
<span class="p">.</span><span class="nf">.</span><span class="p">.</span>
<span class="nf">end</span>
</code></pre>
<p>In 2010 I saw Jim Weirich speak about the <a href="http://vimeo.com/10837903">Grand Unified Theory of Software
Development</a> (this is the version from Aloha on Rails) where he introduced
his audience to the idea of <a href="http://en.wikipedia.org/wiki/Connascence_(computer_programming)">Connascence</a>.</p>
<blockquote>
<p>In software engineering, two components are connascent if a change in one
would require the other to be modified in order to maintain the overall
correctness of the system.</p>
</blockquote>
<p>Let’s look again at the <code>Adapter</code> code through the lens of connascence.</p>
<p>The <code>setup</code> method is checking the scheme of the <code>uri</code> and deciding which
specific adapter to use in this instance. This is an example of <a href="http://en.wikipedia.org/wiki/Connascence_(computer_programming)#Connascence_of_Meaning_.28CoM.29">Connascence of
Meaning</a>.</p>
<p>As Andre pointed out in his post, adding a new adapter also means changing this
method. If an <code>Adapter</code> is changed to handle different schemes, then this method
will also need to change. They must change together because they share the
meaning of the URI scheme.</p>
<p>The refactoring that Andre has implemented doesn’t rid us of Connascence of
Meaning but it reduces the <em>Degree</em> and increases the <em>Locality</em> of the
connascence.</p>
<p>When we are looking at connascence and deciding whether any particular instance
of connascence is acceptable, there are two concepts that we need to consider.</p>
<p>The degree of connascence is really about the volume of connascence, how much of
it we can see. Andre mentions in his post that the example presented above is
not terrible, but when he was about to add 19 more branches to the case
statement it would have become much worse. The degree of connascence would have
increased, and would only have continued increasing.</p>
<p>The locality of connascence is concerned with how closely related the elements
are. Stronger forms of connascence are considered to be more acceptable when the
elements involved are closer together. In the original <code>setup</code> method the
connascence of meaning ties the <code>Adapter</code> class to the specific adapters.</p>
<p>Let’s take a look at Andre’s refactoring.</p>
<pre><code class="highlight ruby"><span class="c1"># adapter.rb</span>
<span class="k">class</span> <span class="nc">Adapter</span>
<span class="vi">@adapters</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">setup</span><span class="p">(</span><span class="n">uri_string</span><span class="p">)</span>
<span class="n">uri</span> <span class="o">=</span> <span class="no">Addressable</span><span class="o">::</span><span class="no">URI</span><span class="p">.</span><span class="nf">parse</span><span class="p">(</span><span class="n">uri_string</span><span class="p">)</span>
<span class="k">unless</span> <span class="n">adapter</span> <span class="o">=</span> <span class="nb">self</span><span class="p">[</span><span class="n">uri</span><span class="p">.</span><span class="nf">scheme</span><span class="p">]</span>
<span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">,</span> <span class="s2">"</span><span class="si">#{</span><span class="n">uri_string</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2"> uri is not supported"</span>
<span class="k">end</span>
<span class="n">adapter</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">register</span><span class="p">(</span><span class="n">adapter</span><span class="p">)</span>
<span class="vi">@adapters</span> <span class="o"><<</span> <span class="n">adapter</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">[]</span><span class="p">(</span><span class="n">scheme</span><span class="p">)</span>
<span class="vi">@adapters</span><span class="p">.</span><span class="nf">detect</span> <span class="p">{</span> <span class="o">|</span><span class="n">adapter</span><span class="o">|</span> <span class="n">adapter</span><span class="p">.</span><span class="nf">schemes</span><span class="p">.</span><span class="nf">include?</span><span class="p">(</span><span class="n">scheme</span><span class="p">.</span><span class="nf">to_sym</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># adapter/memory.rb</span>
<span class="k">class</span> <span class="nc">Adapter</span>
<span class="k">class</span> <span class="nc">Memory</span>
<span class="k">def</span> <span class="nf">schemes</span>
<span class="p">[</span><span class="ss">:memory</span><span class="p">]</span>
<span class="k">end</span>
<span class="c1"># Methods to communicate with DB omitted.</span>
<span class="no">Adapter</span><span class="p">.</span><span class="nf">register</span><span class="p">(</span><span class="nb">self</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Adapter</span><span class="p">.</span><span class="nf">setup</span><span class="p">(</span><span class="s2">"memory://test"</span><span class="p">).</span><span class="nf">class</span>
<span class="c1"># => Adapter::Memory</span>
</code></pre>
<p>We still have Connascence of Meaning, but it is now isolated inside the
individual adapter class, an adapter will change if the URI scheme it supports
changes. The <em>locality</em> of connascence has been increased.</p>
<p>Each specific adapter will only have a small number of schemes that it matches,
rather than all of them. The <em>degree</em> of connascence has been reduced.</p>
<p>By increasing the locality and reducing the degree of connascence, Andre has
made the connascence of meaning more acceptable. The connascence of meaning
resulted in the <code>Adapter</code> abstraction depending on the details of the specific
adapters.</p>
<p>It also prevented the <code>Adapter</code> from being <em>Closed for Modification</em>. Any time
we add a new adapter we need to change the <code>Adapter</code> class to add another
branch to the switch statement. It violated the <a href="http://en.wikipedia.org/wiki/Open/closed_principle">Open/Closed Principle</a>.</p>
<p>Andre’s refactoring reduced the degree and increased the locality of connascence
of meaning. This makes the code adhere more closely to both the Single
Responsibility Principle and the Open/Closed Principle.</p>
<p>I think this is a good example of what <a href="http://twitter.com/kevinrutherford">Kevin Rutherford</a> hints at in
<a href="http://silkandspinach.net/2012/09/03/the-problem-with-code-smells/">The problem with code smells</a>. By finding where our code is
more connascent — having the stronger forms of connascence, having a high
degree of connascence, or having low locality of connascence — and making
the connascence more acceptable, we will improve the design of our software.</p>
Next Kickstart Academy Podcast Show with Liz Keogh and Chris Mattshttp://tooky.co.uk/next-kickstart-academy-podcast-show-with-liz-keogh-and-chris-matts/2014-08-21T01:00:00+01:002014-09-01T09:10:21+01:00Steve Tooke<p>Our next live Kickstart Academy podcast show will be on Monday, 1st
September at 15:30 BST. We’re pleased to welcome back <a href="https://twitter.com/lunivore">Liz Keogh</a> and
her invited guest <a href="https://twitter.com/PapaChrisMatts">Chris Matts</a>.</p>
<p>The show will be broadcast live here as well as from the <a href="https://plus.google.com/u/2/b/112947453773806733442/events/ca1jlhcdngrc29v5s96i8f2rdgc">event
page</a>. If you have any questions during the show, please use the Q&A
app on the <a href="https://plus.google.com/u/2/b/112947453773806733442/events/ca1jlhcdngrc29v5s96i8f2rdgc">event page</a> or tweet us
<a href="https://twitter.com/kickstartac">@kickstartac</a>.</p>
<iframe width="560" height="315" src="//www.youtube.com/embed/VHmjW3qjkLE"
frameborder="0" allowfullscreen></iframe>
Kickstart Academy Podcast with Liz Keogh and Corey Haineshttp://tooky.co.uk/kickstart-academy-podcast-with-liz-keogh-and-corey-haines/2014-07-31T01:00:00+01:002014-07-31T13:00:30+01:00Steve Tooke<p>For the third installment of the Kickstart Academy podcast we were pleased to
have <a href="https://twitter.com/lunivore">Liz Keogh</a> join us — and <a href="https://twitter.com/coreyhaines">Corey Haines</a> returned to the
panel for his second appearance.</p>
<p></p>
<p>We enjoyed having <a href="https://twitter.com/sandimetz">Sandi Metz</a> on the panel for the <a href="http://kickstartacademy.io/blog/2014-07-29-kickstart-academy-podcast-with-corey-haines-and-sandi-metz">last
podcast</a> so much that we hope to have a running theme of inviting
the previous guest back to the following show – in a similar vein to BBC Radio
4’s <a href="http://en.wikipedia.org/wiki/Chain_Reaction_%28radio%29">Chain Reaction</a>.</p>
<iframe width="560" height="315" src="//www.youtube.com/embed/_hKO-AVjCJM"
frameborder="0" allowfullscreen></iframe>
<p>There is an <a href="https://dl.dropboxusercontent.com/u/41915/kickstart-academy-podcast/003-liz-keogh-and-corey-haines.mp3">audio version of this podcast available here</a>.</p>
<h2>Show Notes</h2>
<ul>
<li>[0:01:39] Liz’s backstory</li>
<li>[0:04:17] Define <a href="http://en.wikipedia.org/wiki/Cynefin">Cynefin</a> - a sense making framework
<ul>
<li>Simple/Obvious - children can solve it</li>
<li>Requires expertise - watchmaker</li>
<li>Complex - not predictable outcomes</li>
<li>Chaos - accident and emergency</li>
</ul></li>
<li>[0:08:30] Software development approaches within the different cynefin domains
<ul>
<li>Commoditised requirements vs Differentiating Requirements</li>
<li>Chaos - Experiment / Spike / Probe</li>
<li>Requires expertise - Analyze (e.g. BDD)</li>
<li>Simple - off the shelf</li>
</ul></li>
<li>[0:12:25] Capabilities vs Goals
<ul>
<li>Understanding the goal behind the capability</li>
<li>Which stakeholders are getting the benefit?</li>
<li><a href="https://twitter.com/imtomgilb">Tom Gilb</a> - <a href="http://gilb.com/Project-Management">Evolutionary Project Management</a></li>
</ul></li>
<li>[0:16:31] Is BDD a design activity not required for obvious requirements? - <a href="https://twitter.com/mattwynne">Matt Wynne</a>
<ul>
<li>Analyze as simply as possible</li>
<li>Name the scenarios</li>
<li>Ask: is there anything different?</li>
</ul></li>
<li>[0:20:40] BDD: automation and regression testing
<ul>
<li>How you set the context with “Given” doesn’t matter</li>
<li>“When” is the actual behaviour your interested in</li>
</ul></li>
<li>[0:22:11] Liz’s scale for classifying capabilities
<ul>
<li>5 - nobody in the world has ever done it before</li>
<li>4 - somebody has done it before but not in this organisation</li>
<li>3 - somebody in this organisation has done it before, and we need their expertise</li>
<li>2 - somebody in the team has done it before</li>
<li>1 - we all know how to do it</li>
</ul></li>
<li>[0:23:05] When automated scenarios catch a regression bug it’s usually because of poor design
<ul>
<li>Don’t just throw more scenarios at it find out why your getting the bugs</li>
<li>Often because two capabilities are bleeding in to each other</li>
</ul></li>
<li>[0:25:51] Techniques for talking through capabilities with stakeholders
<ul>
<li>Why are we doing this project?</li>
<li>Who are we doing it for?</li>
<li>Can you give me an example?</li>
<li>What will you be able to do that you can’t do now?</li>
</ul></li>
<li>[0:30:44] Focusing on the outcome
<ul>
<li><a href="https://twitter.com/PapaChrisMatts">Chris Matts</a> - <a href="http://theitriskmanager.wordpress.com/2014/07/06/a-tale-of-two-feature-injections-a-cynefin-tale/">Value Mapping</a></li>
<li>Assign numbers from Liz’s scale to capabilities</li>
<li>For 1s and 2s, “Choose the technology that’s easy to change” - Chris Matts</li>
</ul></li>
<li>[0:37:01] Applying BDD at the different levels
<ul>
<li>When outcomes are uncertain, can lead to analysis paralysis</li>
<li>Often an indicator of 4s and 5s</li>
<li>So find a way to prototype/experiment</li>
<li>Listen for the uncertainty</li>
<li>Listen for the boredom</li>
</ul></li>
<li>[0:42:05] What is BDD?
<ul>
<li>Not testing tools with BDD mode - “should” or “expect”</li>
<li>“Using examples to illustrate behaviour” - Liz</li>
<li>Let dev’s write the scenarios, and get feedback from the testers and experts</li>
<li><a href="https://twitter.com/tastapod">Dan North</a>’s <a href="http://en.wikipedia.org/wiki/Behavior-driven_development#History">definition</a> true in 2009, maybe not 2010</li>
<li>It’s not necessarily high-automation</li>
<li>It’s still outside-in</li>
<li>It’s still 2nd generation</li>
<li>It’s still pull-based</li>
<li>It’s still multiple-scale</li>
<li>It’s still agile</li>
<li>It’s still about getting feedback</li>
<li>It’s still a cycle of interactions</li>
<li>We now respect we can’t always get well defined outputs</li>
<li>It still results in software that matters</li>
</ul></li>
<li>[0:49:01] Patterns for improving scenarios
<ul>
<li>Just write down what people say</li>
<li>Have the conversation</li>
<li>Don’t try to make patterns fit existing steps</li>
<li>Step away from the tools</li>
</ul></li>
<li>[0:53:14] How does having theses conversations about the system itself affect the minute-by-minute development process?
<ul>
<li>Leads to more spikes and prototypes, and understanding why to do them?</li>
<li>Less useful for large organisations where a lot of the work is governed by regulations</li>
<li>Removes frustrations of things like 4-hour planning meetings</li>
</ul></li>
<li>[0:55:25] Can you use examples to identify and then test your assumptions?</li>
<li>[0:57:45] Leveling capabilities
<ul>
<li>Map out the capabilities</li>
<li>Map the stakeholders - then understand the capailities they are looking for</li>
<li>Try estimating them using relative sizes</li>
<li>Find the capabilities that are new</li>
</ul></li>
<li>[1:00:33] Liz’s Fantasy Fiction
<ul>
<li><a href="https://leanpub.com/silversongchild">The Silversong Child</a></li>
<li><a href="https://leanpub.com/nightingalethrone">The Nightingale Throne</a></li>
<li>High-level fantasy - a bit like Game of Thrones, with less killings and more magic</li>
</ul></li>
<li>[1:01:40] How do you guard against new adopters of BDD from just rewriting existing requirements with new words, e.g. should, then, describe, expect - <a href="https://twitter.com/kerryb">Kerry Buckley</a>
<ul>
<li><a href="http://vimeo.com/75923366">What is the value of Social Capital? - Jabe Bloom</a> - <a href="https://twitter.com/cyetain">Jabe Bloom</a></li>
</ul></li>
</ul>
Kickstart Academy Podcast with Corey Haines and Sandi Metzhttp://tooky.co.uk/kickstart-academy-podcast-with-corey-haines-and-sandi-metz/2014-07-29T01:00:00+01:002014-07-29T11:25:30+01:00Steve Tooke<p>Last month we broadcast our 2nd live podcast. We were fortunate to be joined by
<a href="https://twitter.com/coreyhaines">Corey Haines</a> — to discuss simple design — and by <a href="https://twitter.com/sandimetz/">Sandi
Metz</a> — who was kind enough to return for a second show.</p>
<p></p>
<iframe width="560" height="315" src="//www.youtube.com/embed/BT7MYd07OFw"
frameborder="0" allowfullscreen></iframe>
<p>There is an <a href="http://bit.ly/1lR4AsO">audio version of this podcast available here</a> - but due to the nature
of the live code examples on the video version that is probably the better
experience.</p>
<h2>Show Notes</h2>
<ul>
<li>[0:02:20] — 4 rules of simple design
<ul>
<li><a href="https://twitter.com/kentbeck">Kent Beck</a></li>
<li>“Design that is easier to change” - Corey</li>
<li><a href="http://www.jbrains.ca/permalink/the-four-elements-of-simple-design">Four elements of simple design</a> — <a href="https://twitter.com/jbrains">J. B. Rainsberger</a></li>
</ul></li>
<li>[0:6:11] — <a href="https://leanpub.com/4rulesofsimpledesign">Understanding the 4 Rules of Simple Design</a>
<ul>
<li><a href="http://coderetreat.org/">Code Retreat</a></li>
<li>Sandi doesn’t hate Corey…</li>
</ul></li>
<li>[0:10:17] Understanding Testing Book
<ul>
<li>What can you learn from writing your own assert method?</li>
<li>All testing frameworks bring baggage with them - leaving that aside allows
you to understand the fundamentals</li>
<li>Do you start with <code>assert</code> or <code>assert_true</code> ?</li>
</ul></li>
<li>[0:19:55] Writing your own assert method demo
<ul>
<li>(apologies about the sound cutting in and out, Hangouts appears to mute
typing)</li>
<li>“Fundamentally testing is about checking that two things are the same” - Corey</li>
</ul></li>
<li>[0:30:02] Having rich ways of verifying your system can mask design feedback from simple tests
<ul>
<li><a href="http://www.typemock.com/">TypeMock</a> for mocking static methods in .NET masked the need to inject dependencies</li>
</ul></li>
<li>[0:36:00] Only having simple testing features can lead to writing a single method that does everything</li>
<li>[0:38:10] The tension between learning and getting things out in production
<ul>
<li>Being able to explain the value of the things that you use</li>
<li>Doing something because smart people say you should do it, and understanding why they do it</li>
</ul></li>
<li>[0:45:21] What’s the best approach to teaching design sense to new programmers?
<ul>
<li>Go back to the mechanical refactoring steps - back to the fundamentals</li>
<li>“refactorings are little machines that produce objects” - Sandi</li>
<li><a href="http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29">SOLID</a> principles are guide points</li>
</ul></li>
<li>[0:54:10] Actionable principles
<ul>
<li>SOLID principles are hard to action, minute-by-minute</li>
<li>Inner/outer design loops</li>
<li><a href="http://industriallogic.com/xp/refactoring/">Refactoring to Patterns - Joshua Kerievsky</a></li>
</ul></li>
<li>[01:01:22] Efficient ways of travelling the long road
<ul>
<li>Paying attention to what your doing</li>
<li><a href="http://www.innovationexcellence.com/blog/2012/10/24/divergent-and-convergent-thinking/">Divergent/convergent thinking</a> phases</li>
<li><a href="http://en.wikipedia.org/wiki/Sunk_costs">Sunk cost fallacy</a></li>
</ul></li>
<li>[01:04:07] Only ever one undo away from being back to green
<ul>
<li><a href="https://gist.github.com/tooky/a75778f70499af2f9435">Corey’s Challenge</a></li>
<li><a href="http://www.infoq.com/presentations/The-Limited-Red-Society">Limited Red Society - Joshua Kerievsky</a></li>
<li><a href="http://vimeo.com/3763583">Time to Green Graph - Gary Bernhardt</a></li>
</ul></li>
</ul>
Using charklock_holmes on Herokuhttp://tooky.co.uk/using-charklock_holmes-on-heroku/2014-06-11T01:00:00+01:002014-06-11T13:58:54+01:00Steve Tooke<p><a href="https://github.com/brianmario/charlock_holmes"><code>charlock_holmes</code></a> is a useful gem if you have to deal with
user supplied data which may come in a variety of text-encodings. Not only does
it enable you to detect the encoding of a string, but it also allows you to
transcode the string to a different encoding.</p>
<p><code>charklock_holmes</code> uses <a href="http://site.icu-project.org"><code>libicu</code></a> to deal with string encoding.</p>
<p>Unfortunately, the default <a href="https://www.heroku.com">Heroku</a> buildpack for Ruby doesn’t include
<code>libicu</code> which prevents bundler from being able to compile <code>charklock_holmes</code>
C-extension.</p>
<p>There have been a few attempts at solving this problem, most of which are
discussed over on <a href="http://stackoverflow.com/questions/18926574/how-to-install-charlock-holmes-dependency-libicu-dev-on-heroku">stack overflow</a>. The <a href="http://stackoverflow.com/a/18926982/223996">accepted
answer</a> is a common solution, which relies on using
a version of the gem which includes a bundled version of <code>libicu</code>. While this
works, it does result in very slow build times both on heroku, and locally when
doing a bundle install.</p>
<p><a href="http://stackoverflow.com/a/20507705/223996">Another solution</a> uses a custom version of the ruby
buildpack which includes <code>libicu</code> — while this is a simple solution it
relies on the maintainer of that solution keeping it up to date with heroku’s
ruby buildpack.</p>
<p><a href="http://stackoverflow.com/a/22662875/223996">My favourite solution</a> seems to move in the right direction,
it uses <a href="https://github.com/ddollar/heroku-buildpack-multi"><code>heroku-buildpack-multi</code></a> and
<a href="https://github.com/ddollar/heroku-buildpack-apt"><code>heroku-buildpack-apt</code></a> to install <code>libicu</code> using apt.
Unfortunately it uses a forked version of the <code>heroku-buildpack-apt</code> which
adds specific behaviour for <code>charlock_holmes</code> and where <code>bundler</code> can find the
version of <code>libicu</code> installed by <code>apt</code>.</p>
<p>My solution builds upon the previous solution, but rather than use a custom
version of the <code>heroku-buildpack-apt</code> I have added one more buildpack into the
mix — <a href="https://github.com/timolehto/heroku-bundle-config"><code>heroku-bundle-config</code></a>.</p>
<p>This buildpack allows you to configure your heroku bundler config in your
repository in the <code>.heroku-bundle</code> directory. During the build it will move this
directory to <code>.bundle</code>, and most importantly, make sure that all <code>/app</code> paths
point correctly to the temporary build directory.</p>
<p>I’ve created a <a href="https://github.com/tooky/heroku-charlock-holmes">sample project</a>, that can be <a href="http://heroku-charlock-holmes.herokuapp.com">deployed to heroku</a> – the only thing
you need to do is ensure that you have set the <code>BUILDPACK_URL</code> to
<code>https://github.com/ddollar/heroku-buildpack-multi.git</code>:</p>
<pre><code class="highlight plaintext">$ heroku config:set BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git
</code></pre>
<p>When you push to heroku, this buildpack will check for a <code>.buildpacks</code> file,
which specify the different buildpacks you want to use:</p>
<pre><code class="highlight plaintext">https://github.com/ddollar/heroku-buildpack-apt
https://github.com/timolehto/heroku-bundle-config
https://github.com/heroku/heroku-buildpack-ruby
</code></pre>
<p><code>heroku-buildpack-apt</code> will then check for an <code>Aptfile</code> and install the
specified packages:</p>
<pre><code class="highlight plaintext">libicu-dev
</code></pre>
<p>Finally, you need to configure you <code>.heroku-bundle/config</code> to make sure that
<code>bundler</code> can use your newly installed version of <code>libicu</code>:</p>
<pre><code class="highlight plaintext">---
BUNDLE_FROZEN: '1'
BUNDLE_PATH: vendor/bundle
BUNDLE_BIN: vendor/bundle/bin
BUNDLE_JOBS: 4
BUNDLE_WITHOUT: development:test
BUNDLE_DISABLE_SHARED_GEMS: '1'
BUNDLE_BUILD__CHARLOCK_HOLMES: --with-icu-lib=/app/.apt/usr/lib --with-icu-include=/app/.apt/usr/include
</code></pre>
<p>That should be all you need.</p>
Using `direnv` and `chruby` togetherhttp://tooky.co.uk/using-direnv-and-chruby-together/2014-06-10T01:00:00+01:002014-06-10T07:07:17+01:00Steve Tooke<p>I’ve been using <a href="https://github.com/postmodern/chruby"><code>chruby</code></a> to manage my ruby versions for a few
months — I like it’s lightweight approach.</p>
<p>A combination of <a href="http://bundler.io">bundler’s</a> <a href="http://robots.thoughtbot.com/use-bundlers-binstubs">binstubs</a>, the introduction
of rails 4 introducing the <code>bin</code> directory and trying to <a href="http://12factor.net">use the
environment to configure my apps</a> has meant I wanted a way to
to manage my environment on a per project basis.</p>
<p>I’ve tried using <a href="https://github.com/bkeepers/dotenv">dotenv</a>, which works well for ruby projects, and for
setting environment variables to be used by your app — but, as far as
I can tell, it doesn’t actually modify your environment. So setting your <code>PATH</code>
to select the correct binary, e.g. <code>bin/rails</code> in a rails app, won’t work.</p>
<p>Enter <a href="https://github.com/zimbatm/direnv"><code>direnv</code></a>. <code>direnv</code> looks for a <code>.envrc</code> file in a directory and
loads any thing there into your environment. You have to specifically allow
direnv to load a file, and it tracks modifications to the file. It’s very nice.</p>
<p>Unfortunately, I had a problem using it alongside <code>chruby</code> — everytime
I entered a directory <code>direnv</code> would do it’s thing and then <code>chruby</code> would
follow suit, and I could never quite get the result I wanted! For example, I’d
have the right version of ruby, but the wrong <code>PATH</code> &mdash or the right <code>PATH</code>
with the wrong ruby.</p>
<p>To fix this I removed <code>chruby</code>’s auto switching feature from my default
environment, and based on a suggestion <a href="https://github.com/zimbatm/direnv/issues/98">here</a> added a <code>use_ruby</code>
function to my <code>~/.direnvrc</code>:</p>
<pre><code class="highlight shell"><span class="nb">source</span> /usr/local/share/chruby/chruby.sh
<span class="c"># use ruby [version]</span>
use_ruby<span class="o">()</span> <span class="o">{</span>
<span class="nb">local </span><span class="nv">ver</span><span class="o">=</span><span class="nv">$1</span>
<span class="k">if</span> <span class="o">[[</span> -z <span class="nv">$ver</span> <span class="o">]]</span> <span class="o">&&</span> <span class="o">[[</span> -f .ruby-version <span class="o">]]</span>; <span class="k">then
</span><span class="nv">ver</span><span class="o">=</span><span class="k">$(</span>cat .ruby-version<span class="k">)</span>
<span class="k">fi
if</span> <span class="o">[[</span> -z <span class="nv">$ver</span> <span class="o">]]</span>; <span class="k">then
</span><span class="nb">echo </span>Unknown ruby version
<span class="nb">exit </span>1
<span class="k">fi
</span>chruby <span class="nv">$ver</span>
<span class="o">}</span>
</code></pre>
<p>This checks for a <code>.ruby-version</code> file, and, if it finds one, defers to <code>chruby</code>
to load the correct ruby environment.</p>
<p>I can now use this function in a project <code>.envrc</code> to load ruby before I modify
the path:</p>
<pre><code class="highlight shell">use ruby
PATH_add bin
</code></pre>
<p>You can also pass a ruby version to the <code>use_ruby</code> function:</p>
<pre><code class="highlight shell">use ruby 2.1
PATH_add bin
</code></pre>
<p>If you don’t want to use a <code>.ruby-version</code> file.</p>
<p>This seems to work really well. The only downside is that I don’t have
autoswitching of ruby versions anymore — unless I decide that’s what
I want. I don’t think its too bad to have to be explicit about that.</p>
Kickstart Academy Podcast with Sandi Metzhttp://tooky.co.uk/kickstart-academy-podcast-with-sandi-metz/2014-05-21T01:00:00+01:002014-06-10T07:00:47+01:00Steve Tooke<p><a href="https://twitter.com/mattwynne">Matt</a>, <a href="https://twitter.com/chrismdp">Chris</a> and <a href="https://twitter.com/tooky">I</a> were joined yesterday by <a href="https://twitter.com/sandimetz">Sandi
Metz</a> for a live google hangout.</p>
<p></p>
<iframe width="560" height="315" src="//www.youtube.com/embed/u-d2v_8YYw4" frameborder="0" allowfullscreen></iframe>
<p>You can <a href="https://dl.dropboxusercontent.com/u/41915/kickstart-academy-podcast/001-sandi-metz.mp3">download an audio only version of the podcsast
here</a>.</p>
<p>I’d like to thank Sandi for giving us her time and her insight!</p>
<p>We would love to hear any thoughts you have about the show - either about the
content or the format. We’re planning to do a live show about once a month, so
if there’s anyone you’d like us to talk to, or any topics you’d like us to cover
please let us know.</p>
<p>You can email us at <a href="mailto:hello@bddkickstart.com">hello@bddkickstart.com</a>.</p>
<h2>Show notes</h2>
<p>We all had a lot of fun and covered quite a few topics:</p>
<ul>
<li><a href="https://github.com/makaroni4/sandi_meter">The Sandi Meter</a> and the (don’t call them the) “Sandi Metz” rules</li>
<li>Small Things</li>
<li>Letting go of the big picture</li>
<li>“Everything I know now I cargo culted”</li>
<li>Finding the sweet spot between extremes</li>
<li>Experimenting</li>
<li>Object-oriented thinking</li>
<li>Rails and frameworks</li>
<li>Testability
<ul>
<li><a href="https://twitter.com/tomstuart">Tom Stuart</a> - <a href="http://codon.com/how-testability-can-help">How testability can help</a></li>
</ul></li>
<li><a href="http://en.wikipedia.org/wiki/Open/closed_principle">Open/Closed Principle</a></li>
<li>Focus on the messages</li>
<li>Starting at the whiteboard</li>
<li>It’s not <a href="http://geepawhill.org/?p=47">TDYAR</a></li>
<li>End-to-end testing vs isolated testing</li>
<li>Testing at different levels of granularity</li>
<li><a href="http://blog.thecodewhisperer.com/2014/05/14/the-curious-case-of-tautological-tdd/">Tautological TDD</a></li>
<li>TDD and driving desing</li>
<li><a href="http://en.wikipedia.org/wiki/Single_responsibility_principle">Single Responsibility Principle</a></li>
<li>Confidence</li>
<li><a href="http://kickstartacademy.io/courses/practical-object-oriented-design">#POODL</a> - Practical Object Oriented Design classes with Sandi and
Matt in London</li>
<li>Integration tests and testing roles</li>
<li>Functional vs Object Oriented
<ul>
<li><a href="http://elixir-lang.org/">Elixir</a></li>
</ul></li>
<li>Microservices Architecture
<ul>
<li><a href="https://twitter.com/fgeorge52">Fred George</a> on <a href="http://oredev.org/2013/wed-fri-conference/implementing-micro-service-architectures">Microservices Architecture</a></li>
</ul></li>
<li>Readable code</li>
<li>Imperative vs Declarative approach</li>
<li>Tell Don’t Ask - What Not How</li>
<li><a href="http://signup.practicalrailsbook.com/?lrRef=Ejvoln">Practical Rails Programming</a></li>
<li>99 Bottles of Beer</li>
<li><a href="http://vimeo.com/26330100">T R U E</a>
<ul>
<li><a href="https://twitter.com/unclebobmartin">Uncle Bob Martin</a> - <a href="http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf">Symptoms of Rotting Design</a></li>
</ul></li>
<li>Exemplary Code</li>
<li>The pattern failed me
<ul>
<li><a href="https://www.youtube.com/watch?v=x1wnI0AxpEU">All the little things keynote</a></li>
<li>Gilded rose kata</li>
</ul></li>
<li>Code Metrics
<ul>
<li><a href="https://github.com/seattlerb/flog">Flog</a></li>
<li><a href="https://codeclimate.com/">Code Climate</a></li>
</ul></li>
</ul>
Hangout with Matt Wynne and Aslak Hellesøyhttp://tooky.co.uk/hangout-with-matt-wynne-and-aslak-hellesoy/2014-05-16T16:11:00+01:002014-06-10T07:00:47+01:00Steve Tooke<p>A few weeks ago Matt, Aslak and I held a live google hangout. Today I realised
that I hadn’t mentioned it here. If you haven’t seen it yet you can watch it
here:</p>
<p></p>
<iframe width="560" height="315" src="//www.youtube.com/embed/P6znT1H04PE" frameborder="0" allowfullscreen></iframe>
<p>I’d love to hear what you thought about it, and what we can do better next time
— especially as next time is this Monday, and we’ll be joined by <a href="http://www.sandimetz.com">Sandi
Metz</a> to talk about object-oriented design.</p>
<p><a href="https://plus.google.com/b/112947453773806733442/events/ck08u3ha70spbk5p467j2ip5sgs">Kickstart Academy Hangout with Sandi Metz</a></p>
<p>Using the hangout format means that we can include screensharing, code and most
importantly your contributions! Please let us know what you’d like to hear us
discuss.</p>
The Cucumber Test Traphttp://tooky.co.uk/the-cucumber-test-trap/2014-03-29T00:00:00+00:002014-04-03T11:55:02+01:00Steve Tooke<p><a href="https://twitter.com/aslak_hellesoy">Aslak Hellesøy</a> recently wrote how cucumber is “<a href="https://cucumber.pro/blog/2014/03/03/the-worlds-most-misunderstood-collaboration-tool.html">the world’s most
misunderstood collaboration tool</a>.”</p>
<blockquote>
<p>Cucumber was born out of the frustration with ambiguous requirements and
misunderstandings between the people who order the software and those who
deliver it.</p>
</blockquote>
<p>Anybody who has spent time with more than a few codebases that use cucumber will
probably recognise Aslak’s description of a cucumber anti-pattern:</p>
<blockquote>
<p>When Cucumber is adopted solely as a tool to write automated tests without
any input from business analysts they tend to become imperative and lose
their documentation value.</p>
<p>This also makes them slow and brittle.</p>
</blockquote>
<p>This doesn’t tell the whole story though - there are many teams that work with
the business to define their scenarios, that make an effort to write declarative
scenarios - yet some of these teams still suffer from slow and brittle builds.</p>
<p>They’ve fallen into the cucumber test trap - they want to document everything
the system does and automatically check it using cucumber.</p>
<p>As they start building their system the automated cucumber suite gives them
the confidence that everything is working. Running the features is quick and
their system is simple. As they add behaviour to the system they diligently
document the behaviour in gherkin and automate it with cucumber. All of the
while running every scenario from end-to-end through their entire stack.</p>
<p>In <a href="http://pragprog.com/book/hwcuc/the-cucumber-book">The Cucumber Book</a> (<em>When Cucumbers Go Bad</em> p. 103), <a href="https://twitter.com/mattwynne">Matt
Wynne</a> and Aslak describe one of the main causes for “<em>Slow Features</em>”:</p>
<blockquote>
<p><strong>Lots of Scenarios</strong></p>
<p>It might seem like stating the obvious, but having a lot of scenarios is by
far the easiest way to give yourself a slow overall feature run. We’re not
trying to suggest you give up on BDD and go back to cowboy coding, but we do
suggest you treat a slow feature run as a red flag. Having lots of tests has
other disadvantages than just waiting a long time for feedback. It’s hard
to keep a large set of features organized, making them awkward for readers
to navigate around. Maintenance is also harder on the underlying step
definitions and support code.</p>
</blockquote>
<p>Of course this isn’t really a product of using cucumber, or even trying to get
started with BDD or Specification by Example. It’s exactly the same problem that
<a href="https://twitter.com/jbrains/">J. B. Rainsberger</a> describes when he says that “<a href="http://blog.thecodewhisperer.com/2010/10/16/integrated-tests-are-a-scam/">integrated tests
are a scam</a>.”</p>
<blockquote>
<p>You write integrated tests because you can’t write perfect unit tests. You
know this problem: all your unit tests pass, but someone finds a defect
anyway. Sometimes you can explain this by finding an obvious unit test you
simply missed, but sometimes you can’t. In those cases, you decide you need
to write an integrated test to make sure that all the production
implementations you use in the broken code path now work correctly together.</p>
</blockquote>
<p>As soon as you make a decision that you will describe everything your system
does using cucumber features you’ve left BDD behind, fallen into the cucumber
test trap and are destined to have “<em>Lots of Scenarios</em>”. J. B.
<a href="http://blog.thecodewhisperer.com/2010/10/16/integrated-tests-are-a-scam/">describes</a> this brilliantly:</p>
<blockquote>
<p>You have a medium-sized web application with around 20 pages, maybe 10 of
which have forms. Each form has an average of 5 fields and the average field
needs 3 tests to verify thoroughly. Your architecture has about 10 layers,
including web presentation widgets, web presentation pages, abstract
presentation, an HTTP bridge to your service API, controllers, transaction
scripts, abstract data repositories, data repository implementations, SQL
statement mapping, SQL execution, and application configuration. A typical
request/response cycle creates a stack trace 30 frames deep, some of which
you wrote, and some of which you’ve taken off the shelf from a wide variety
of open source and commercial packages. How many tests do you need to test
this application thoroughly?</p>
<p>At least 10,000. Maybe a million. One million.</p>
</blockquote>
<p><em>One million</em> scenarios - even <em>10,000</em> scenarios - to thoroughly check “a
medium sized web application” using cucumber. All of them running end-to-end. No
wonder teams have “<em>Slow Features</em>”.</p>
<p>Avoiding the cucumber test trap is hard. It’s easy to keep adding scenarios
which give you a false confidence that your application is working correctly.
It’s easy to just add some more code to make those scenarios pass.</p>
<p>Instead we need to keep <a href="http://lizkeogh.com/2011/09/22/conversational-patterns-in-bdd/">focusing on the conversations</a>. Find the
scenarios that matter, that are important to document, that are worth automating
and push everything else down into lower level, isolated tests.</p>
<p>Define contracts between layers, and test those exhaustively. Allow the design
pressure of creating testable code help you to build a cleaner, maintainable
application. This will help you prevent another one of the main causes of “<em>Slow
Features</em>” that Matt and Aslak describe in The Cucumber Book.</p>
<blockquote>
<p><strong>Big Ball of Mud</strong></p>
<p>The Big Ball of Mud is an ironic name given to the type of software design
you see when nobody has really made much effort to actually do any software
design. In other words, it’s a big, tangled mess.</p>
</blockquote>
<p>At the <a href="http://www.meetup.com/Extreme-Programmers-London/">Extreme Programmers London</a> meetup last week <a href="https://twitter.com/keithb_b">Keith
Braithwaite</a> talked about code metrics and the effect that
unit-testing has on the distribution of complexity in the codebase. During the
talk he mentioned that he thought the part of the TDD cycle that has the biggest
effect on the software design is when you have to add the next test, because we
often have to refactor our code to support adding the next test - to make it
testable.</p>
<p>In <a href="http://www.growing-object-oriented-software.com">Growing Object Oriented Software, Guided by Tests</a> (<em>What Is the Point
of Test-Driven Development</em>), <a href="https://twitter.com/sf105">Steve Freeman</a> and <a href="https://twitter.com/natpryce">Nat Pryce</a>
describe why testable code <em>is</em> well designed code.</p>
<blockquote>
<p>Thorough unit testing helps us to improve the internal quality because, to
be tested, a unit has to be structured to run outside the system in a test
fixture. A unit test for an object needs to create the object, provide its
dependencies, interact with it, and check that it behaved as expected. So,
for a class to be easy to unit-test, the class must have explicit
dependencies that can easily be substituted and clear responsibilities that
can easily be invoked and verified. In software engineering terms, that
means that the code must be <em>loosely coupled</em> and <em>highly cohesive</em> - in
other words, well designed.</p>
</blockquote>
<p>By falling into the cucumber test trap and relying on checking the system
end-to-end you lose this valuable design pressure that comes from TDD. You have
no need to make your units testable in isolation, because it’s <em>easy</em> to add
another test that runs from outside of the application. Which means you have
nothing pushing you to improve the internal quality of the codebase, nothing to
help you avoid creating a <em>Big Ball of Mud</em>.</p>
<p>Writing scenarios <em>with your customers</em> will help you to understand what your
application needs to do, and automating those scenarios with cucumber will help
you to know when the application meets those needs. Just don’t fall into the
trap of thinking you can use cucumber to test the app completely at the expense
of unit tests or <em>Lots of Scenarios</em> and a <em>Big Ball of Mud</em> will be your
reward.</p>
Discovering BDDhttp://tooky.co.uk/discovering-bdd/2013-12-11T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p>I graduated from UMIST in 2002 with a Software Engineering degree, and I started work with a company who provided document scanning services, mostly to the public sector - NHS trusts and local authorities. I came into the company thinking I knew it all - I had a software engineering degreee!</p>
<p>Wow - I had a <em>LOT</em> to learn!</p>
<p>I met Shane Paterson while I was there. Shane was another developer at the company, and even though he was based in New Zealand, he was responsible for pointing me in the direction of XP and TDD. There’s some more about this story in the <a href="http://chimera.labs.oreilly.com/books/1234000001813/ch04.html#solution_id19">Apprenticeship Patterns</a> book.</p>
<p>I started reading a lot of blogs and participating in the various mailing lists. I found an <a href="http://groups.yahoo.com/neo/groups/extremeprogramming/conversations/messages/116122">old post</a> on the XP mailing list where I was introducing a colleague to TDD using the bowling game kata which made me smile as I used the same exercise during some recent ruby/tdd training.</p>
<p>This colleague and I were about to start working on the new version of our main software application. A decision had been taken to rewrite the application with a completely new look and feel, to move to the new (at the time) .NET technology stack and to support MS SQL server as well as MS Access. The company had great success with application up until then because it could be set up and installed by anyone with file sharing permissions, so no need to involve corporate IT. This kind of culture was coming to an end though, so we needed to fit in with what the IT departments demanded.</p>
<p>We ran it as close to a proper XP project as the business would allow. In particular we were pair programming and we were writing our tests first! Not just unit tests, we were also writing acceptance tests with our ‘customer’ to help us understand the requirements.</p>
<p>We used a tool called <a href="http://en.wikipedia.org/wiki/Framework_for_Integrated_Test">FIT</a>. This allowed us to create word documents (!!) that contained tables of examples of what the software should do. We would then hook these tables up to some test classes which would run the tests and colour the tables appropriately.</p>
<p>Using tables to describe the requirements was fantastic. We were able to communicate clearly with our project sponsors about the business rules, using concrete examples to support our understanding.</p>
<p>Brian Marick’s foreword from the book really sums up what the FIT community were trying to do:</p>
<blockquote>
<p>A software project is a place where different cultures come together. Some people face towards the business and its concerns; other people face toward the computer and its demands.</p>
<p>To an expert in financial trading, a “bond” is something that’s tangled up in all sorts of explicit and implicit legal, social, historical and emotional meanings.</p>
<p>To programmers, a Bond is an object in their program that they’re trying to keep from getting too tangled up with other objects, lest their brains explode.</p>
<p>Somehow these people have to work together, and they do it by creating a shared language. Most of that creating happens through the conversation that threads through the whole project. But some of it happens through writing.</p>
<p><em>Brian Marick, Feb 2005 (foreword of <a href="http://www.pearsoned.co.uk/bookshop/detail.asp?item=100000000079971">Fit for Developing Software</a>)</em></p>
</blockquote>
<p>At about the same time as this I came across the term <em>Behaviour Driven Development</em> in <a href="http://blog.daveastels.com/2005/07/a-new-look-at-test-driven-development/">this post</a> by Dave Astels. It was about trying to change the focus of TDD from testing to specifying behaviour.</p>
<blockquote>
<ol>
<li><p>The problem I have with TDD is that its mindset takes us in a different direction… a wrong direction.</p></li>
<li><p>We need to start thinking in terms of behavior specifications, not verification tests.</p></li>
<li><p>The value of doing this will be thinking more clearly about each behaviour, relying less on testing by class or by method, and having better executable documentation.</p></li>
<li><p>Since TDD is what it is, and everyone isn’t about to change their meaning of that name (nor should we expect them to), we need a new name for this new way of working… BDD: Behaviour Driven Development.</p></li>
</ol>
</blockquote>
<p>This post really struck a chord with me. I was still getting to grips with TDD but when it had worked well for me it was when I was working how Dave described. The timing of this is a little fuzzy for me now, but it was right around the time I first started to use Ruby and Rails, so I picked up RSpec as my testing tool of choice.</p>
<p>The FIT toolchain didn’t exist in ruby, but in August 2007 the <a href="http://rubyforge.org/pipermail/rspec-devel/2007-August/003756.html">RSpec Story Runner was released</a> which gave us the tools to do similar things in ruby. The story runner gave way to <a href="http://cukes.info/">cucumber</a>.</p>
<p>Cucumber and Gherkin (the formal language for writing cucumber specifcations), have spread. It is now possible to write Gherkin specifications <a href="https://github.com/cucumber/cucumber-jvm">on</a> <a href="https://github.com/cucumber/cucumber-js">a</a> <a href="http://www.specflow.org/">huge</a> <a href="https://github.com/cucumber/cucumber-cpp">range</a> <a href="http://behat.org/">of</a> <a href="https://github.com/gabrielfalcao/lettuce">platforms</a>.</p>
<p>I think I made a mistake using these tools that many people have done. I used them to write tests. Sometimes they were very brittle tests, <a href="http://tooky.co.uk/stop-writing-scenarios-that-test-everything-through-the-view/">overly focussed on the view</a>. Often they were boring lists of instructions. I learnt to be more <a href="http://benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories.html">declarative</a>, and my tests became more readable. But…</p>
<p>They were still written as tests by me (and my colleagues) for the computer to run. <a href="http://lizkeogh.com/2011/03/04/step-away-from-the-tools/">BDD isn’t about the tools</a> its about the <a href="http://dannorth.net/2010/08/30/introducing-deliberate-discovery/">discovery</a>.</p>
<p>BDD enables communication. Our teams are made up of those who need the capabilities some new software will provide, and those who are able to create that software. These people come from different backgrounds, different experiences. Using stories and examples helps to create a shared language which we can then use to explore the problem space and begin to discover the things we don’t know!</p>
Learning by Teachinghttp://tooky.co.uk/learning-by-teaching/2013-11-06T00:00:00+00:002013-12-18T12:36:38+00:00Steve Tooke<p>For the last few weeks I’ve been working with <a href="http://kickstartacademy.io/">Kickstart Academy</a> teaching the <a href="https://www.onthebeach.co.uk/">On The Beach</a> ruby academy. We’ve been introducing a group of graduate and experienced developers to software development using ruby, bdd and git. Much of the teaching in the academy was based on ideas from <a href="http://www.bowperson.com/books.htm">Training from the Back of the Room</a> by Sharon Bowman and I wanted to share one of the exercises that we ran.</p>
<p>Bowman’s book has had quite an influence on the way that I approach training. The book focuses on leaving behind traditional training methods where learners are a passive audience as the trainer pushes information through lectures and slides. Instead, Bowman suggests that trainers should try to connect learners to past experiences, use shorter presented segments, and focus on giving learners lots of oppurtunity for concrete practice through exercises and activities.</p>
<p>Another major theme in the book is the idea that trainers should “step aside” and let the learners teach and learn from each other. This really stood out to me as I have found that whenever I’m teaching something to someone else, it helps me understand it more.</p>
<p>We set the group a task to go and spend some time researching the <a href="http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)">SOLID principles</a>. They worked in twos or threes and each group took one of the principles.</p>
<p>We gave them 45 minutes to produce a poster about the principle before we got back together and presented back to the group. Each group had the chance to think about their principle and how it affected some of the things we’d been working on. After each presentation we had a group discussion about the benefits and drawbacks that following the principle presented. Working through them together made the connections between the principles obvious.</p>
<p>This exercise, it’s output and the discussion between the learners really highlighted to me the role of a trainer. As a trainer we aren’t there to teach, or to talk at learners. We are trying to facilitate learning. We want to create an environment where the learners are able to discover ideas and try them out for themselves, offering guidance and help when they are stuck. Not only does this make the training more interesting and relevant for the learners, but it makes it more satisfying to teach. You get fast feedback about how the group are doing, and what topics you might need to spend more time on.</p>
<p>Here are the posters the group created.</p>
<h3>Single Responsibility Principle</h3>
<p><img alt="Single Responsibility Principle" src="https://dl.dropboxusercontent.com/u/41915/otb-solid/single-responsibility.jpg" /></p>
<h3>Open-Closed Principle</h3>
<p><img alt="Open-Closed Principle" src="https://dl.dropboxusercontent.com/u/41915/otb-solid/open-closed.jpg" /></p>
<h3>Liskov Substitution Principle</h3>
<p><img alt="Liskov Substitution Principle" src="https://dl.dropboxusercontent.com/u/41915/otb-solid/liskov-substitution.jpg" /></p>
<h3>Interface Segregation Principle</h3>
<p><img alt="Interface Segregation Principle" src="https://dl.dropboxusercontent.com/u/41915/otb-solid/interface-segregation.jpg" /></p>
<h3>Dependency Inversion Principle</h3>
<p><img alt="Dependency Inversion Principle" src="https://dl.dropboxusercontent.com/u/41915/otb-solid/dependency-inversion.jpg" /></p>
Stop Writing Scenarios That Test Everything Through The Viewhttp://tooky.co.uk/stop-writing-scenarios-that-test-everything-through-the-view/2013-10-29T00:00:00+00:002014-06-10T07:02:29+01:00Steve Tooke<p>Following on from my <a href="http://tooky.co.uk/this-gherkins-not-for-reading/">last post</a>, I wanted to mention a common anti-pattern that <a href="http://blog.8thlight.com/kevin-liddle/2013/09/18/a-case-against-cucumber.html">Kevin’s case against cucumber</a> mentioned. Scenarios that are too focussed on the user interface. Scenarios written as an imperative set of instructions for a machine to follow.</p>
<p></p>
<p>Scenarios like this.</p>
<pre><code class="highlight gherkin"><span class="nf">Given</span> I go to the homepage
<span class="nf">And</span> I fill in my username
<span class="nf">And</span> I click sign in
<span class="nf">When</span> I click <span class="s">"Accounts"</span>
<span class="nf">Then</span> I see <span class="s">"Current Account"</span>
<span class="nf">And</span> I see <span class="s">"Savings Account"</span>
</code></pre>
<p><em>sigh</em></p>
<p>There has been quite a lot written about this, the <a href="http://benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories.html">canonical post</a> is from 2008. The cucumber team made a mistake including <code>web_steps.rb</code> - they were <a href="https://github.com/cucumber/cucumber-rails/commit/f027440965b96b780e84e50dd47203a2838e8d7d">removed</a> 2 years ago.</p>
<p>The problem here isn’t just isolated to the imperative style of this scenario, but also that the scenario is highly coupled to the view.</p>
<p>Testing through the view is something you have to be wary of with any tool. It’s slow and brittle. That isn’t to say it has no value, but you don’t need every test to go through the UI. Beware the <a href="http://watirmelon.com/2012/01/31/introducing-the-software-testing-ice-cream-cone/">ice cream cone</a> anti-pattern.</p>
<p>I’ve written a little more about this <a href="http://tooky.co.uk/cucumber-and-full-stack-testing/">here</a>, Seb has introduced the <a href="http://claysnow.co.uk/the-testing-iceberg/">Testing Iceberg</a> and <a href="http://mattwynne.net">Matt</a> talks more about it <a href="http://skillsmatter.com/podcast/agile-testing/why-your-step-definitions-should-be-one-liners-and-other-pro-tips">here</a>.</p>
This Gherkin's Not For Readinghttp://tooky.co.uk/this-gherkins-not-for-reading/2013-10-24T01:00:00+01:002013-12-18T10:29:53+00:00Steve Tooke<p>Recently <a href="http://www.8thlight.com/our-team/kevin-liddle">Kevin Liddle</a> made his <a href="http://blog.8thlight.com/kevin-liddle/2013/09/18/a-case-against-cucumber.html">case against cucumber</a>. In the article he outlines several problems he experiences working with cucumber. One of his key arguments is that non-technical team members don’t read the scenarios written by developers.</p>
<blockquote>
<p>In theory, this is a valuable thing, a bridge between the divergent worlds of
developers and managers. In practice, however, I’ve never seen Cucumber used
this way. Non-technical people don’t read code, no matter how easy it is to
read. They care about the actual use cases and that means using the
application. And if they use the application, who cares if there is some text
claiming the application works!</p>
</blockquote>
<p>So why don’t non-technical people read the scenarios written by developers or testers?</p>
<p>Because they aren’t written for non-technical people to read! They probably aren’t even written with non-technical people in mind. They are written as a test script, they are written as a set of instructions for a computer to follow so they can execute a test plan. At best they’re written as set of steps that the developer will go through to get the feature finished.</p>
<p>Gherkin isn’t a scripting language for tests. Cucumber isn’t a testing tool. BDD isn’t a testing process. Kevin says that “non-technical people don’t read code” and that they “care about the actual use cases”.</p>
<p>We don’t want them to read our code, or our test plans. We want to talk to them about the behaviour, we want to discuss the impact they are looking to create and collaborate on how we can achieve that.</p>
<p>Gherkin’s value isn’t when it’s read. It’s when it’s written - it’s value is as a communication tool. It is close enough to natural language that both technical and non-technical people can collaborate but it has enough constraints to encourage thinking in terms of behaviour.</p>
<p>Writing scenarios with non-technical people, allows you to document the conversations you have about the behaviour of the system. It provides an avenue to explore new features and their value without building anything.</p>
<p>Kevin’s article goes on to highlight the value of gherkin when “gathering requirements”, but he argues that automating those scenarios using cucumber adds a level of overhead and’ indirection that is not worthwhile.</p>
<p>I have more to say about that, but that’s another post.</p>
<p>For now try sitting down with with your stakeholders and use gherkin to document examples of how they expect your software to behave. Use those examples to help you when you’re writing the code, but also check the assumptions with other people on the team. Do other non-technical stakeholders find them more readable?</p>
Cucumber and Full Stack Testinghttp://tooky.co.uk/cucumber-and-full-stack-testing/2013-01-18T00:00:00+00:002017-09-18T09:11:29+01:00Steve Tooke<p>There has been two similar questions asked on two different mailing lists I subscribe to (Corey Haines’ <a title="Build an app with Corey Haines" href="http://www.cleancoders.com/codecast/bawch-episode-1/show">BAWCH</a> mailing list, and <a href="http://rubyrogues.com/">Ruby Rogues</a> Parley list). Both of these lists are private so I thought it would be worthwhile posting my answer here.</p>
<p>Both of the questions were concerned with out-side-in development, full-stack integration testing, and how much of the application needs to be tested through the entire system.</p>
<p>Firstly consider why we write <a href="http://cukes.info/">cucumber</a> scenarios (or <a href="http://fitnesse.org/">fitnesse</a> test cases). These tests are business facing acceptance tests. They are a medium through which we can engage with the business people on our team and to help us understand how the system should behave. They give us an opportunity to check <em>our</em> understanding of what the system should do — to check the <em>business</em>’s understanding of what the system should do. We automate these tests to give the business confidence that the system behaves as expected.</p>
<p>Full-stack, end-to-end, integration tests are there to give us confidence that the system fits together correctly, that we have all the different pieces in place, and they are able to talk to each other.</p>
<p>It’s very easy to conflate these two concerns. I have worked on many systems where the business facing acceptance tests were also the end-to-end integration tests. The test runs end up being slow, and the tests are cumbersome to work with.</p>
<p>I’ve been talking about this with <a href="https://twitter.com/mattwynne">Matt Wynne</a> and he drew the following diagram:</p>
<p><img alt="Business Facing Acceptance Tests vs End-To-End Tests" src="https://www.dropbox.com/s/9urwnbofdbcwm82/business-facing-vs-end-to-end.png?dl=1" /></p>
<p>The circle on the left represents the tests that we would write in cucumber (or fitnesse). The circle on the right the tests which exercise the whole system end-to-end. In the centre we have the intersection — our cucumber scenarios which we run end-to-end against the whole system.</p>
<p>The key thing is that your business acceptance tests do not all have to drive the whole system end-to-end. We only a need a few scenarios to go end-to-end to give us the confidence the system as a whole is working. We can also write system tests, that aren’t part of the acceptance suite, to test specific integrations</p>
<p>Try to write acceptance tests that directly drive the domain objects. Use these to accurately describe your application’s behaviour. Focus them on the behaviour by not having them integrate the UI and the database.</p>
Delegation is not inheritancehttp://tooky.co.uk/delegation-is-not-inheritance/2012-08-08T01:00:00+01:002013-12-18T10:29:53+00:00Steve Tooke<p>On the train home last night I watched the excellent <a href="https://peepcode.com/products/play-by-play-jimweirich-ruby">Jim Weirich Play-by-play</a> from <a href="https://peepcode.com/">PeepCode</a>.</p>
<p>During the screencast Jim develops a library that “protects against unauthorized data model modification by users in less-privileged roles.” The screencast provides a great insight into the way Jim approaches problems, designs apis, and how he’s customised his environment to suit the way he works.</p>
<p>His approach is to build a proxy object which wraps the object to be updated, and provides a whitelist for fields which can be updated. He also inadvertantly demonstrates an easy mistake to make when using proxy objects.</p>
<p>Here is a simplified version of Jim’s solution - without any of the api for creating / finding proxies - which we will use to demonstrate this pitfall and its effects.</p>
<pre><code class="highlight ruby"><span class="nb">require</span> <span class="s1">'delegate'</span>
<span class="k">class</span> <span class="nc">ProtectionProxy</span> <span class="o"><</span> <span class="no">SimpleDelegator</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">object</span><span class="p">,</span> <span class="o">*</span><span class="n">writable_fields</span><span class="p">)</span>
<span class="k">super</span><span class="p">(</span><span class="n">object</span><span class="p">)</span>
<span class="vi">@writable_fields</span> <span class="o">=</span> <span class="n">writable_fields</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">method_missing</span><span class="p">(</span><span class="nb">method</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="n">method_name</span> <span class="o">=</span> <span class="nb">method</span><span class="p">.</span><span class="nf">to_s</span>
<span class="k">if</span> <span class="o">!</span><span class="n">method_name</span><span class="p">.</span><span class="nf">end_with?</span><span class="p">(</span><span class="s1">'='</span><span class="p">)</span>
<span class="k">super</span>
<span class="k">elsif</span> <span class="vi">@writable_fields</span><span class="p">.</span><span class="nf">include?</span><span class="p">(</span><span class="n">method_name</span><span class="p">[</span><span class="mi">0</span><span class="p">.</span><span class="nf">.</span><span class="p">.</span><span class="nf">-</span><span class="mi">1</span><span class="p">].</span><span class="nf">to_sym</span><span class="p">)</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>This approach works great for silently dropping calls to the accessor methods that are not in the provided whitelist. Here are some rspec examples which show how it works.</p>
<pre><code class="highlight ruby"><span class="nb">require</span> <span class="s1">'rspec-given'</span>
<span class="nb">require</span> <span class="s1">'protection_proxy'</span>
<span class="k">class</span> <span class="nc">User</span> <span class="o"><</span> <span class="no">Struct</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:email</span><span class="p">,</span> <span class="ss">:membership_level</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">describe</span> <span class="no">ProtectionProxy</span> <span class="k">do</span>
<span class="no">Given</span><span class="p">(</span><span class="ss">:user</span><span class="p">)</span> <span class="p">{</span> <span class="no">User</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"Jim"</span><span class="p">,</span> <span class="s2">"jim@somewhere"</span><span class="p">,</span> <span class="s2">"Beginner"</span><span class="p">)</span> <span class="p">}</span>
<span class="no">Given</span><span class="p">(</span><span class="ss">:proxy</span><span class="p">)</span> <span class="p">{</span> <span class="no">ProtectionProxy</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="ss">:membership_level</span><span class="p">)</span> <span class="p">}</span>
<span class="no">Then</span> <span class="p">{</span> <span class="n">proxy</span><span class="p">.</span><span class="nf">name</span><span class="p">.</span><span class="nf">should</span> <span class="o">==</span> <span class="s2">"Jim"</span> <span class="p">}</span>
<span class="n">context</span> <span class="s2">"when modifiying a writable field"</span> <span class="k">do</span>
<span class="no">When</span> <span class="p">{</span> <span class="n">proxy</span><span class="p">.</span><span class="nf">membership_level</span> <span class="o">=</span> <span class="s2">"Advanced"</span> <span class="p">}</span>
<span class="no">Then</span> <span class="p">{</span> <span class="n">proxy</span><span class="p">.</span><span class="nf">membership_level</span><span class="p">.</span><span class="nf">should</span> <span class="o">==</span> <span class="s2">"Advanced"</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">context</span> <span class="s2">"when modifiying a non-writable field"</span> <span class="k">do</span>
<span class="no">When</span> <span class="p">{</span> <span class="n">proxy</span><span class="p">.</span><span class="nf">name</span> <span class="o">=</span> <span class="s2">"Joe"</span> <span class="p">}</span>
<span class="no">Then</span> <span class="p">{</span> <span class="n">proxy</span><span class="p">.</span><span class="nf">name</span><span class="p">.</span><span class="nf">should</span> <span class="o">==</span> <span class="s2">"Jim"</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Now if we imagine we have a rails project, we can create a proxy to wrap our ActiveRecord object, and specify an attribute whitelist. This should then prevent mass-assignment of any non-whitelist attributes - it could be used in a controller like this:</p>
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">UserController</span> <span class="o"><</span> <span class="no">ActionController</span><span class="o">::</span><span class="no">Base</span>
<span class="k">def</span> <span class="nf">update</span>
<span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">])</span>
<span class="n">proxy</span> <span class="o">=</span> <span class="no">ProtectionProxy</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">:email</span><span class="p">)</span>
<span class="k">if</span> <span class="n">proxy</span><span class="p">.</span><span class="nf">update_attributes</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:user</span><span class="p">])</span>
<span class="c1"># happy path</span>
<span class="k">else</span>
<span class="c1"># error</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Unfortunately this won’t work as we might expect.</p>
<p>Proxying like this is a great way to add new behaviour to existing objects, without modifying them - or creating new subclasses. but there is one thing to be aware of when you are using delegation in this way.</p>
<p>Methods called on the wrapped object have <strong>no</strong> knowledge of the methods in the proxy object.</p>
<p>So what happens when we call <code>proxy.update_attributes</code>?</p>
<p>The proxy object immediately delegates that method call to the user object, it will call <code>user.update_attributes</code>.</p>
<p>If you have used ActiveRecord, you will be aware of the way that <code>ActiveRecord::Base#update_attrbiutes</code> will make use of the accessor methods on its instances to set the field names.</p>
<p>So, <code>user.update_attributes name: 'Joe'</code> will call <code>user.name = 'Joe'</code>, not the accessor methods on the proxy.</p>
<p><img alt="update attributes sequence diagram" src="http://dl.dropbox.com/u/41915/update_attributes_sequence_diagram.png" /></p>
<p>As we are not calling the accessor methods on the proxy, we aren’t filtering out the fields that don’t appear in the whitelist and our attribute protection won’t work when we use <code>update_attributes</code>.</p>
<p>Here is another example. <code>Capitalise</code> wraps an object and provides a upper case version of its name method.</p>
<pre><code class="highlight ruby"><span class="nb">require</span> <span class="s1">'delegate'</span>
<span class="k">class</span> <span class="nc">Capitalise</span> <span class="o"><</span> <span class="no">SimpleDelegator</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">source</span><span class="p">)</span>
<span class="vi">@source</span> <span class="o">=</span> <span class="n">source</span>
<span class="k">super</span><span class="p">(</span><span class="n">source</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">name</span>
<span class="vi">@source</span><span class="p">.</span><span class="nf">name</span><span class="p">.</span><span class="nf">upcase</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Person</span> <span class="o"><</span> <span class="no">Struct</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">:name</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">greet</span>
<span class="s2">"Hello, </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">john</span> <span class="o">=</span> <span class="no">Person</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s1">'john'</span><span class="p">)</span>
<span class="n">capital_john</span> <span class="o">=</span> <span class="no">Capitalise</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">john</span><span class="p">)</span>
<span class="n">john</span><span class="p">.</span><span class="nf">greet</span> <span class="c1">#=> "Hello, john"</span>
<span class="n">capital_john</span><span class="p">.</span><span class="nf">greet</span> <span class="c1">#=> "Hello, john"</span>
</code></pre>
<p>Because <code>greet</code> is defined in the <code>Person</code> class, when it calls <code>name</code> it will always call <code>Person#name</code>.</p>
<p>This has caught me out a couple times. It’s so easy in ruby to create proxy objects or decorators that its easy to forget that you have a different object.</p>
<p>One solution is to implement a version of <code>update_attributes</code> on the proxy object.</p>
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">ProtectionProxy</span> <span class="o"><</span> <span class="no">SimpleDelegator</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">object</span><span class="p">,</span> <span class="o">*</span><span class="n">writable_fields</span><span class="p">)</span>
<span class="k">super</span><span class="p">(</span><span class="n">object</span><span class="p">)</span>
<span class="vi">@object</span> <span class="o">=</span> <span class="n">object</span>
<span class="vi">@writable_fields</span> <span class="o">=</span> <span class="n">writable_fields</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">update_attributes</span><span class="p">(</span><span class="n">attributes</span><span class="o">=</span><span class="p">{})</span>
<span class="n">attrs</span> <span class="o">=</span> <span class="n">attributes</span><span class="p">.</span><span class="nf">select</span> <span class="p">{</span> <span class="o">|</span><span class="n">field_name</span><span class="o">|</span>
<span class="vi">@writable_fields</span><span class="p">.</span><span class="nf">include?</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
<span class="p">}</span>
<span class="vi">@object</span><span class="p">.</span><span class="nf">update_attributes</span> <span class="n">attrs</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Here we add an <code>update_attributes</code> method to the <code>ProtectionProxy</code> class - this only allows attributes allowed by the whitelist through to <code>User#update_attributes</code>.</p>
<p>The <a href="https://peepcode.com/products/play-by-play-jimweirich-ruby">screencast</a> ends with a note that Jim noticed this error later after recording of the screen cast finished. Jim’s complete solution, including the nice api, can be found on <a href="https://github.com/jimweirich/protection_proxy">github</a>.</p>
<p><a href="https://gist.github.com/3294185.js">Here is the whole of the <code>ProxyProtection</code> implementation</a>, with rspec examples.</p>
Tracking Project Emotions Using MercuryApphttp://tooky.co.uk/tracking-project-emotions-using-mercury-app/2010-11-23T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p>I’ve been trying out <a href="http://mercuryapp.com">MercuryApp</a> as a way to track how I’m feeling about a project we’ve just started. I’m tracking once a day, usually at about 4pm.</p>
<p>We try to run regular retrospectives on our projects, this gives us a chance to reflect on how the project is going. We often include a segment where each participant draws a ‘sparkline’ of how they were feeling over the period of time leading up to the retrospective. This let’s us see how various events effect peoples emotions.</p>
<p>This time I had my sparkline already. <a href="http://mercuryapp.com">MercuryApp</a> had been tracking this data for me all week. The surprise for me though was that I seemed to be more upbeat about things than I remembered. If I hadn’t had <a href="http://mercuryapp.com">MercuryApp</a> I’m sure my sparkline would have been less positive.</p>
<p>I suspect that the negatives I perceived were something to do with my mood at the time of the retrospective. It as towards the end of the day so I was tired, and I’d had a tough day.</p>
<p>I’m guessing that had my day been better, and I was in a more positive mood then my sparkline may well have been influenced in the other direction.</p>
<p>Having real data is great, not only is it more accurate when thinking about the previous week, but looking at how it differs from your perception gives you the chance to reflect on your mood right now! Liking the results from <a href="http://mercuryapp.com">MercuryApp</a> so far.</p>
<hr>
<p><em>Disclaimer: <a href="http://edendevelopment.co.uk">Eden Development</a> have been working with the guys at <a href="http://mercuryapp.com">MercuryApp</a>, but I have not been involved in the project.</em></p>
Fixing "There was a problem with the editor 'vi'" for Git on Mac OS X Snow Leopardhttp://tooky.co.uk/there-was-a-problem-with-the-editor-vi-git-on-mac-os-x/2010-04-08T01:00:00+01:002013-12-18T10:29:53+00:00Steve Tooke<p>I have had an annoying problem with git and vi. I like to use vim to edit my commit messages, but I’ve been hit with this annoying message every time I write the message and quit vim.</p>
<pre><code class="highlight plaintext">error: There was a problem with the editor 'vi'
</code></pre>
<p>After a little bit of digging I found that this message is shown by git when the editor exits with a non-zero exit code. You can use <code>$?</code> to see the exit code of last script or application.</p>
<pre><code class="highlight plaintext">$ vim # then exit vim with :q immediately
$ echo $?
1
</code></pre>
<p>I’m still not sure why vim is exiting with non-zero exit code, but it is definitely related to my <code>.vimrc</code> - moving it to <code>.vimrc.bak</code> seemed to fix the problem. I’m using the excellent <a href="http://www.vim.org/scripts/script.php?script_id=2332">pathogen</a> plugin to manage my vimfiles, so I plan to go through that and my installed plugins to find the cause of the problem.</p>
<p>There is a fix though, I’m not sure what’s causing this, but I found a <a href="http://groups.google.com/group/vim_mac/browse_thread/thread/0d33e2f2130867b0">post on the vim-mac mailing list</a> which shows this:</p>
<pre><code class="highlight plaintext">$ vim # and exit with :q
$ echo $?
1
$ /usr/bin/vim # and exit with :q
$ echo $?
0
$ which vim
/usr/bin/vim
</code></pre>
<p>Running vim with <code>/usr/bin/vim</code> seems to make it exit cleanly. So to fix the problem with git commit you just need to run this:</p>
<pre><code class="highlight plaintext">$ git config --global core.editor /usr/bin/vim
</code></pre>
<p>I’d still like to get to the root of the problem, but this gets me my git commit messages back!</p>
Why I think you should go to a code retreathttp://tooky.co.uk/why-i-think-you-should-go-to-a-coderetreat/2010-03-17T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p>Last Saturday I went along to the UK leg of <a href="http://coreyhaines.com/">Corey Haines</a> <a href="http://www.coderetreat.com/how-it-works.html">Code Retreat tour</a>. Apart from the early start it was a really interesting day, and I really enjoyed the chance to <a href="http://twitter.com/despo">pair</a> <a href="http://twitter.com/morty_uk">with</a> <a href="http://twitter.com/duncanbutler">lots</a> of new people.</p>
<p>The day was pretty tiring, pairing is always an intense experience, but I definitely learnt quite a lot. Its amazing how much fun working on the same problem several times in a row is, and how different approaches affect the way you think about it. By repeating the problem you allow your brain to concentrate on how you are solving it, rather than the problem itself. This gives you a really different perspective and is something I want to explore more.</p>
<p>There were so many things that I took away from the day, some of them are already changing my approach to building software:</p>
<h3>45 minutes is a really short amount of time</h3>
<p>The format of the code retreat is to work on the problem with a pair for 45 minutes. When the time is up, you delete all your code, and take break. Spend 15 minutes grabbing a coffee, reflecting on what you’ve done, and finding your next pair. Rinse and repeat.</p>
<p>Every 45 minute session flew by. Even so, with each pairing I was surprised at how far we’d managed to get. But what really surprised me, was how useful the short break and change of partner proved to be. The break gave you a real chance to reconsider your assumptions. That little bit of perspective was great in kick starting the next session.</p>
<p>It really surprised me how easy it was to swap pairs. Granted, everybody had been thinking about the same problem. But everyone was using a different approach, and sometimes a different language. The context switching didn’t seem to affect anybody. The new combinations brought new ideas and really contributed to the success of the day.</p>
<p>We’ve been trying the <a href="http://www.pomodorotechnique.com/">pomodoro technique</a> at work. I know I’ve been a bit resistant to stopping when the timer goes. I always feel like I should just get the rest of my ideas out before I take break, but based on my experience at code retreat, I think the short break from the problem will turn out to be a real benefit. I’m determined to try and do it properly and see how it works out.</p>
<p>I also want to try and swap pairs more often. I think that the new perspective a new pair will bring to a problem will really help to come to the best solution. I’m not sure about every hour, but once or twice a day should be achievable.</p>
<h3>Pairing is a great way to share insights and learning</h3>
<p>Leading on from the new perspective a new pair brings is also the amount of shared learning that happens when your pairing. I learnt something from everyone I paired with. Not just how to approach the problem, but new things about the language, the tools. In a team, pairing will really help to bring every team member up to speed on any new part of the code base or library added. Switching often will make this happen even faster.</p>
<h3>If you don’t need the infrastructure yet, don’t build it</h3>
<p>Why do you need to build a class to make your first spec pass? Why not just write the code you need in the spec? Then write the next spec, and the code to pass it in that spec. As soon as you start to see shared behaviour extract a method. When specs are using the same state and the same methods extract a class.</p>
<p>Working like this is <em>really</em> hard, but its amazing how the design you need just starts to show itself. </p>
<h3>Look at one behaviour at a time by isolating it using canned responses</h3>
<p>Most of the code we write doesn’t split up nicely into discreet chunks of behaviour. We build systems that rely on several pieces all working together to produce complicated behaviour. Complexity is difficult to define, so to make it easier we need to try to isolate the part that we’re interested in right now. We can use simple objects that return canned responses, this allows us to consider only the behaviour we care about now.</p>
<h3>Keeping things really simple is really hard</h3>
<p>Corey was continually encouraging us to keep things simple. Its amazing how often you think your doing something as simply as possible, and then someone comes along and makes it even simpler. Simple is good, it allows you to work on one thing at a time, and not get bogged down in things that don’t matter <em>right now</em>. </p>
<p>A lot of the direction at code retreat was about ways to keep things simple, to specify only the smallest piece of behaviour. Writing the code in the spec at first, and using ‘doubles’ to isolate behaviour are both great techniques to help you do that.</p>
<p>One of the main things I’m taking away from code retreat is to work hard at writing smaller, more focussed specs.</p>
<p>If there’s a <a href="http://www.coderetreat.com/">code retreat</a> near you I really encourage you to go along. If there isn’t join the <a href="http://coderetreat.ning.com/">community</a> and see if there’s anyone else who would be interested in helping get one organised.</p>
<p>I’d like to say thank you to <a href="http://coreyhaines.com/">Corey Haines</a>, the sponsors <a href="http://riverglide.com/">RiveGlide</a> and <a href="http://edendevelopment.co.uk/">Eden Development</a>, all of the attendees, and of course <a href="http://www.bletchleypark.org.uk/">Bletchley Park</a> and the <a href="http://www.tnmoc.org/">The National Museum of Computing</a> for making the day such a great success.</p>
Exploring Harmony for javascript BDD with RSpechttp://tooky.co.uk/exploring-harmony-for-unit-testing-with-rspec/2010-03-02T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p>We try to BDD all of our production code, but the one area we always seem to struggle with is our javascript. There are various test/spec frameworks for javascript, but we’ve never quite found one we’ve been totally happy with.</p>
<p>There’s been a fair amount of interest lately in a new ruby gem which allows you to execute javascript against a DOM from within a ruby process. <a href="http://github.com/mynyml/harmony">Harmony</a> uses <a href="http://github.com/jbarnette/johnson/">Johnson</a> a ruby wrapper for the <a href="http://www.mozilla.org/js/spidermonkey/">Mozilla SpiderMonkey</a> javascript runtime.</p>
<p>To get started figuring out how I might be able to integrate harmony into my workflow, I’ve created a very simple <a href="http://gist.github.com/319235">project</a> which uses rspec to make some very simple assertions about javascript behaviour.</p>
<p><script src="http://gist.github.com/319235.js?file=rspec_with_harmony.rb"></script></p>
<p>The 3rd and 4th specs are probably the most interesting. They show how how you can use an HTML fixture file, and load the javascript you want to test. This feels like a nice way of isolating your javascript, and would probably encourage me to write much more modular javascript.</p>
<p>Please fork the <a href="http://gist.github.com/319235">gist</a> and play with some more detailed specs.</p>
Remote pairing with GNU Screen and Vimhttp://tooky.co.uk/remote-pairing-with-gnu-screen-and-vim/2010-01-08T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p>All the recent <a href="http://search.twitter.com/search?q=%23uksnow">#uksnow</a> has left the <a href="http://edendevelopment.co.uk/blogs/company/2009/11/28/welcome-to-our-new-office/">Eden studio</a> a little deserted. With several of us having longish drives in to the office, we’ve been forced to get much better at remote pairing.</p>
<p>In the past we’ve used iChat screen sharing in the office for pairing on laptops, but with two people both at the end of a DSL connection, the screen + voice bandwidth demands are pretty high, and the guest user is at a painful disadvantage.</p>
<p><a href="http://www.vim.org/">Vim</a> is currently undergoing something of a rennaisance at <a href="http://edendevelopment.co.uk">Eden Development</a>. Several of us have been trying to use it for all our coding. Fortunately this has stood us in good stead to take advantage of a great low bandwidth pair programming solution.</p>
<p><a href="http://www.gnu.org/software/screen/">GNU Screen</a> + <a href="http://www.vim.org/">vim</a> (+ <a href="http://skype.com">skype</a>).</p>
<p>John Haruska gives a great <a href="http://haruska.com/2009/09/29/remote-pair-programming/">overview of different remote pairing solution</a> and outlines how to use screen to set up a shared terminal. Unfortunately we weren’t able to use the acl method to allow different UNIX users to share a ‘screen’ on our macs, but if both users logged in to the same unix account it worked like a dream.</p>
<p>Our basic process is:</p>
<p>User 1 sets up a screen as a shared user on the host machine</p>
<pre><code class="highlight plaintext">pairing$ screen -S pairing
Ctrl-a :multiuser on
</code></pre>
<p>User 2, logs into the maching via ssh, and connects to the shared screen</p>
<pre><code class="highlight plaintext">local$ ssh pairing@shared_machine
pairing$ screen -x pairing
</code></pre>
<p>That’s basically it. Both users then have access to a full shared terminal environment. A shared screen can have multiple windows, so we tend to work with one screen for vim and another for running tests and other terminal commands. We also make extensive use of <a href="http://www.linux.com/archive/articles/59533">vim tabs</a> and shell execution from within vim.</p>
<p>A couple of tips:</p>
<ul>
<li>make use of the <a href="http://www.samsarin.com/blog/2007/03/11/gnu-screen-working-with-the-scrollback-buffer/">GNU screen scrollback buffer</a></li>
<li>remote pairing can be quite intense, we find using <a href="http://www.pomodorotechnique.com/">The Pomodoro Technique</a> really useful in helping combat that - see <a href="http://tomatoi.st/">http://tomatoi.st/</a> for a shared timer.</li>
<li>audio is essential, but having a video link is even better</li>
<li>SSH requires some kind of NAT/firewall traversal - we found it simplest to just connect to the office vpn.</li>
</ul>
<p><a href="http://edendevelopment.co.uk/blogs/aimee/">aimee</a> has a great description of how aimee, <a href="http://blog.nexwerk.com/">Enrique</a> and I ended up <a href="http://edendevelopment.co.uk/blogs/aimee/2010/01/06/remote-trio-programming/">trio-programming</a> over the last couple of days, and here’s a photo to prove it. I’m the remote on the macbook to aimee’s left.</p>
<p><img title="Trio-programming with aimee and Enrique" alt="trio-programming" src="http://farm5.static.flickr.com/4055/4257007886_3442ceceba_d.jpg" /></p>
A Model for Lifehttp://tooky.co.uk/model_for_life/2009-12-17T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p>Its nearly two weeks since <a href="http://twitter.com/edentodd">Todd</a> gave me my first apprenticeship task:</p>
<blockquote>
<p>Assignment: To logically model an individual’s life from the perspective of a parent instructing their
child guidelines on how to make decisions to maximize happiness.</p>
<p>Requirements: Your model of a “Life” can be as extensive or granular as you wish to take it. There is
generally no wrong answer, other that it must reflect reality. You will be expected to defend your
model and the business rules you create.</p>
<p>Your model must take into to account (at minimum):</p>
<ul>
<li>Desires</li>
<li>Needs</li>
<li>Relationships</li>
<li>Finances</li>
<li>A State of well-being (happiness)</li>
<li>An unforeseen disaster</li>
</ul>
</blockquote>
<p>My son will be 2 on Monday. Its been amazing to watch him grow up and see him develop into a real character. When I think back to those first few weeks, I can say exactly what he needed and what made him happy then.</p>
<p>So long as he was warm, dry and fed and he had his mum he was happy - he was also mostly asleep.</p>
<p>Now its a different story. He still needs to be warm, dry and fed, but its no longer enough. He has to be entertained or challenged. He needs to see all the significant people in his life (coming home from work to excited shrieks of “Daddy, daddy” never gets old). He loves to visit his favourite places, play with favourite toys and watch his favourite DVDs. His life has become much more complex, and what makes him happy has followed suit.</p>
<p>This is how I’m going to approach this problem. I’m going to try to model a life from the point of view of a baby initially and see how it will evolves with time. I’ll continue to record my progress here.</p>
The Language of Software Craftsmanshiphttp://tooky.co.uk/language-of-software-craftsmanship/2009-12-11T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p>The <a href="http://groups.google.com/group/software_craftsmanship/browse_thread/thread/417bec17184ccfc2#">software craftsmanship list</a> had a little flurry of activity today. <a href="http://twitter.com/jasongorman">Jason Gorman</a> posted about <a href="http://www.teamsandtechnology.com/dh/blog/">David Harvey’s</a> <a href="http://qconlondon.com/london-2010/presentation/Danger:+Software+Craftsmen+at+Work">session</a> at next years <a href="http://qconlondon.com/london-2010/">QCon London</a>. The talk - <a href="http://qconlondon.com/london-2010/presentation/Danger:+Software+Craftsmen+at+Work">Danger: Software Craftsmen at Work</a> - unsurprisingly caused some discussion on the list!</p>
<p>Linked in the thread is an <a href="http://www.teamsandtechnology.com/dh/blog/2009/05/25/software-craftsmanship-can-we-just-get-over-it/">interesting article</a> by David that gives a little bit more context to his position.</p>
<blockquote>
<p>I have a problem with the language of software craftsmanship. The notion that somehow we’ll solve
our nascent profession’s problems by calling ourselves, or regarding ourselves, as “apprentices”,
“journeymen”, “masters” and so on is more than faintly absurd.</p>
</blockquote>
<p>I have <a href="http://tooky.github.com/craftsmanship/eden/2009/11/25/software-craftsmanship.html">recently joined</a> the formal apprenticeship scheme at <a href="http://www.edendevelopment.co.uk">Eden Development</a>, and I wanted to give some perspective of what being an apprentice means to me.</p>
<p>Using terms like “apprentice”, “journeymen” and “master” <strong>is</strong> probably a bit absurd. But its absurd in a good way. <a href="http://c2.com/cgi/wiki?SystemMetaphor">Metaphor</a> is one of the core practices of XP, developing a system metaphor gives a team a shared vision for project. Its not meant to define what the software does, but the language of the metaphor gives the team a way to discuss the system.</p>
<p>The software craftsmanship metaphor gives us shared vision for improving the state of software development. Its not supposed to be new ideas, its just a new way of framing new ideas to give people a common language to use. Calling myself an apprentice allows me to say that I have a lot to learn, that I want to be part of company that is willing to invest in me, if I’m willing to invest in myself.</p>
<p>If I sound absurd when I tell people that, then so be it. It certainly starts the conversation.</p>
Software Craftsmanship and Eden Developmenthttp://tooky.co.uk/software-craftsmanship/2009-11-25T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p>I’m not sure when I first came across <a href="http://en.wikipedia.org/wiki/Software_Craftsmanship">software craftsmanship</a>, but I know that <a href="http://twitter.com/edentodd">Dave Hoover</a>’s early blogs about <a href="http://oreilly.com/catalog/9780596518387">apprenticeship patterns</a> were some of the posts that made it really start to resonate with me!</p>
<p>In 2005 I read one of Dave’s posts - <a href="http://redsquirrel.com/cgi-bin/dave/2005/04/12#a.thread.of.patterns">A Thread of Patterns</a> - and I started to recognise some of these patterns in my own experience. This post prompted me to email Dave and tell him a little of my story.</p>
<p>Reading back over those emails today its striking that I had started to look for a mentor. That I felt that there were serious problems with the way the company I worked for approached software, but I didn’t feel I had the experience to fix those problems, and that I needed to move and take the next step in my career.</p>
<blockquote>
<p>I think one area that your patterns need to touch upon is getting the culture
right. This is an area that I think is making my life more difficult. There
isn’t a culture of developing software in this company. Most of the
programming here is about quick and dirty solutions to solve one time problems
for production.</p>
</blockquote>
<p>This was 2005 - it was two more years before I left that company, and the move I made then didn’t work out the way I hoped. I learnt alot along the way, but have never really found the culture I was looking for.</p>
<p>Fast-forward to today - after 5 months at <a href="http://edendevelopment.co.uk/">Eden Development</a> I feel that I have finally found a company with a culture that I share. The company itself has been on a bit of a <a href="http://blog.edendevelopment.co.uk/2009/10/13/software-craftsmanship-a-meeting-of-minds/">voyage of discovery</a> and growth and I am really excited to be part of its future. Not only did we leave our old office for the first time today, but the company started its new
formal apprenticeship scheme.</p>
<p>I’m pleased to say that I was offered, and have accepted, an Eden Development apprenticeship under the guidance of <a href="http://twitter.com/edentodd">Todd Anderson</a>. I’m excited to see how this program develops, and look forward to sharing my experiences.</p>
UK Apprenticeships and Software Developmenthttp://tooky.co.uk/uk-apprenticeships-and-software-development/2009-09-02T01:00:00+01:002013-12-18T10:29:53+00:00Steve Tooke<p><a href="http://twitter.com/coreyhaines">Corey Haines</a> recently blogged about <a href="http://programmingtour.blogspot.com/2009/09/software-development-school-idea.html">building a software development school</a> and it got me thinking about UK <a href="http://www.apprenticeships.org.uk/Employers/Whats-it-all-about/What-is-an-Apprenticeship.aspx">Apprenticeships</a> and how we could improve the “craft” here in the UK.</p>
<p>UK Apprenticeships (a rebranding of “Modern Apprenticeships” - also known as “Day Release”) is essentially a scheme that combines on and off the job training. They cover a large array of careers but all have the same common principle: apprentices spend most of their time (typically 4-days per week) working in a real business under a mentor, and the remaining time at college studying for a recognised qualification.</p>
<p>According to the <a href="http://www.apprenticeships.org.uk/Employers/Whats-it-all-about/What-is-an-Apprenticeship.aspx">Apprenticeships website</a>) an Apprenticeship is not a qualification itself but a framework containing separately certificated elements.</p>
<p>The Apprenticeship frameworks cover a wide range of <a href="http://www.apprenticeships.org.uk/Types-of-Apprenticeships.aspx">industries</a> including an <a href="http://www.apprenticeships.org.uk/Types-of-Apprenticeships/Information-and-Communication-Technology/ICT-Professional.aspx">ICT Professional apprenticeship</a> - I wonder what it would take to develop a scheme for software developers which would enable UK development workshops to start taking an active role in developing the next generation of software craftsmen?</p>
How I'm going to try to become a better pair.http://tooky.co.uk/how-to-improve-my-pairing/2009-09-02T01:00:00+01:002013-12-18T10:29:53+00:00Steve Tooke<p>I started my new job with <a href="http://www.edendevelopment.co.uk">Eden Development</a> about 2 months ago now. So far its been going great, I’ve been working on an interesting project (which I hope to speak more about soon) with a great team.</p>
<p>One of our core practices at Eden is <a href="http://en.wikipedia.org/wiki/Pair_programming">pair programming</a>, which is something I’ve only had limited experience of in the past, but after 2 months of doing it every day with a variety of people, I’m convinced of its <a href="http://en.wikipedia.org/wiki/Pair_programming#Benefits">merits</a>.</p>
<p>Pairing is hard though. Doing it well is a skill, and because its now something I do every day I want to get better at it. <a href="http://www.markhneedham.com">Mark Needham</a> posted an interesting article on <a href="http://www.markhneedham.com/blog/2009/08/27/pair-programming-observations-on-anti-patterns/">pair programming anti-patterns</a> which I really identified with.</p>
<p>I can definitely recognise the anti-pattern behaviour he describes in my own pairing, and I’ve been frustrated by the same behaviour by my pair!</p>
<p>What I take away from Mark’s post is that effective pairing is really about good communication! You have to let your pair know what your doing and you have to listen to what their saying. </p>
<p>When I’m driving I’m going to try to slow down a little - rather than just diving headlong into solving the problem, and racing around the code I am going to try to spend more time explaining what I’m doing and why I’m doing it.</p>
<p>I’m pretty sure that taking the time to explain my thinking will not only help my pair stay involved but will give us both chance to think about it, and pick up on any potential problems or wrong assumptions.</p>
<p>Hopefully talking more will make it easier for my pair to offer an alternative strategy. If we’ve slowed down, and we’re talking more about the solution its less work to stop and change direction to try an alternative - it feels less like an interruption perhaps.</p>
Simple Old-school webcam using iSightcapture and dropboxhttp://tooky.co.uk/webcam-with-isightcapture-and-dropbox/2009-02-20T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p>I’ve been having a bit of trouble with my shoulder and back for the last couple of weeks - mostly rugby related I think - and I’ve been seeing my osteopath to get it sorted. He suggested that I might be making things worse by the way I’m sitting at my desk. He’s probably right, I think I’m a chronic sloucher. His idea was to get someone at the office to keep an eye on me, or take photos of me every now and again…</p>
<p>Well I didn’t think that sounded too great, so I decided I could just use my macbook pro’s built in iSight to do the job - throw in <a href="http://www.intergalactic.de/pages/iSight.html">isightcapture</a> with a cron job and I have an image of how i’m sitting every 20 mins.</p>
<p>After doing that I couldn’t resist putting up a page with of <a href="/me.html">me</a> with the updated image, in the old-school webcam style. I’m just using dropbox to sync the image to my public folder as it seemed the simplest thing.</p>
Getting started with Cucumber and Sinatrahttp://tooky.co.uk/getting-started-with-cucumber-and-sinatra/2009-02-05T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p><strong>UPDATE</strong> Sinatra and cucumber integration has changed now, Rob Holland updated the <a href="https://github.com/cucumber/cucumber/wiki/sinatra">wiki</a> to reflect it. There is also a more full featured example on his <a href="http://github.com/robholland/cucumber/commit/0e12d8100ca8541af014abe6a480c53a90b6aebd">branch</a> of cucumber. I’ve updated the blog to reflect that.</p>
<p><a href="http://sinatra.github.com">Sinatra</a> is probably the most popular ruby micro web framework at the moment. Its simple dsl for quickly creating web apps, it give you “just enough” framework to get things done.</p>
<p><a href="http://cukes.info">Cucumber</a> is that latest development from the <a href="http://dannorth.net/introducing-bdd">BDD</a> / <a href="http://rspec.info">RSpec</a> guys. <a href="http://cukes.info">Cucumber</a> lets you describe the behaviour of your software in plain text. These files then serve as automated tests and documentation.</p>
<p>I’ve been considering using both of these tools for an upcoming project so I wanted to make sure they worked happily together. A quick google seemed to suggest that some work had been done, but I could find a tutorial for getting up and running. Happily the latest releases of Cucumber (and <a href="http://github.com/brynary/webrat/tree/master">Webrat</a>) have Sinatra support built in so its really very easy!</p>
<p>With cucumber you write your plain text specifications in terms of ‘features’, by convention they are in a features directory with the .feature extension. So for our purposes we will start with a very simple feature:</p>
<pre><code class="highlight plaintext">Feature: view pages
Scenario: Home page
Given I am viewing "/"
Then I should see "Hello, world!
</code></pre>
<p>To run our feature (and test our code against it) is as simple as <code>cucumber feature/home.feature</code>.</p>
<p><img alt="cucumber pending steps" src="https://dl.dropboxusercontent.com/u/41915/tooky-images/cucumber1.png" /></p>
<p>Cucumber parses the feature and looks for matching step definitions. As we can see in the screenshot we need to implement the steps in our feature so cucumber knows how to run it. Step definitions are implemented in ruby.</p>
<pre><code class="highlight plaintext">Given /^I am viewing "(.+)"$/ do |url|
visit(url)
end
Then /^I should see "(.+)"$/ do |text|
response_body.should =~ Regexp.new(Regexp.escape(text))
end
</code></pre>
<p>These two simple steps make use of webrat to request the url from our app and check that the response contains the text we’re looking for.</p>
<p><img alt="cucumber failing without webrat" src="https://dl.dropboxusercontent.com/u/41915/tooky-images/cucumber2.png" /></p>
<p>The feature is currently failing as a method we have used in our step definition doesn’t exist. <code>visit</code> is a method from webrat so we need to configure cucumber’s environment to use webrat. Webrat has a <code>SinatraSession</code> specifically for testing sinatra web apps. We will also need to require the RSpec expectations as we are using them to check the response.</p>
<pre><code class="highlight plaintext">require 'spec/expectations'
require 'webrat'
Webrat.configure do |config|
config.mode = :sinatra
end
World do
Webrat::SinatraSession.new
end
</code></pre>
<p>Running the scenario again, and we see that everything is hooked up properly and the scenario is failing (as expected because we haven’t written any code).</p>
<p><img alt="cucumber failing no code" src="https://dl.dropboxusercontent.com/u/41915/tooky-images/cucumber3.png" /></p>
<p>Now we have our failing scenario we can start putting together our web app and make sure we’re running with a green light!</p>
<pre><code class="highlight plaintext">require 'sinatra'
get '/' do
"Hello, world!"
end
</code></pre>
<p>Now if we run out scenario again unfortunately it still fails, we need to hook cucumber up to our app.</p>
<pre><code class="highlight plaintext">require 'spec/expectations'
require 'webrat'
Webrat.configure do |config|
config.mode = :sinatra
end
World do
Webrat::SinatraSession.new
end
require File.dirname(__FILE__) + '/../../hello''
</code></pre>
<p>Finally running cucumber gives us that nice green feeling.</p>
<p><img alt="green cucumber" src="https://dl.dropboxusercontent.com/u/41915/tooky-images/cucumber4.png" /></p>
<p>The only thing left to do is to add a rake file to run our features for us.</p>
<pre><code class="highlight plaintext">require 'rubygems'
require 'cucumber/rake/task'
Cucumber::Rake::Task.new(:features) do |t|
t.cucumber_opts = "--format pretty"
end
</code></pre>
<p><img alt="rake features" src="https://dl.dropboxusercontent.com/u/41915/tooky-images/cucumber5.png" /></p>
<p>All of the code for this getting started guide is available from <a href="http://gist.github.com/58647">gist</a>.</p>
GitHub Pages and Jekyllhttp://tooky.co.uk/github-pages-and-jekyll/2008-12-18T00:00:00+00:002013-12-18T10:29:53+00:00Steve Tooke<p><a href="http://github.com">GitHub’s</a> new GitHub pages service makes it incredibly easy to host a static site, which is completely version controlled, when you add <a href="http://mojombo.github.com">Tom Preston-Werner’s</a> <a href="http://github.com/mojombo/jekyll">Jekyll</a> into the mix you get a fantastically simple blogging platform.</p>
<p>To set up your github pages site all you need to do is create a [username].github.com repository and push your site to the repository. Really simple. Checkout <a href="http://you.github.com">you.github.com</a> for more detailed instructions!</p>
<p>The great thing about this is that <a href="http://github.com">GitHub</a> run your repository through <a href="http://github.com/mojombo/jekyll/tree/master">Jekyll</a>. This means that you can create a really simple blogging platform with all your posts stored and version controlled in git! See <a href="http://mojombo.github.com/2008/11/17/blogging-like-a-hacker.html">Blogging Like a Hacker</a> for more details.</p>
<p>Tom has also published his <a href="http://github.com/mojombo/tpw/tree/master">repository</a> to help you get started as well.</p>
<p>Many thanks to Tom for all of this, I’ve managed to put together a nice simple clean site based on his ideas, which I’m really pleased with!</p>