<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>blog dot voxdolo dot me</title>
 <link href="http://blog.voxdolo.me/atom.xml" rel="self"/>
 <link href="http://blog.voxdolo.me/"/>
 <updated>2010-09-22T09:01:45-07:00</updated>
 <id>http://blog.voxdolo.me</id>
 <author>
   <name>Stephen Caudill</name>
   <email>voxdolo@me.com</email>
 </author>

 
 <entry>
   <title>Remote Pairing with Vim and TMux</title>
   <link href="http://blog.voxdolo.me/remote-pairing-with-vim-and-tmux.html"/>
   <updated>2010-09-21T00:00:00-07:00</updated>
   <id>http://blog.voxdolo.me/remote-pairing-with-vim-and-tmux</id>
   <content type="html">&lt;p&gt;While it&amp;#8217;s always best to pair program side-by-side with your pair, it&amp;#8217;s not always feasible. Over the last couple of weeks, &lt;a href='http://twitter.com/jremsikjr'&gt;Jim Remsik&lt;/a&gt; and I needed to pair on a new project, but circumstances dictated that he be elsewhere.&lt;/p&gt;

&lt;h2 id='whats_a_pair_to_do'&gt;What&amp;#8217;s a Pair to Do?&lt;/h2&gt;

&lt;p&gt;Keep right on pairing, of course. We just had to figure out how. Our requirements were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Collaborative Editing&lt;/strong&gt;: the fundament of pairing, both people need to be able to type into the same editor.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Access to the Local Server&lt;/strong&gt;: it&amp;#8217;s pretty hard to develop an app you can&amp;#8217;t see.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Ease of Communication&lt;/strong&gt;: we need to be able to hear each other, preferably seeing each other as well (there&amp;#8217;s a lot of nonverbal communication when pairing).&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Light Weight&lt;/strong&gt;: the internet connections would be of variable quality, so we required something that wouldn&amp;#8217;t tax small pipes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We&amp;#8217;d previously used iChat Screen Sharing when we needed to do this at &lt;a href='http://www.hashrocket.com'&gt;Hashrocket&lt;/a&gt;&amp;#8230; it works great for numbers 1 and 2, gets us half way to number 3, but falls over entirely on number 4. The lag from sending so much data over the network starts out as merely grating, but quickly crescendos in abject frustration, tending to make the client of the pairing session little more than an observer.&lt;/p&gt;

&lt;p&gt;Given that, the no-brainer for us was to use &lt;a href='http://www.vim.org'&gt;Vim&lt;/a&gt; inside a terminal-multiplexer that allowed multiple client connections, so we could attach to the session over SSH. That&amp;#8217;d get us &amp;#8220;Collaborative Editing&amp;#8221;, but what about the other requirements? After a bit of discussion, we decided we could solve numbers 2 and 4 by forwarding port 3000 of the host machine to the client attaching via SSH. Being that this was such a lightweight solution, we opted for &lt;a href='http://www.skype.com'&gt;Skype&lt;/a&gt; (our communications weapon of choice) for video chat.&lt;/p&gt;

&lt;p&gt;Our initial permutation involved opening a port in our SonicWALL firewall and manually forwarding the port to a machine inside the firewall with a static IP. This worked great, after the initial pain of configuring SonicWALL (which is, in my estimation, a FPOS). The shortcoming here is that we didn&amp;#8217;t want to have to open up a port for every station we wanted to remote-pair from (some days Hashrocket is an elaborate game of musical chairs). &lt;a href='http://tpo.pe'&gt;tpope&lt;/a&gt; came to the rescue with his recommendation for using the &lt;code&gt;ProxyCommand&lt;/code&gt; option for SSH.&lt;/p&gt;

&lt;p&gt;Enough background.&lt;/p&gt;

&lt;h2 id='pairing_down_the_configuration'&gt;Pairing Down the Configuration&lt;/h2&gt;

&lt;p&gt;The configuration we used makes several assumptions about your network&amp;#8217;s environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At least one machine in your network is available at a public IP&lt;/li&gt;

&lt;li&gt;The externally available machine understands &lt;a href='http://www.multicastdns.org'&gt;MDNS&lt;/a&gt; (e.g. Bonjour)&lt;/li&gt;

&lt;li&gt;The other machines on your network are available via MDNS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That said, it should be relatively easy to modify this to work with a direct peer-to-peer connection (provided the host has a routable IP address). If you&amp;#8217;re so inclined, please contribute in the comments below.&lt;/p&gt;

&lt;h3 id='id1'&gt;&lt;code&gt;.ssh/config&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;You&amp;#8217;ll need an entry for the machine you&amp;#8217;re tunneling into, ours looks like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;  Host tunnels
    Hostname 0.0.0.0 &lt;span class='c'&gt;# this should be an externally routable address&lt;/span&gt;
    User your_user
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now here&amp;#8217;s the magic:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;  Host *.hashrocket &lt;span class='c'&gt;#*&lt;/span&gt;
    User your_user
    ProxyCommand ssh -ax tunnels nc &lt;span class='sb'&gt;`&lt;/span&gt;&lt;span class='nb'&gt;echo&lt;/span&gt; %h|sed -e &lt;span class='s1'&gt;&amp;#39;s/\.hashrocket$/.local/&amp;#39;&lt;/span&gt;&lt;span class='sb'&gt;`&lt;/span&gt; %p 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Let me attempt to unravel what this is doing. &lt;code&gt;ProxyCommand&lt;/code&gt; allows you to specify a command to use to connect to the host machine. In our case, we&amp;#8217;re doing a wildcard match on anything at &lt;code&gt;.hashrocket&lt;/code&gt;, the actual match is then used to figure out how to route the request inside the network. So in our case, tunneling to &lt;code&gt;fry.hashrocket&lt;/code&gt; gets us to our tunnels machine, then we use netcat to echo the given command to &lt;code&gt;fry.local&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Which brings us to the actual forwarding command:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;  $ ssh fry.hashrocket -L 3000:localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This drops us into a shell on &lt;code&gt;fry.local&lt;/code&gt; and establishes the reverse tunnel, forwarding &lt;code&gt;localhost:3000&lt;/code&gt; on the host to &lt;code&gt;localhost:3000&lt;/code&gt; on the client machine.&lt;/p&gt;

&lt;h3 id='tmux'&gt;tmux&lt;/h3&gt;

&lt;p&gt;If you&amp;#8217;re interested in why we chose &lt;a href='http://tmux.sourceforge.net'&gt;&lt;code&gt;tmux&lt;/code&gt;&lt;/a&gt; over &lt;a href='http://www.gnu.org/software/screen'&gt;&lt;code&gt;gnu
screen&lt;/code&gt;&lt;/a&gt;, I&amp;#8217;ll first refer you to the &lt;a href='http://tmux.cvs.sourceforge.net/viewvc/tmux/tmux/FAQ'&gt;&lt;code&gt;tmux&lt;/code&gt; FAQ&lt;/a&gt; and subsequently admit that I went with it primarily because it&amp;#8217;s newer and shinier. You could easily substitute &lt;code&gt;screen&lt;/code&gt; for &lt;code&gt;tmux&lt;/code&gt; here, though my opinion after a few weeks use is that it&amp;#8217;s much more intuitive and I won&amp;#8217;t be making the move back.&lt;/p&gt;

&lt;p&gt;The relevant commands for creating and attaching to a new session follow. On the host, you&amp;#8217;ll need to create a session:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;  $ tmux new -s mysession&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;On the client, you&amp;#8217;ll need to attach to that session:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='console'&gt;&lt;span class='go'&gt;  $ tmux attach -t mysession&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Once you&amp;#8217;re connected, you&amp;#8217;ll need to run Vim (or some other terminal-friendly editor, e.g. emacs, sorry TextMate people) in a window or pane. We opted to run Terminal full screen on an iMac, with two panes arranged vertically; a shell session in one, Vim in the other and new windows for long-running processes or utility shells.&lt;/p&gt;

&lt;h3 id='id2'&gt;&lt;code&gt;tmux.conf&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;We&amp;#8217;re Vimtarded, so putting the following in &lt;code&gt;~/.tmux.conf&lt;/code&gt; made us feel a bit more homey:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;  setw -g mode-keys vi

  &lt;span class='nb'&gt;bind &lt;/span&gt;h &lt;span class='k'&gt;select&lt;/span&gt;-pane -L
  &lt;span class='nb'&gt;bind &lt;/span&gt;j &lt;span class='k'&gt;select&lt;/span&gt;-pane -D
  &lt;span class='nb'&gt;bind &lt;/span&gt;k &lt;span class='k'&gt;select&lt;/span&gt;-pane -U
  &lt;span class='nb'&gt;bind &lt;/span&gt;l &lt;span class='k'&gt;select&lt;/span&gt;-pane -R
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The initial configuration puts navigation commands in Vim mode (you&amp;#8217;ll see this in copy mode, the help screen, etc). The custom bindings below that make navigating the panes within a window work like navigating splits in Vim.&lt;/p&gt;

&lt;h3 id='_crash_course'&gt;&lt;code&gt;tmux&lt;/code&gt; crash course&lt;/h3&gt;

&lt;p&gt;The default binding for the command mode is &lt;code&gt;ctrl-b&lt;/code&gt;. We will refer to it as &lt;code&gt;&amp;lt;command&amp;gt;&lt;/code&gt; hereafter. &lt;code&gt;&amp;lt;command&amp;gt;-d&lt;/code&gt; means: &lt;code&gt;ctrl-b&lt;/code&gt;, then &amp;#8216;d&amp;#8217;.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;  &amp;lt;&lt;span class='nb'&gt;command&lt;/span&gt;&amp;gt;-d &lt;span class='c'&gt;# detach from current session&lt;/span&gt;
  &amp;lt;&lt;span class='nb'&gt;command&lt;/span&gt;&amp;gt;-&lt;span class='err'&gt;&amp;quot;&lt;/span&gt; &lt;span class='c'&gt;# split window into panes horizontally&lt;/span&gt;
  &amp;lt;&lt;span class='nb'&gt;command&lt;/span&gt;&amp;gt;-% &lt;span class='c'&gt;# split window into panes vertically&lt;/span&gt;
  &amp;lt;&lt;span class='nb'&gt;command&lt;/span&gt;&amp;gt;-o &lt;span class='c'&gt;# go to next pane&lt;/span&gt;
  &amp;lt;&lt;span class='nb'&gt;command&lt;/span&gt;&amp;gt;-x &lt;span class='c'&gt;# close current pane&lt;/span&gt;
  &amp;lt;&lt;span class='nb'&gt;command&lt;/span&gt;&amp;gt;-? &lt;span class='c'&gt;# display available keybindings&lt;/span&gt;
  &amp;lt;&lt;span class='nb'&gt;command&lt;/span&gt;&amp;gt;-c &lt;span class='c'&gt;# create a new window&lt;/span&gt;
  &amp;lt;&lt;span class='nb'&gt;command&lt;/span&gt;&amp;gt;-n &lt;span class='c'&gt;# go to next window&lt;/span&gt;
  &amp;lt;&lt;span class='nb'&gt;command&lt;/span&gt;&amp;gt;-p &lt;span class='c'&gt;# go to next window&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='pairing_is_such_suite_sorrow'&gt;Pairing is Such Suite Sorrow&lt;/h2&gt;

&lt;p&gt;So now we&amp;#8217;re editing text together, we&amp;#8217;re looking at &lt;code&gt;localhost&lt;/code&gt; on each end, we&amp;#8217;re running some specs, writing some cucumbers, everything&amp;#8217;s perfect. Until you need to &lt;code&gt;save_and_open_page&lt;/code&gt;. You have two options: never make any errors &lt;em&gt;or&lt;/em&gt; move those files somewhere that your pair can see them too.&lt;/p&gt;

&lt;p&gt;Since we&amp;#8217;ve yet to be issued our Ninja-Passes, we opted for the latter and since we&amp;#8217;re using &lt;a href='http://github.com/jnicklas/capybara'&gt;Capybara&lt;/a&gt;, we did it like so:&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;features/support/env.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='no'&gt;Capybara&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;save_and_open_page_path&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;public/tmp&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Awesome, now they can just browse to &lt;code&gt;http://localhost:3000/tmp&lt;/code&gt; and see Capybara temp pages! That is, if they can guess the name of them, or want to &lt;code&gt;ls&lt;/code&gt; the directory, copy the name of the last file and paste it into the browser.&lt;/p&gt;

&lt;p&gt;That &lt;em&gt;would&lt;/em&gt; work, but how about this instead:&lt;/p&gt;

&lt;p&gt;At the bottom of &lt;code&gt;config/routes.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='no'&gt;Rails&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;env&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;development?&lt;/span&gt;
    &lt;span class='no'&gt;Some&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Application&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;routes&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;draw&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;match&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;tmp/(:action)&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:controller&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;tmp&amp;#39;&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;app/controllers/tmp_controller.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;TmpController&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;ApplicationController&lt;/span&gt;
    &lt;span class='n'&gt;expose&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:temp_pages&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='no'&gt;Dir&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;glob&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;File&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;public&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;tmp&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;capybara-*&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;latest&lt;/span&gt;
      &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='n'&gt;temp_pages&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;last&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:layout&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='kp'&gt;false&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Adding an index view would be trivial if you needed to look at more than just the latest one&lt;sup id='fnref:1'&gt;&lt;a href='#fn:1' rel='footnote'&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h2 id='the_pair_stare'&gt;The Pair Stare&lt;/h2&gt;

&lt;p&gt;As a side-note, we did use Skype to video chat as our primary means of communication. Jim claims that the best part of it was that I Skyped from my machine (a 13&amp;#8221; MBP, with my iPhone headset) and hosted the &lt;code&gt;tmux&lt;/code&gt; session on the iMac right beside it. This had the unintended side effect of me not &amp;#8220;staring at him&amp;#8221; all day long while I coded. It&amp;#8217;s the little things that make all the difference :)&lt;/p&gt;

&lt;h2 id='check_out_the_pair_on_this_guy'&gt;Check Out The Pair On This Guy&lt;/h2&gt;

&lt;p&gt;While my brief stint of remote pairing has come to a close, I&amp;#8217;ve no doubt I&amp;#8217;ll need to do it again at some point in the future and am interested in refining this process. So please, if you can think of a way to improve on or simplify any of this, leave a note in the comments!&lt;/p&gt;
&lt;div class='footnotes'&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li id='fn:1'&gt;
&lt;p&gt;Curious about that &lt;code&gt;expose&lt;/code&gt; method? Check out &lt;a href='http://github.com/voxdolo/decent_exposure'&gt;decent_exposure&lt;/a&gt;.&lt;/p&gt;
&lt;a href='#fnref:1' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>A Diatribe on Maintaining State</title>
   <link href="http://blog.voxdolo.me/a-diatribe-on-maintaining-state.html"/>
   <updated>2010-09-03T00:00:00-07:00</updated>
   <id>http://blog.voxdolo.me/a-diatribe-on-maintaining-state</id>
   <content type="html">&lt;h2 id='tldr'&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;If you&amp;#8217;re interacting directly with an instance variable and it&amp;#8217;s not inside an accessor or mutator method, you&amp;#8217;re breaking encapsulation and promoting close coupling in the design of your object system. Just because an API encourages this behavior doesn&amp;#8217;t mean that it&amp;#8217;s a good design practice (see &lt;a href='http://vurl.me/UBO' title='Specifically, the bit about making instance   variables from controllers available to the view.'&gt;Rails&lt;/a&gt; for a great example of enshrining this bad habit).&lt;/p&gt;

&lt;h2 id='the_discourse_proper'&gt;The Discourse Proper&lt;/h2&gt;

&lt;p&gt;An object instance, while resident in memory, must have somewhere to store its state. In Ruby (as in most languages), the instance variable is our go-to guy. It&amp;#8217;s so useful and its usage is so universally understood, in fact, that many people don&amp;#8217;t look much further than it when determining how to store and subsequently access state.&lt;/p&gt;

&lt;h3 id='a_common_approach'&gt;A Common Approach&lt;/h3&gt;

&lt;p&gt;Let&amp;#8217;s look at an example of an approach where we directly interact with state stored in an instance variable:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Message&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='vi'&gt;@body&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;to_html&lt;/span&gt;
      &lt;span class='vi'&gt;@body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gsub&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sr'&gt;/\n/&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;#8217;ve got some state, I initialize my object with it, and I later access it. Clearly, this code isn&amp;#8217;t the worst thing that has ever happened to the software world. In this simple example, it&amp;#8217;s largely forgivable to use an approach like this.&lt;/p&gt;

&lt;p&gt;The first principle from &lt;a href='http://vurl.me/UBP' title='The Wikipedia entry on the classic work.'&gt;&lt;em&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/em&gt;&lt;/a&gt; is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Program to an interface, not an implementation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or as I like to dramatize it:&lt;/p&gt;
&lt;q&gt;If you're not programming to an interface, you're coupling with an
implementation.&lt;/q&gt;
&lt;p&gt;When consuming code (be it your own or someone else&amp;#8217;s) in an Object-Oriented system the thing we are meant to be concerned with is the state of the object itself. To wit: the fact that an object&amp;#8217;s state is (or isn&amp;#8217;t) stored in an instance variable, should be a detail of the implementation.&lt;/p&gt;

&lt;h3 id='an_important_nuance'&gt;An Important Nuance&lt;/h3&gt;

&lt;p&gt;People tend to think of APIs in terms of how they&amp;#8217;re consumed externally. It&amp;#8217;s equally important to consume them internally. Let&amp;#8217;s add the requirement that our &lt;code&gt;Message&lt;/code&gt; object must remove leading, trailing and repetitive space.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Message&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='vi'&gt;@body&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;squeeze&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strip&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;to_html&lt;/span&gt;
      &lt;span class='vi'&gt;@body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gsub&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sr'&gt;/\n/&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Still a very straightforward implementation, but we start to see a lack of &lt;a href='http://vurl.me/UBQ' title='The Wikipedia entry on Cohesion'&gt;cohesion&lt;/a&gt; here as the initializer is now responsible for both storing and manipulating this state. We have yet to declare an interface though, so there&amp;#8217;s really little recourse at this point.&lt;/p&gt;

&lt;h3 id='refactoring_to_an_interface'&gt;Refactoring To An Interface&lt;/h3&gt;

&lt;p&gt;I mentioned earlier that interacting directly with instance variables is largely forgivable in the simple case. That is not to be confused with an endorsement. Ruby makes it so simple to abstract away state maintenance, that it feels irresponsible not to. Here&amp;#8217;s how we might refactor that given our previous case:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Message&lt;/span&gt;
    &lt;span class='kp'&gt;attr_reader&lt;/span&gt; &lt;span class='ss'&gt;:body&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;body&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='vi'&gt;@body&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;squeeze&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strip&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;to_html&lt;/span&gt;
      &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gsub&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sr'&gt;/\n/&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;With this factoring, we need never know that our state has been stored in that instance variable. It becomes a detail of the implementation. Additionally, we&amp;#8217;ve moved the responsibility for cleaning up the excess whitespace in the message body into the setter.&lt;/p&gt;

&lt;p&gt;Now that we&amp;#8217;ve declared an interface, it becomes significantly easier to make substantial refactors, such as upgrading your state maintenance to allow for persistence:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Message&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;body&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='n'&gt;cache&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:body&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;squeeze&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strip&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;body&lt;/span&gt;
      &lt;span class='n'&gt;cache&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:body&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;to_html&lt;/span&gt;
      &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gsub&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sr'&gt;/\n/&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='kp'&gt;private&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;cache&lt;/span&gt;
      &lt;span class='vi'&gt;@cache&lt;/span&gt; &lt;span class='o'&gt;||=&lt;/span&gt; &lt;span class='no'&gt;PStore&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;message_cache.pstore&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Here we begin to see advantages of declaring an interface. By defining an interface, you effectively declare the &amp;#8220;surface area&amp;#8221; of your internal API. This also goes a long way toward making methods that are both atomic and highly cohesive.&lt;/p&gt;

&lt;p&gt;This example is still very simple. In interest of fairness, an equivalent &lt;code&gt;class&lt;/code&gt; (assuming you only really care about the value of &lt;code&gt;to_html&lt;/code&gt;) which employs direct access to instance variables might be within your threshold of acceptable use:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Message&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='vi'&gt;@cache&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;PStore&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;message_cache.pstore&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='vi'&gt;@cache&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:body&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;squeeze&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strip&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;to_html&lt;/span&gt;
      &lt;span class='vi'&gt;@cache&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:body&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gsub&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sr'&gt;/\n/&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Given the simplicity (and brevity) of this implementation, why is there any issue with this approach? At this scale, there probably isn&amp;#8217;t. The previous objection to this approach regarding the ease of declaring an interface in Ruby still stands, but it&amp;#8217;s truly not until the software system exists at a sufficient level of complexity that you&amp;#8217;ll start to experience the detriment of this approach.&lt;/p&gt;

&lt;h3 id='a_slightly_more_complex_use_case'&gt;A Slightly More Complex Use Case&lt;/h3&gt;

&lt;p&gt;Let&amp;#8217;s add support for finding and storing multiple &lt;code&gt;Message&lt;/code&gt; object instances.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Message&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='n'&gt;cache&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;PStore&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;message_cache.pstore&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='kp'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;cache&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='p'&gt;})&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='vi'&gt;@cache&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;PStore&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;message_cache.pstore&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='vi'&gt;@id&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;id&lt;/span&gt;
      &lt;span class='vi'&gt;@cache&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='vi'&gt;@id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;squeeze&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strip&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;save&lt;/span&gt;
      &lt;span class='vi'&gt;@cache&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='vi'&gt;@id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@body&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;to_html&lt;/span&gt;
      &lt;span class='vi'&gt;@body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gsub&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sr'&gt;/\n/&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now let&amp;#8217;s see what that might look like when declaring an interface:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;Message&lt;/span&gt;
    &lt;span class='kp'&gt;attr_reader&lt;/span&gt; &lt;span class='ss'&gt;:body&lt;/span&gt;
    &lt;span class='kp'&gt;attr_accessor&lt;/span&gt; &lt;span class='ss'&gt;:id&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='kp'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;cache&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='p'&gt;})&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;initialize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;id&lt;/span&gt;
      &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;body&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='vi'&gt;@body&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;squeeze&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strip&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;to_html&lt;/span&gt;
      &lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;gsub&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sr'&gt;/\n/&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;save&lt;/span&gt;
      &lt;span class='nb'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;class&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;cache&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;transaction&lt;/span&gt;&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='nb'&gt;id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;body&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='kp'&gt;private&lt;/span&gt;
    &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nc'&gt;self&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='nf'&gt;cache&lt;/span&gt;
      &lt;span class='vi'&gt;@cache&lt;/span&gt; &lt;span class='o'&gt;||=&lt;/span&gt; &lt;span class='no'&gt;PStore&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;message_cache.pstore&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='analyzing_the_implementations'&gt;Analyzing The Implementations&lt;/h3&gt;

&lt;p&gt;In the first example, you end up with some some incidental coupling in the initializer. It takes on the responsibility for assigning internal attributes, manipulating them where necessary, as well as initializing a persistent reference to the cache itself. Additionally, there&amp;#8217;s no ability to manipulate the state of an instantiated object, so another object interacting with an instance of &lt;code&gt;Message&lt;/code&gt; wouldn&amp;#8217;t be able to change the value of its &lt;code&gt;@body&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Conversely, the implementation which has declared an interface is ready to behave as a good citizen within an object system. It allows other objects to interact with it at all stages of its life cycle in a specified fashion (it has declared its &amp;#8220;surface area&amp;#8221;). It retains atomicity and expresses no signs of coupling.&lt;/p&gt;

&lt;p&gt;Another notion that I haven&amp;#8217;t addressed is that of Code Beauty. This is an entirely subjective topic, but I contend that a well-specified interface creates more beautiful code. I&amp;#8217;ll leave that to you to decide, but I think the examples do a fair job of showing this.&lt;/p&gt;

&lt;h2 id='wrapping_up'&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;This is such a simple topic that it&amp;#8217;s easy to take for granted. To reiterate: the issues with accessing instance variables directly become most obvious when a software system attains some basic scale and complexity. Generally speaking, once objects in a system begin to interact in any significant manner, the coupling created by not specifying and adhering to an interface starts to become clear. This coupling makes it more difficult to adhere to &lt;a href='http://vurl.me/UBR' title='The Wikipedia entry on the Single Responsiblity   Principle'&gt;Single Responsibility Principle&lt;/a&gt;, which subsequently increases rigidity.&lt;/p&gt;

&lt;p&gt;The intended takeaway is that you can improve the overall design of your software system at every stage of its evolution by specifying and adhering to an interface. One simple way you can do that is to ensure that you&amp;#8217;re not manipulating state maintained in instance variables directly.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Gibbon</title>
   <link href="http://blog.voxdolo.me/gibbon.html"/>
   <updated>2009-10-10T00:00:00-07:00</updated>
   <id>http://blog.voxdolo.me/gibbon</id>
   <content type="html">&lt;p&gt;At &lt;a href='http://www.hashrocket.com/'&gt;work&lt;/a&gt;, I&amp;#8217;ve recently been downplaying the importance of &lt;a href='http://gist.github.com/206969'&gt;Gibbon&lt;/a&gt; being distributed as a library, since I don&amp;#8217;t really think it&amp;#8217;s the code that&amp;#8217;s important&amp;#8230; the technique is where it&amp;#8217;s at. As such, I&amp;#8217;m not going to give the &lt;a href='http://gist.github.com/206969'&gt;hack&lt;/a&gt; itself or its &lt;a href='http://gist.github.com/190739'&gt;configuration&lt;/a&gt; any stage time in order to jump in and talk about how to use it and what its limitations are.&lt;/p&gt;

&lt;h2 id='monkeying_around'&gt;Monkeying Around&lt;/h2&gt;

&lt;p&gt;By and large, Gibbon&amp;#8217;s syntax apes &lt;a href='http://cukes.info'&gt;Cucumber&lt;/a&gt;&amp;#8217;s take on &lt;a href='http://wiki.github.com/aslakhellesoy/cucumber/given-when-then'&gt;Given/When/Then Templates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are, however, some gotcha&amp;#8217;s and limitations and that&amp;#8217;s what I&amp;#8217;d like to focus on. Let&amp;#8217;s start off with an example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='no'&gt;Feature&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;A Tomatoist does a pomodoro&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='no'&gt;Story&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class='no'&gt;eos&lt;/span&gt;
&lt;span class='sh'&gt;    In order to perform a focused unit of work&lt;/span&gt;
&lt;span class='sh'&gt;    As a Tomatoist&lt;/span&gt;
&lt;span class='sh'&gt;    I want to start a pomodoro&lt;/span&gt;
&lt;span class='no'&gt;    eos&lt;/span&gt;

    &lt;span class='no'&gt;Scenario&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Starting a pomodoro&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='no'&gt;When&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;I go to the home page&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
        &lt;span class='n'&gt;executes&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;visit&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='no'&gt;Then&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;I should be sent to a new session&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;current_url&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;=~&lt;/span&gt; &lt;span class='sr'&gt;/\/\w{3,}/&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='no'&gt;And&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;I should see an unstarted timer&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;#timer .countdown_row&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;00:00&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='no'&gt;And&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;I should see a pomdoro button&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;input[type=submit][value=?]&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;Pomdoro&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='no'&gt;When&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;I click the pomodoro button&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;executes&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='vi'&gt;@session_url&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;current_url&lt;/span&gt;
            &lt;span class='n'&gt;click_button&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Pomodoro&amp;#39;&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

          &lt;span class='no'&gt;Then&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;I should be on my session&amp;#39;s page&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='n'&gt;current_url&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='vi'&gt;@session_url&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

          &lt;span class='no'&gt;And&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;my timers should have been initialized&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;#timer .countdown_row&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;25:00&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

          &lt;span class='no'&gt;And&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;my timer history should show the current pomdoro&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;#history ul li&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='sr'&gt; /Pomodoro/&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;

          &lt;span class='no'&gt;And&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;the pomodoro button should be highlighted&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
            &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;have_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;form.current input[type=submit][value=?]&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;Pomdoro&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
          &lt;span class='k'&gt;end&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And here&amp;#8217;s what the output of that feature looks like using RSpec&amp;#8217;s built in &lt;code&gt;nested&lt;/code&gt; formatter:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;A Tomatoist does a pomodoro
  In order to perform a focused unit of work
  As a Tomatoist
  I want to start a pomodoro

  Scenario: Starting a pomodoro
    When I go to the home page
      Then I should be sent to a new session
      And I should see an unstarted timer
      And I should see a pomdoro button
      When I click the pomodoro button
        Then I should be on my session&amp;#39;s page
        And my timers should have been initialized
        And my timer history should show the current pomdoro
        And the pomodoro button should be highlighted&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='flinging_poo'&gt;Flinging Poo&lt;/h2&gt;

&lt;p&gt;There are a couple of things you should note about the syntax straight off:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It&amp;#8217;s verbose.&lt;/li&gt;

&lt;li&gt;It relies heavily on nesting (sometimes in ways that feel awkward).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It&amp;#8217;s also noteworthy that the primary means of interrogating the response is through either the &lt;code&gt;have_tag&lt;/code&gt; matchers or using something like &lt;code&gt;contain&lt;/code&gt; to look for text. This is not necessarily a bad thing, but it can lead quickly to close coupling unless you are constantly vigilant. I&amp;#8217;m still mulling this aspect over, but as it stands, I haven&amp;#8217;t thought of a better way to handle it.&lt;/p&gt;

&lt;h2 id='monkey_wrenches'&gt;Monkey wrenches&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ve talked some to &lt;a href='http://www.tpope.net/'&gt;Tim Pope&lt;/a&gt; about Gibbon, since he&amp;#8217;s a big fan of Cucumber driven development. His criticism, in a nutshell, is that the English text is not executable. He asserts that Cucumber keeps you honest by actually mapping the text to executable code. This is definitely valid; I frequently make the same argument about comments: &amp;#8220;they&amp;#8217;re lies waiting to happen&amp;#8221;. It&amp;#8217;s only a matter of time &amp;#8216;til they become stale and the code itself is more recent. I would argue though, that Cucumber only separates you from that same fate by virtue of the author&amp;#8217;s diligence.&lt;/p&gt;

&lt;p&gt;Tackling the problem of example descriptions diverging from implementation from the opposite direction is &lt;a href='http://onestepback.org/'&gt;Jim Weirich&lt;/a&gt;&amp;#8217;s recent entry into this field, &lt;a href='http://github.com/jimweirich/Given'&gt;Given&lt;/a&gt;. Given eshew&amp;#8217;s explanatory text altogether, preferring to let the code speak for itself. Now we&amp;#8217;re talking! Combine that with something like &lt;a href='http://blog.citrusbyte.com/2009/05/20/stories/'&gt;Stories&lt;/a&gt;&amp;#8217; ability to convert code to plain English for output and you&amp;#8217;d have a really nice offering. What this solution still lacks though is the facility of RSpec&amp;#8217;s matchers, as Given is built on top of Test::Unit (as is Stories).&lt;/p&gt;

&lt;h2 id='monkey_gone_to_heaven'&gt;Monkey Gone to Heaven&lt;/h2&gt;

&lt;p&gt;For now, I&amp;#8217;ll be sticking with Gibbon, since it provides me access to RSpec&amp;#8217;s matchers, is crazy simple and gives me pretty much everything I require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expressing business value using Given/When/Then templates&lt;/li&gt;

&lt;li&gt;English language output for deliverables&lt;/li&gt;

&lt;li&gt;Access to RSpec&amp;#8217;s matchers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&amp;#8217;d love to hear from you in the comments about what your experience is with integration testing in general and how you&amp;#8217;re scratching that itch these days.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>You Say Tomato</title>
   <link href="http://blog.voxdolo.me/you-say-tomato.html"/>
   <updated>2009-10-05T00:00:00-07:00</updated>
   <id>http://blog.voxdolo.me/you-say-tomato</id>
   <content type="html">&lt;h2 id='i_say_pomodoro'&gt;I say Pomodoro!&lt;/h2&gt;

&lt;p&gt;After a significant amount of time and effort and the gracious help of several contributors, I&amp;#8217;m proud to officially announce &lt;a href='http://tomatoi.st/'&gt;tomatoi.st&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id='for_those_in_a_hurry'&gt;For those in a hurry&lt;/h3&gt;

&lt;p&gt;&lt;a href='http://tomatoi.st/'&gt;tomatoi.st&lt;/a&gt; is a simple timer application that helps you implement the &lt;a href='http://www.pomodorotechnique.com/'&gt;Pomodoro Technique&lt;/a&gt;. You should totally use it.&lt;/p&gt;

&lt;h3 id='the_story'&gt;The Story&lt;/h3&gt;

&lt;p&gt;While pairing with &lt;a href='http://www.coreygrusden.com/'&gt;Corey Grusden&lt;/a&gt; a few months ago, we decided to experiment with the &lt;a href='http://www.pomodorotechnique.com/'&gt;Pomodoro Technique&lt;/a&gt;. We immediately found that it helped improve our productivity and fight off project fatigue. Plus it gave Corey some officially sanctioned time in which to deal with his digital logorrhea (SMS much?). Needless to say, we were hooked!&lt;/p&gt;

&lt;p&gt;The immediate hurdle was that the software available for doing the timing was lackluster (fwiw, &lt;a href='http://github.com/rubyist/tomato'&gt;decent software&lt;/a&gt; has since been developed). In light of this, we spent the first few days working with a simple &lt;code&gt;sleep 1500 &amp;amp;&amp;amp;
growlnotify&lt;/code&gt; type solutioni which was inelegant at best. More importantly, it was missing an utterly essential piece of functionality: the ability to start a timer at my desk, go to the john, and check up on the time left in a break whilst on the throne!&lt;/p&gt;

&lt;p&gt;And so, in pursuit of this lofty goal, &lt;a href='http://tomatoi.st/'&gt;a tomato&lt;/a&gt; was born.&lt;/p&gt;

&lt;h3 id='what_it_does'&gt;What it does&lt;/h3&gt;

&lt;p&gt;&lt;a href='http://tomatoi.st/'&gt;tomatoi.st&lt;/a&gt; does very little, but we like to think it does it very well. &lt;em&gt;ahem&lt;/em&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;a href='http://tomatoi.st/'&gt;http://tomatoi.st&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;Click the &amp;#8220;Pomodoro&amp;#8221; button&lt;/li&gt;

&lt;li&gt;Start a focused unit of work&lt;/li&gt;

&lt;li&gt;When you hear the &amp;#8220;ding!&amp;#8221;, click &amp;#8220;Short Break&amp;#8221;&lt;/li&gt;

&lt;li&gt;Take a break, go to the john, whatever&lt;/li&gt;

&lt;li&gt;Rinse and repeat&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is suggested that you do 4 sets of Pomodoros. The first three are followed by a short break, the last by a long one. &lt;a href='http://tomatoi.st/'&gt;tomatoi.st&lt;/a&gt; makes the assumption that you&amp;#8217;ll be doing them in that order and handily suggests the next timer you should do by highlighting it&amp;#8217;s button in green when the previous timer expires. Your current timer is highlighted in yellow while it&amp;#8217;s underway and then red once it&amp;#8217;s expired. Your timer history is tracked just below the big ticker.&lt;/p&gt;

&lt;p&gt;Timers out of sync with reality (say, after a long lunch)? Click the &amp;#8220;Reset&amp;#8221; button to start fresh.&lt;/p&gt;

&lt;p&gt;Want to come back to this set of timers tomorrow? Customize the name of the timer and then &amp;#8220;rename&amp;#8221; it so it&amp;#8217;s easy to remember.&lt;/p&gt;

&lt;h3 id='what_it_doesnt_do'&gt;What it doesn&amp;#8217;t do&lt;/h3&gt;

&lt;p&gt;It is not intended to be a full implementation of the &lt;a href='http://www.pomodorotechnique.com/'&gt;Pomodoro Technique&lt;/a&gt;. Notably absent are things like task planning and daily review.&lt;/p&gt;

&lt;h3 id='whats_next'&gt;What&amp;#8217;s next&lt;/h3&gt;

&lt;p&gt;Coming up promptly is integration with &lt;a href='http://fluidapp.com/'&gt;Fluid&lt;/a&gt;&amp;#8217;s javascript API to provide neat things like Growl integration.&lt;/p&gt;

&lt;p&gt;Want to help shape the face of what &lt;a href='http://tomatoi.st/'&gt;tomatoi.st&lt;/a&gt; will become? There are a number of ways you can help do so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scratch your own itch and &lt;a href='http://github.com/voxdolo/ding'&gt;fork it on github&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;file a &lt;a href='http://github.com/voxdolo/ding/issues'&gt;github issue&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;peruse and/or add to our &lt;a href='http://www.pivotaltracker.com/projects/11740'&gt;tracker project&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;or make a request below in the comments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id='shout_outs'&gt;Shout Outs&lt;/h3&gt;

&lt;p&gt;A number of people have contributed to making this application what it is and I&amp;#8217;d like take a second to thank them all.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://turriate.com/'&gt;Sandro Turriate&lt;/a&gt;: for adding server side polling to keep multiple people watching the same timer in sync as new timers are started.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://twitter.com/wesgibbs'&gt;Wes Gibbs&lt;/a&gt; and &lt;a href='http://blog.leshill.org/'&gt;Les Hill&lt;/a&gt;: for adding timer countdown in the title bar (one of my favorite features).&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.coreyhaines.com/'&gt;Corey Haines&lt;/a&gt;: for his general good will toward the app and for helping to spread the word about it.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.uxbooth.com/author/andrewmaier/'&gt;Andrew Maier&lt;/a&gt;: for taking the app from plain to fantastic! His design is what made the official release a possiblity.&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- #hashrocket --&gt;</content>
 </entry>
 
 <entry>
   <title>Given Due Consideration</title>
   <link href="http://blog.voxdolo.me/given-due-consideration.html"/>
   <updated>2009-09-21T00:00:00-07:00</updated>
   <id>http://blog.voxdolo.me/given-due-consideration</id>
   <content type="html">&lt;h2 id='or_just_say_no_to_cukes'&gt;Or: Just Say No to Cukes&lt;/h2&gt;

&lt;p&gt;As alluded to by &lt;a href='http://blog.veez.us/2009/09/11/integration-testing-without-cucumber'&gt;veez&lt;/a&gt;, the undercurrent from some of us at &lt;a href='http://www.hashrocket.com'&gt;Hashrocket&lt;/a&gt; has been decidedly anti-&lt;a href='http://cukes.info'&gt;cucumber&lt;/a&gt;. Here&amp;#8217;s my brief littany:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A well developed cucumber suite is invariably slow to run&lt;/li&gt;

&lt;li&gt;For me, at least, it makes development feel slower (this is almost certainly perceptual, but that doesn&amp;#8217;t mean it&amp;#8217;s not actual as well)&lt;/li&gt;

&lt;li&gt;The indirection makes debugging laborious&lt;/li&gt;

&lt;li&gt;Matching plain english to executable code via regular expressions just &lt;em&gt;feels wrong&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these things (and more) have been excused for quite some time because Cucumber is thought of as a necessary tax. If you want to do full stack integration testing in Ruby&amp;#8230; this is how it&amp;#8217;s done.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the good news: it&amp;#8217;s not the only way! Veez has gone over the basics in the post I linked above, so I won&amp;#8217;t belabor the setup, though I will give you the latest version. Here are the relevant bits of my &lt;code&gt;spec/spec_helper.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;webrat&amp;#39;&lt;/span&gt;
  &lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;spec/support/integration&amp;#39;&lt;/span&gt;

  &lt;span class='no'&gt;Webrat&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;configure&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;mode&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='ss'&gt;:rails&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='no'&gt;Spec&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Runner&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;configure&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='n'&gt;config&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;include&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;Webrat&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Matchers&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:type&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:integration&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;ActionController&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Integration&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Session&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='kp'&gt;include&lt;/span&gt; &lt;span class='no'&gt;Spec&lt;/span&gt;&lt;span class='o'&gt;::&lt;/span&gt;&lt;span class='no'&gt;Matchers&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Interleaving the above into your existing &lt;code&gt;spec_helper.rb&lt;/code&gt; is all you need to get going.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s use this user story from a project I&amp;#8217;m working on now as the backdrop to our discussion:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In order to dissolve a business relationship&lt;br /&gt;As a user&lt;br /&gt;I want to be able to remove a colleague&lt;/p&gt;

&lt;p&gt;Scenario:&lt;br /&gt;Given a user with colleagues&lt;br /&gt;When I click a colleagues &amp;#8220;Remove colleague&amp;#8221; button&lt;br /&gt;Then I should be on the colleagues list&lt;br /&gt;And I should not see the colleague&lt;br /&gt;And the colleague should not see me in their colleague list&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here&amp;#8217;s how you might implement that using RSpec and Webrat:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;User removes colleague&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;before&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;login_as&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;
      &lt;span class='n'&gt;visit&lt;/span&gt; &lt;span class='n'&gt;colleauges_path&lt;/span&gt;
      &lt;span class='n'&gt;click_button&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Remove colleague&amp;#39;&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;redirects you to the colleagues list&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;current_url&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='n'&gt;colleagues_url&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;removes them from my colleagues list&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_not&lt;/span&gt; &lt;span class='n'&gt;have_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;#colleagues .colleague&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;removes me from their colleague list&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;logout&lt;/span&gt;
      &lt;span class='n'&gt;login_as&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='vi'&gt;@colleague&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
      &lt;span class='n'&gt;visit&lt;/span&gt; &lt;span class='n'&gt;colleauges_path&lt;/span&gt;
      &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_not&lt;/span&gt; &lt;span class='n'&gt;have_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;#colleagues .colleague&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;That&amp;#8217;s all well and good, but you may be saying to yourself (or your co-worker, or your poor, terrified cat): &amp;#8220;But, that doesn&amp;#8217;t capture the plain english user story! Darn it all to Bethesda!&amp;#8221;. And you&amp;#8217;re absolutely right&amp;#8230; but how&amp;#8217;s this strike you:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='no'&gt;Feature&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;User removes colleague&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='no'&gt;Given&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;login_as&lt;/span&gt; &lt;span class='vi'&gt;@user&lt;/span&gt;
      &lt;span class='n'&gt;visit&lt;/span&gt; &lt;span class='n'&gt;colleagues_path&lt;/span&gt;
      &lt;span class='n'&gt;click_button&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;Remove colleague&amp;#39;&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;

    &lt;span class='no'&gt;Scenario&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;removal&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='no'&gt;When&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;I press remove&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
        &lt;span class='no'&gt;Then&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;I should be on my collegues list&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;current_url&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='n'&gt;colleagues_url&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='no'&gt;And&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;I should not see the user in my colleagues list&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_not&lt;/span&gt; &lt;span class='n'&gt;have_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;#colleagues .colleague&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;

        &lt;span class='no'&gt;And&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;My colleague should not see me in their colleague list&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
          &lt;span class='n'&gt;logout&lt;/span&gt;
          &lt;span class='n'&gt;login_as&lt;/span&gt; &lt;span class='vi'&gt;@colleague&lt;/span&gt;
          &lt;span class='n'&gt;visit&lt;/span&gt; &lt;span class='n'&gt;colleagues_path&lt;/span&gt;
          &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;body&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should_not&lt;/span&gt; &lt;span class='n'&gt;have_tag&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;#colleagues .colleague&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;end&lt;/span&gt;
      &lt;span class='k'&gt;end&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href='http://twitter.com/l4rk'&gt;@l4rk&lt;/a&gt; and I came up with this clever bit of aliasing to get you where you want to go. Just add this at the bottom of your &lt;code&gt;spec_helper.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;  &lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;Spec::DSL::Main&lt;/span&gt;
    &lt;span class='k'&gt;alias&lt;/span&gt; &lt;span class='ss'&gt;:Feature&lt;/span&gt; &lt;span class='ss'&gt;:describe&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='k'&gt;module&lt;/span&gt; &lt;span class='nn'&gt;Spec::Example::ExampleGroupMethods&lt;/span&gt;
    &lt;span class='k'&gt;alias&lt;/span&gt; &lt;span class='ss'&gt;:Scenario&lt;/span&gt; &lt;span class='ss'&gt;:describe&lt;/span&gt;
    &lt;span class='k'&gt;alias&lt;/span&gt; &lt;span class='ss'&gt;:When&lt;/span&gt; &lt;span class='ss'&gt;:describe&lt;/span&gt;
    &lt;span class='k'&gt;alias&lt;/span&gt; &lt;span class='ss'&gt;:Given&lt;/span&gt; &lt;span class='ss'&gt;:before&lt;/span&gt; &lt;span class='c1'&gt;#TODO: make Given take :before or :after and :each or :all&lt;/span&gt;
    &lt;span class='k'&gt;alias&lt;/span&gt; &lt;span class='ss'&gt;:Then&lt;/span&gt; &lt;span class='ss'&gt;:example&lt;/span&gt;
    &lt;span class='k'&gt;alias&lt;/span&gt; &lt;span class='ss'&gt;:And&lt;/span&gt; &lt;span class='ss'&gt;:example&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The failing of this technique, for the time being, is the round-trip output:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;User removes colleague removal I press remove&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I should be on my collegues list&lt;/li&gt;

&lt;li&gt;I should not see the user in my colleagues list&lt;/li&gt;

&lt;li&gt;My colleague should not see me in their colleague list&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;But we&amp;#8217;re already scheming up a way to improve that situation, so stay tuned as the story develops.&lt;/p&gt;
&lt;!-- #hashrocket --&gt;</content>
 </entry>
 
 <entry>
   <title>Twiki</title>
   <link href="http://blog.voxdolo.me/twiki.html"/>
   <updated>2009-09-17T00:00:00-07:00</updated>
   <id>http://blog.voxdolo.me/twiki</id>
   <content type="html">&lt;p&gt;While pairing with &lt;a href='http://twitter.com/wesgibbs'&gt;@wesgibbs&lt;/a&gt; on a project at &lt;a href='http://www.hashrocket.com'&gt;hashrocket&lt;/a&gt;, we got in the habbit of &amp;#8216;testing&amp;#8217; our migrations by doing the following:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='sh'&gt;    rake db:migrate db:migrate:redo db:test:prepare
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;At some point; frazzled and dealing with a migration that kept breaking while running the above, I uttered: &amp;#8220;db-db-db&amp;#8221;, which was subsequently flipped around to &amp;#8220;bidi-bidi-bidi&amp;#8221;. Now, as a proud (well, kinda) son of the 80&amp;#8217;s, my mind went immediately to &lt;a href='http://www.pamela-hensley.com/'&gt;Pamela Hensley&lt;/a&gt;&amp;#8230; and soon thereafter, to &lt;a href='http://en.wikipedia.org/wiki/Twiki'&gt;Twiki&lt;/a&gt; of &lt;a href='http://www.imdb.com/title/tt0078579/'&gt;Buck Rodgers&lt;/a&gt; and his &lt;a href='http://www.youtube.com/watch?v=bS7MGflCbW0'&gt;perennial tag line&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And so the following shell script was born (Mac only, sorry windozers):&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='sh'&gt;    twiki &lt;span class='o'&gt;()&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
      say -v Zarvox &lt;span class='s1'&gt;&amp;#39;beedee-beedee-beedee&amp;#39;&lt;/span&gt;
      rake db:migrate &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; rake db:migrate:redo &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; rake db:test:prepare
    &lt;span class='o'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The speed and voice aren&amp;#8217;t quite right, but the sheer cheese factor cracks me up on the regular, so I figured I&amp;#8217;d spread the wealth ;)&lt;/p&gt;

&lt;p&gt;Also of note: &lt;a href='http://www.youtube.com/watch?v=YAjyUoF928Q'&gt;the Twiki throwback dance mix&lt;/a&gt;&lt;/p&gt;
&lt;!-- #hashrocket --&gt;</content>
 </entry>
 
 <entry>
   <title>(re-)Introduction</title>
   <link href="http://blog.voxdolo.me/re-introduction.html"/>
   <updated>2009-05-30T00:00:00-07:00</updated>
   <id>http://blog.voxdolo.me/re-introduction</id>
   <content type="html">&lt;h3 id='whats_this_all_about_then'&gt;What&amp;#8217;s this all about then?&lt;/h3&gt;

&lt;p&gt;This is yet another attempt (my fourth) to maintain a blog. I haven&amp;#8217;t settled on what sort of content I intend to post here as of yet. It&amp;#8217;s a safe bet, however, that posts will be primarily technical in nature. No link or micro blogging, strictly full articles.&lt;/p&gt;

&lt;p&gt;So, yeah&amp;#8230; Welcome to the new digs and please do subscribe to my &lt;a href='http://feeds2.feedburner.com/voxdolo'&gt;atom feed&lt;/a&gt; if you fancy that sort of thing.&lt;/p&gt;

&lt;p&gt;Oh! and you can blame the sites utter lack of design on &lt;a href='http://twitter.com/andrewmaier'&gt;@andrewmaier&lt;/a&gt;&amp;#8217;s copious lack of free time ;) I kid, I kid! I&amp;#8217;ll try and beat things into shape promptly.&lt;/p&gt;</content>
 </entry>
 

</feed>

